Alamofire Not Handling Authentication Challenge

Auth Challenge Alamofire 2.0

Making two requests is how the underlying URL Loading System was designed by Apple. The Alamofire authenticate methods simply allow you to provide the credentials to supply to the challenge if it occurs.

If you want to provide the header directly, the use the headers parameter on the request method. Additionally, you could insert the user:password credentials directly into the URL.

Alamofire 4.9.1 sessionManager.delegate.sessionDidReceiveChallenge is not getting assigned in iOS 15

I managed to solve the issue by modifying the SessionDelegate.swift file of the Alamofire pod itself. Namely, I initialized the certificate in the SessionDelegate.swift file and passed its urlCredential property to the task delegate's credential property in

open func urlSession(
_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

and voilà, it worked.

So I re-defined the class (PKCS12) that lets me initialize the certificate inside the SessionDelegate.swift file and the body of the above function now looks like this:

if let taskDidReceiveChallenge = taskDidReceiveChallenge {
let result = taskDidReceiveChallenge(session, task, challenge)
completionHandler(result.0, result.1)
} else if let delegate = self[task]?.delegate {
// this gets executed in iOS 15 and we need to get a credential in order for the delegate to successfully set the disposition required for getting data from the server
let cert = PKCS12.init(mainBundleResource: "\(certNameHere)",
resourceType: "pfx",
password: "%^&^%*&")
delegate.credential = cert.urlCredential()
delegate.urlSession(
session,
task: task,
didReceive: challenge,
completionHandler: completionHandler
)
} else {
urlSession(session, didReceive: challenge, completionHandler: completionHandler)
}

This has solved the issue for us and I hope it is of help to others who may experience similar issues with iOS 15 and Alamofire 4.9.1. Thank you for reading.

Issue with Alamofire challenge delegate and escaping closure

It seems to me the missing piece of your question is whether the completion handler in Authhandler.handleChallenge is escaping. It is, right?

But the taskDidReceiveChallengeWithCompletion completionHandler is non-escaping. So you're trying to figure out how to let it escape when it's not allowed to escape.

Looking at the Alamofire source code, about 3 months ago, they changed that completionHandler to be @escaping! See here: https://github.com/Alamofire/Alamofire/commit/b03b43cc381ec02eb9855085427186ef89055eef

You need to update to a version of Alamofire after that PR got merged or you need to figure out how to handle the completionHandler in a fully non-escaping way. Meaning, your Authhandler.handleChallenge can't have an escaped completionHandler.

Alamofire 5 alternative to sessionDidReceiveChallenge

First you need a ServerTrustEvaluating that handle the certificate pinning a simple implement would be something similar to

public final class CertificatePinnerTrustEvaluator: ServerTrustEvaluating {

public init() {}

func setupCertificatePinner(host: String) -> CertificatePinner {

//get the CertificatePinner
}

public func evaluate(_ trust: SecTrust, forHost host: String) throws {

let pinner = setupCertificatePinner(host: host)

if (!pinner.validateCertificateTrustChain(trust)) {
print("failed: invalid certificate chain!")
throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}

if (!pinner.validateTrustPublicKeys(trust)) {
print ("couldn't validate trust for \(host)")

throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}
}
}

To be able to use the same evaluator I would suggest to subclass ServerTrustManager to return the same evaluator I did it like this:

class CertificatePinnerServerTrustManager: ServerTrustManager {

let evaluator = CertificatePinnerTrustEvaluator()

init() {
super.init(allHostsMustBeEvaluated: true, evaluators: [:])
}

open override func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating? {

return evaluator
}
}

after that you should be ready to go by creating the session and passing the manager to it

private let session: Session = {

let trustManager = CertificatePinnerServerTrustManager()

return Session(serverTrustManager: trustManager)
}()

My reference was the method urlSession(_:task:didReceive:completionHandler:) in Alamofire source in SessionDelegate.swift at line 86 (Alamofire V5.2.1)

Authenticated http request swift Alamofire

So the majority of your code looks solid.

The error leads me to believe that CFNetwork is having difficulty figuring out how to compute the protection space for the challenge. I would also assume you are getting a basic auth challenge since you are attaching an Authorization header.

Digging through your logic a bit more with this in mind led me to see that your not attaching your token to the string properly inside the Authorization header. You need to do the following instead.

defaultHeaders["Authorization"] = "bearer \(token!)"

Otherwise your Authorization header value is going to include Optional(value) instead of just value.

That's the only issue I can see at the moment. If you could give that a try and comment back that would be great. I'll update my answer accordingly if that doesn't actually solve your problem.

Best of luck!



Related Topics



Leave a reply



Submit