2
votes

I'm trying to connect to an API running on localhost so I can test out my app in the iOS emulator. I'm getting

NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “127.0.0.1” which could put your confidential information at risk., NSErrorFailingURLKey=https://127.0.0.1:8000/post/, NSErrorFailingURLStringKey=https://127.0.0.1:8000/post/, NSErrorClientCertificateStateKey=0

I'm using Alamofire. This similar question has not helped. It seems to be outdated from an older version of Alamofire.

My info.plist already contains

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

How can I temporarily disable the certificate requirement so I can test my app on localhost?

Here is my code after changing the server trust policies as was suggested in one of the answers

ViewController:

class TableViewController: UIViewController {
    let postClient = PostServiceClient.sharedInstance

    override func viewDidLoad() {
        super.viewDidLoad()
        postClient.getPosts()
    }
}

PostServiceClient:

import Alamofire

class PostServiceClient {

    static let sharedInstance: PostServiceClient = PostServiceClient()

    var sessionManager : SessionManager!

    init() {
        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            "https://127.0.0.1:8000/" : .disableEvaluation
        ]

        self.sessionManager =  SessionManager(configuration: URLSessionConfiguration.default,
                                              serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
        )
    }
    static let url = URL.init(string: "https://127.0.0.1:8000/post/")

    // Method to get posts from the wall
    func getPosts(){
        print("Getting posts with completion handler")
        var request = URLRequest(url: PostServiceClient.url!)
        request.httpMethod = "GET"
        self.sessionManager.request(request).responseJSON { (response) in
            guard response.result.isSuccess else {
                print("Error while getting posts: \(String(describing: response.result.error))")
                return
            }
            guard let responseJSON = response.result.value as? [String: Any],
                let results = responseJSON["results"] as? [[String: Any]] else {
                print("Invalid response recieved from service")
                return
            }
            print(responseJSON)
        }

    }
}

Here is the full output I'm getting:

Getting posts with completion handler 2017-06-19 14:22:15.770616-0400 WallAppiOS[28605:9092279] [] nw_coretls_callback_handshake_message_block_invoke_3 tls_handshake_continue: [-9812] 2017-06-19 14:22:15.770 WallAppiOS[28605:9092321] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813) Error while getting posts: Optional(Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “127.0.0.1” which could put your confidential information at risk." UserInfo={NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “127.0.0.1” which could put your confidential information at risk., NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSUnderlyingError=0x7a3627c0 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9813, _kCFStreamErrorCodeKey=-9813, _kCFStreamErrorDomainKey=3, kCFStreamPropertySSLPeerTrust=, kCFStreamPropertySSLPeerCertificates=( "" )}}, _kCFStreamErrorCodeKey=-9813, NSErrorFailingURLStringKey=https://127.0.0.1:8000/post/, NSErrorPeerCertificateChainKey=( "" ), NSErrorClientCertificateStateKey=0, NSURLErrorFailingURLPeerTrustErrorKey=, NSErrorFailingURLKey=https://127.0.0.1:8000/post/})

2
how do you get the server cert? Looks like you have to turn off cert check in Alamofire. ATS is asking you not to use HTTP, but it has nothing do to with the cert. Cert checking is a chain starting to the root certWingzero
@Wingzero do you know how I can turn off cert check?Matt
not really, but you can look for trust policy setting or search for the switchWingzero

2 Answers

1
votes

In this example I use the serverTrustPolicyManager to handle the connection with an ssl not certificated server, I use a singleton to handle all connections in my app you must declare sessionManager as says the Alamofire github page

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

    class exampleNetworkClient {

        static let sharedInstance: exampleNetworkClient = exampleNetworkClient()

        var sessionManager : SessionManager?

        init() {
            let serverTrustPolicies: [String: ServerTrustPolicy] = [
                "https://127.0.0.1:8000" : .disableEvaluation 
            ]

            self.sessionManager =  SessionManager(configuration: URLSessionConfiguration.default,
                                  serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
            )
        }

        static let portalUrl = URL.init(string:"https://127.0.0.1:8000/exampleserviceUrl")

    func exampleMethod()
    {
        var request = URLRequest(url: iOSETKClient.portalUrl!)
        request.httpMethod = "GET"

        //Important Note that you need to use your custom session manager
        self.sessionManager!.request(request).responseString { (response) in
            ///...RESPONSE LOGIC...///

        }
    }
}

Hope this helps

1
votes

I did it by combining ReinerMelian's answer with one of the answers in the other question

ViewController:

class TableViewController: UIViewController {

    let postClient = PostServiceClient.sharedInstance

    override func viewDidLoad() {
        super.viewDidLoad()

        postClient.sessionManager.delegate.sessionDidReceiveChallenge = { session, challenge in
            var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
            var credential: URLCredential?

            if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, let trust = challenge.protectionSpace.serverTrust {
                disposition = URLSession.AuthChallengeDisposition.useCredential
                credential = URLCredential(trust: trust)
            } else {
                if challenge.previousFailureCount > 0 {
                    disposition = .cancelAuthenticationChallenge
                } else {
                    credential = self.postClient.sessionManager.session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)

                    if credential != nil {
                        disposition = .useCredential
                    }
                }
            }

            return (disposition, credential)
        }

        postClient.getPosts()
    }
}

Service Client:

class PostServiceClient {

    static let sharedInstance: PostServiceClient = PostServiceClient()

    var sessionManager : SessionManager!

    init() {
        self.sessionManager =  SessionManager(configuration: URLSessionConfiguration.default)
    }
    static let url = URL.init(string: "https://127.0.0.1:8000/post/")

    // Methods to get posts from the wall
    func getPosts(){
        print("Getting posts with completion handler")
        var request = URLRequest(url: PostServiceClient.url!)
        request.httpMethod = "GET"
        self.sessionManager.request(request).responseJSON { (response) in
            guard response.result.isSuccess else {
                print("Error while getting posts: \(String(describing: response.result.error))")
                return
            }
            guard let responseJSON = response.result.value as? [String: Any],
                let results = responseJSON["results"] as? [[String: Any]] else {
                print("Invalid response recieved from service")
                return
            }
            print(responseJSON)
        }

    }
}