How to make a NTML request with Alamofire 4.0?

617 views Asked by At

These are request headers:

    let headers: HTTPHeaders = [
        "Accept": "application/json",
        "username": "someUserName",
        "password": "aPasswordForSomeUserName"
    ]

When making a request with below code it's giving me "Garbage at the end". However, when I checked the response with JSON parser online. It's a valid JSON.

Alamofire.request("http://myserver/list.svc/random", headers: headers).responseJSON { response in
    print(response)
}

I also tried making a request like this:

Alamofire.request("http://myserver/list.svc/random", headers: headers).responseString { response in
    print(response)
}

I am getting this message in console: "401 UNAUTHORIZED".

What am I doing wrong? I believe, when using responseJSON completion block it's not complaining about Unauthorization, but it's complaining about bad JSON (or some garbage).

P.S. The same request works fine with Advance Rest Client (a chrome extension) and also in chrome browser.

2

There are 2 answers

0
Eslam Hanafy On

In Swift4.2

Alamofire has built in NTLM auth support. You can make a request like that

        let user = "YOUR_USER_NAME OR EMAIL"
        let password = "YOUR_PASSWORD"
        let url = "YOUR_API_URL"
        let credential = URLCredential(user: user, password: password, persistence: .forSession)
        //These headers are optional based on your api and your server.
        //There were required for me
        let headers = ["Accept": "application/json;odata=verbose",
                           "Content-type": "application/json;odata=verbose"]
        Alamofire.request(url, method: .get, headers: headers).authenticate(usingCredential: credential).responseJSON {
                (response) in
                switch response.result {
                case .success:
                    if let value = response.result.value {
                        print("The server response is: ", value)
                    }else{
                        print("There is error in the server response")
                    }
                case .failure (let error):
                    print("The NTLM request error is: ", error.localizedDescription)
                }

            }
0
christophercarlsson On

I don't know how relevant this is to you anymore but I've got a working solution I'll post for any future reference.

So, I had two issues. The first one being that the Authorization header fell of the request when it was redirected. The second one being the NTLM-challenge from the server not being handled. The following code should be quite self explanatory I hope :) It asumes you store the username and password in variables name just that.

    let credentialData = "\(username):\(password)".data(using: String.Encoding.utf8)!
    let base64Credentials = credentialData.base64EncodedString(options: [])
    request.addValue("Basic \(base64Credentials)", forHTTPHeaderField: "Authorization")

    let manager = Alamofire.SessionManager.default
    let delegate: Alamofire.SessionDelegate = manager.delegate

    // This bit will re-add the auth headers for the redirected request
    delegate.taskWillPerformHTTPRedirection = { session, task, response, request in
        var redirectedRequest = request

        if let originalRequest = task.originalRequest, let redirectheaders = originalRequest.allHTTPHeaderFields {
            if let authorizationHeaderValue = redirectheaders["Authorization"] {
                redirectedRequest.setValue(authorizationHeaderValue, forHTTPHeaderField: "Authorization")
            }
            if let contentTypeHeaderValue = redirectheaders["Content-Type"] {
                redirectedRequest.setValue(contentTypeHeaderValue, forHTTPHeaderField: "Content-Type")
            }
        }

        return redirectedRequest
    }

    // This bit looks at challenges received and applies the correct credentials
    delegate.taskDidReceiveChallenge = { session, task, challenge in
        var disposition: URLSession.AuthChallengeDisposition = .useCredential
        var credential: URLCredential = URLCredential()

        if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM) {
            disposition = URLSession.AuthChallengeDisposition.useCredential
            credential = URLCredential(user: username, password: password, persistence: URLCredential.Persistence.forSession)
        }

        if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
            disposition = URLSession.AuthChallengeDisposition.useCredential
            credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
        }

        return(disposition, credential)
    }

    manager.request(request).responseData { (response) in
        // Handle response accordingly
    }

Hope this helps someone.