0

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

plgelso
  • 107
  • 2
  • 15

2 Answers2

6

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

plgelso
  • 107
  • 2
  • 15
0

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

Kegham K.
  • 1,589
  • 22
  • 40
  • No good unfortunately. I still got the same error. Have any other ideas? Here are the header parameters I get in postman. Connection →Keep-Alive Content-Type →text/html; charset=UTF-8 Date →Tue, 23 May 2017 16:59:36 GMT Keep-Alive →timeout=5, max=100 Server →Apache Transfer-Encoding →chunked X-Frame-Options →SAMEORIGIN The Key value is = {"Authorization":"Basic cGxnZWxzbzpNYXkyMDE3IQ=="} Thanks for helping again I really appreciate it @Kegham K. – plgelso May 23 '17 at 17:00
  • No problem this is part of the solution. Try to change the encoding method. Will update the code and try to use different encoding methods in your request and check again. – Kegham K. May 23 '17 at 17:03
  • Try `URLEnocding.default` or `JSONEncoding.default` – Kegham K. May 23 '17 at 17:11
  • And check this link for SSL pining to your server calls. There is an example using Alamofire in Swift 2. https://infinum.co/the-capsized-eight/how-to-make-your-ios-apps-more-secure-with-ssl-pinning – Kegham K. May 23 '17 at 17:15
  • Those two changes didn't work. I'll read up on the SSL pinning I think that your right and it has to do with that. I have come across that article in my attempts to fix this problem but was unsuccessful implementing the theory. Ill keep trying. Thank you again – plgelso May 23 '17 at 17:19
  • Here is an example on github. https://github.com/antekarin/ssl-pinning-swift/blob/master/SSL-Pinning/ViewController.swift – Kegham K. May 23 '17 at 17:39
  • my issue with using the article earlier and this example is the "cert" is an actual certificate that is in the bundle of Xcode. Im trying to get to the server and do exactly what postman does, without a cert embedded in the app. Unless the cert is the domain name? – plgelso May 23 '17 at 17:42
  • @PeterGelsomino i have updated the code try it but add your own cert.der within the code files so the Bundle.main would find it. – Kegham K. May 23 '17 at 17:47
  • @PeterGelsomino ok i got what you mean. You need to call an SSL server but without the certificate. Did you try calling the route using http not https. And Allowing arbitrary loads in the infoPlist file. – Kegham K. May 23 '17 at 17:50
  • Yes and Yes. My info.plist allows arbitrary loads has the exception domain and a few other items under exception domains that I used to try to solve – plgelso May 23 '17 at 18:00
  • Try this service to make free SSL certificates for your domain. https://letsencrypt.org – Kegham K. May 23 '17 at 18:27