background session configuration + kerberos

I am running into a situation where I have some stuff secured with Kerberos -- hitting the server for general requests with NSURLSessionDataTask's works just fine, the initial request hits an authentication error and then the kerberos credentials get passed along just fine.


The issue is when I need to download a file. I need these downloads to be able to finish in the background, if necessary. If I create a download task with a backgroundSessionConfigurationWithIdentifier the download fails -- I see a 401 response and no credentials get passed along.


If I use the defaultSessionConfiguration with the same download task code, the download succeeds -- but obviously wouldn't be able to complete in the background.



Has anyone else seen this? Should this work?

iOS or Mac?

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

iOS - I have tried on iOS 8.4 and iOS 9 Beta 5.

I can use an NSURLSessionDownloadTask as well -- but the configuration cannot be a background one -- it has to be the default one.

Here is the sample code -- obviously having a kerberos setup is tough to have publicly available -- i've left only the download task since simply changing the config below will trigger failure/success


import UIKit
import Foundation

let URL = "https://some_kerberos_protected_file"

class ViewController: UIViewController, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
    private let downloadURL = NSURL(string: URL)!
    private var session: NSURLSession!
    private var downloadTask: NSURLSessionDownloadTask!
   
    override func viewDidLoad() {
        super.viewDidLoad()
       
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Download", style: .Plain, target: self, action: "download:")
       
        var config = NSURLSessionConfiguration.defaultSessionConfiguration()
       //let config =  NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("DownloadIdentifier")

        session = NSURLSession(configuration:config, delegate: self, delegateQueue: nil)
       
        downloadTask = session.downloadTaskWithURL(downloadURL)
    }
   
    func download(sender: UIBarButtonItem) {
        downloadTask.resume()
    }
   
    func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
       
        print("challenged")
        completionHandler(.PerformDefaultHandling, nil)
    }
   
    func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
        print("Challenged")
        completionHandler(.PerformDefaultHandling, nil)
    }
   
    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
        print("ERROR: \(error)")
    }
        
    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
        print("response: \(response)")
        if (response as! NSHTTPURLResponse).statusCode == 401 {
            completionHandler(.Allow)
        } else {
            completionHandler(.BecomeDownload)
        }
    }
   
    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didBecomeDownloadTask downloadTask: NSURLSessionDownloadTask) {
        print("became download task")
    }
   
    func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
        print("received data: \(data)")
    }
   
    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
        print("finished downloading: \(location)")
       
        let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
       
        do {
            try NSFileManager.defaultManager().moveItemAtURL(location, toURL: NSURL.fileURLWithPath((paths[0] ) + "/output.file"))
        } catch _ {
        }
    }
   
    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {        
        print("progress: \(bytesWritten) of \(totalBytesExpectedToWrite)")
    }
}

I've filed a radar as well 22255017

iOS […]

OK. The rule for Kerberos single sign-on on iOS is that no code changes are required. A corollary to that rule is that, if things aren't working then it's not your fault (-:

Given that things work in the foreground session, my conclusion is that your Kerberos SSO is set up correctly and that this is a bug in the OS itself.

I've filed a radar as well 22255017

Thanks. I think that's about all you can do right now.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
background session configuration + kerberos
 
 
Q