plgelso
plgelso

Reputation: 107

Swift and Alamofire SSL Pinning and Handling Challenge

I need to handle the challenge when I try to get the json from my internal web server. I followed this from a previous question. Here is my code

let defaultManager: Alamofire.SessionManager = {
            let serverTrustPolicies: [String: ServerTrustPolicy] = [
                "myhttpsinternaldomain.org": .disableEvaluation
            ]

            let configuration = URLSessionConfiguration.default
            configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders

            return Alamofire.SessionManager(
                configuration: configuration,
                serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
            )
        }()

        let url = URL(string: urlString)
        let username = "user"
        let password = "password"
        let header = ["user": username, "password": password]

        defaultManager.request(url!, method: .get, headers: header).responseJSON { response in
            switch response.result {
            case .success(let value):
                let json = JSON(value)
                print("JSON: \(json)")
            case .failure(let error):
                print(error)
            }
        }

This is the error I receive

Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://myhttpsinternaldomain.org, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://myhttpsinternaldomain.org}

I found this but I don't have the tokens in my project. I want to just user the username and password or ignore the challenge

Please any help

Upvotes: 0

Views: 4652

Answers (2)

plgelso
plgelso

Reputation: 107

Got it! Or rather I found the right page to that led me to the answer. Github Page Server Trust Policy Manager and connect to self signed servers using Alamofire

Originally I would get a 310 error, after the SSL would deny my authentication.

Then I added the manager class I posted originally and received a -999 error saying that it was "cancelled". Thanks to the Github Page above the reason is because I needed to

"Make sure to keep a reference to the new SessionManager instance, otherwise your requests will all get cancelled when your sessionManager is deallocated."

So I created a NetworkManager class thanks to the second stackoverflow page, and called it in my alamofire request.

Here is the code below that works, hopefully this will save someone a lot of time.

// Network Manager outside view controller

        class NetworkManager {
        static let sharedInstance = NetworkManager()

        let manager: Alamofire.SessionManager = {
            let serverTrustPolicies: [String: ServerTrustPolicy] = [
                "https://mydomainthatwasdrivingmebananas.com": .pinCertificates(
                    certificates: ServerTrustPolicy.certificates(),
                    validateCertificateChain: true,
                    validateHost: true),
                "mydomainthatwasdrivingmebananas.com": .disableEvaluation
            ]

            let configuration = URLSessionConfiguration.default
            configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders

            return Alamofire.SessionManager(
                configuration: configuration,
                serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
            )
        }()
    }

Then the Alamofire call

// Inside ViewController ViewDidLoad

NetworkManager.sharedInstance.manager.request("https://mydomainthatwasdrivingmebananas.com", method: .get).responseJSON{ response in
                switch response.result {
                                case .success(let value):
                                    let json = JSON(value)
                                    print("JSON: \(json)")
                                case .failure(let error):
                                    print(error)
                                }

        }

P.S the JSON() method is swifty JSON in case anyone was confused

Upvotes: 6

Kegham K.
Kegham K.

Reputation: 1614

You cannot send username and password like this in the header like you do in postman. You have to change them to base64. This is what postman does in the background when he adds your credentials to the header.

// Your hostname and endpoint
let hostname = "myhttpsinternaldomain.org"
let cert = "YOUR_CERT" // e.g. for cert.der, this should just be "cert"

// Set up certificates
let pathToCert = Bundle.main.path(forResource: cert, ofType: "der")
let localCertificate = NSData(contentsOfFile: pathToCert!)
let certificates = [SecCertificateCreateWithData(nil, 
localCertificate!)!]

// Configure the trust policy manager
let serverTrustPolicy = ServerTrustPolicy.pinCertificates(
certificates: certificates,
validateCertificateChain: true,
validateHost: true
)    
let serverTrustPolicies = [hostname: serverTrustPolicy]
let serverTrustPolicyManager = ServerTrustPolicyManager(policies: 
serverTrustPolicies)

// Configure session manager with trust policy
let defaultManager = Alamofire.SessionManager(
  configuration: URLSessionConfiguration.default,
  serverTrustPolicyManager: serverTrustPolicyManager
)

let url = URL(string: urlString)

let user = "user"

let password = "password"

let base64 = "\(user):\(password)".toBase64()



   let header = [

        "Authorization": "Basic \(base64)"
   ]

   //Added encoding type in the request. Change and try other types too. Like JSONEncoding.default
    defaultManager.request(url!, method: .get, encoding: URLEncoding.default ,headers: header).responseJSON { response in
        switch response.result {
        case .success(let value):
            let json = JSON(value)
            print("JSON: \(json)")
        case .failure(let error):
            print(error)
        }
    }

extension String {

   func toBase64() -> String {
       return Data(self.utf8).base64EncodedString()
   }
}

enter image description here

Upvotes: 0

Related Questions