Search code examples
iosswiftnsurlsessionbasic-authentication

Difference between NSURLSession on iOS 8 and iOS 9?


I have the following code to authenticate an iOS app to a MediaWiki server:

let task = NSURLSession.sharedSession()
        task.configuration.HTTPAdditionalHeaders = ["Authorization": "Basic " + base64EncodedCredentials]

        task.dataTaskWithURL(url!) {(data, response, error) in
            dispatch_async(dispatch_get_main_queue(), {

                if data != nil {
                    let result = NSString(data: data!, encoding: NSUTF8StringEncoding)
                    if resultIsValid(result) {
                        //Do authentication stuff
                    } else {
                        self.showLoginErrorMessage()
                    }
                } else {
                    self.showLoginErrorMessage()
                }
            })
            }.resume()

On iOS 8 this works perfect and I receive a HTTP 200 OK response. However, on iOS 9 I receive a 401 unauthorised. Unfortunately I do not have access to the server to see what it actually receives, and it is on an internal network, so I cannot link to the server. It uses HTTP basic access authentication, so I will assume that it should be the same as for any other server with that authentication type.

Is there any changes in the API from iOS 8 to 9 that could cause any issues like this? Could for instance other default headers like content type or user agent be changed/removed/added?

Edit: After testing with requests.in I have discovered that by adding a Content-Type, this is a part of the header in iOS 8, but not in iOS 9. In iOS 8 I can still get the request through without setting the Content-Type, but it is still weird that it is not present in the iOS 9 request.


Solution

  • I finally managed to figure it out! Turns out that in iOS 9 the HTTPAdditionalHeaders property of NSURLSessionConfiguration is read-only, and any changes to it will not be reflected in the current NSURLSession. On top of that, the four headers Authorisation, Connection, Host and WWW-Authenticate cannot be modified. Therefore, the only way to do basic access authentication in iOS 9 is by using NSURLCredential as proposed by quellish.

    For anyone having the same problem, here is the final code I used to have my authentication working for both iOS 8 and iOS 9:

    let url = NSURL(string: "https://subdomain2.subdomain1.example.com")
    
    let credential = NSURLCredential(user: username, password: password, persistence: NSURLCredentialPersistence.ForSession)
    let protectionSpace = NSURLProtectionSpace(host: url!.host!, port: 443, `protocol`: url!.scheme, realm: "subdomain2.example.com", authenticationMethod: NSURLAuthenticationMethodHTTPBasic)
    NSURLCredentialStorage.sharedCredentialStorage().setCredential(credential, forProtectionSpace: protectionSpace)
    
    let task = NSURLSession.sharedSession()
    
    task.dataTaskWithURL(url!) {(data, response, error) in
        if data != nil {
             if responseIsValid(response) {
                //Do authenticated stuff
             } else {
                 self.showLoginErrorMessage()
             }         
        } else {
             self.showLoginErrorMessage()
        }
    }.resume()