20

I get the below error while connecting to self signed server.

Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “maskeddomain.com” which could put your confidential information at risk." UserInfo=0x7fb6dec259e0 {NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorCodeKey=-9813, NSUnderlyingError=0x7fb6dbe0dd90 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1202.)"

Looks like Alamofire 1.3 (https://github.com/Alamofire/Alamofire#security) allows disabling this validation. Has anyone implemented this? I'm using Alamofire API's on my swift project, not sure where exactly "Server Trust Policy Manager" needs to be implemented. Please advice.

Arasan Rajendren
  • 265
  • 1
  • 2
  • 7

5 Answers5

40

Manager configuration for Swift 3 or Swift 4 and Alamofire 4:

private static var manager: Alamofire.SessionManager = {

    // Create the server trust policies
    let serverTrustPolicies: [String: ServerTrustPolicy] = [
        "test.example.com": .disableEvaluation
    ]

    // Create custom manager
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
    let manager = Alamofire.SessionManager(
        configuration: URLSessionConfiguration.default,
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )

    return manager
}()
jonaszmclaren
  • 2,459
  • 20
  • 30
22

There is a way to change the Server Trust Policy of the Alamofire manager shared instance, but it's not recommended. Instead you should create your own customised instance of the manager. Here is the recommended solution, code is Swift 2.0 with Alamofire from swift-2.0 branch, compiled in Xcode7 beta 5.

Creating customised instance of the manager

Because you will not use the request method on the Alamofire, but use the one on your custom manager instead, you need to think of where to store the manager. What I do is to store it as static in my networking wrapper (the class that utilizes Alamofire and deals with my application networking needs). I set it up like this:

private static var Manager : Alamofire.Manager = {
        // Create the server trust policies
        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            "maskeddomain.com": .DisableEvaluation
        ]
        // Create custom manager
        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
        let man = Alamofire.Manager(
            configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
            serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
        )
        return man
    }()

Next step is to switch all your calls that use Alamofire.request() with Manager.request(), so you should have something like this:

Manager.request(.GET, "http://stackoverflow.com").responseJSON(
    completionHandler: { (_, respose, result) -> Void in
            if result.isSuccess {
                // enjoy your success
            } else if result.isFailure {
                // deal with your failure
            }
    })

If you want to change the shared instance of the manager anyway, go here for more info.

lawicko
  • 7,246
  • 3
  • 37
  • 49
  • 2
    Shouldn't it be `let man = Alamofire.Manager(configuration: configuration, serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))` ? – SeanR Oct 19 '16 at 01:41
  • in the serverTrustPolicies can i add more then one url? – Ben Shabat Sep 18 '19 at 12:17
12

An example is posted right in the README demonstrating exactly how to disable evaluation if you need to do so.

Since you are going to need to create your own Manager instance as well, you'll want to do something like the following:

class NetworkManager {
    static let sharedInstance = NetworkManager()

    let defaultManager: Alamofire.Manager = {
        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            "test.example.com": .PinCertificates(
                certificates: ServerTrustPolicy.certificatesInBundle(),
                validateCertificateChain: true,
                validateHost: true
            ),
            "insecure.expired-apis.com": .DisableEvaluation
        ]

        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders

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

This will then allow you to make requests with the NetworkManager.sharedInstance.defaultManager object.

cnoon
  • 16,575
  • 7
  • 58
  • 66
  • 1
    Thank you cnoon for looking at my issue. Yes, i read the README file but i'm kind of confused on how this needs to be implemented (I'm new to Swift as well). As per the documentation a new Manager object is initialized with configured serverTrustPolicyManager. However, in my case, i'm using the default sharedInstance like below... Alamofire.request(DeviceAPIRequest.GEN_USER_TOKEN()).validate().responseJSON() { (request, response, results, error) in } The above method uses the sharedInstance of the Manager object. Can you please guide me on how this needs to be overriden? – Arasan Rajendren Aug 12 '15 at 17:34
  • You need to create your own custom `manager` instance. This is the easiest and safest way for you to use a `ServerTrustPolicy`. There are ways to still use the Alamofire singleton `Manager` instance, but it is definitely not recommended. I'll update my answer with a bit more info. – cnoon Aug 14 '15 at 15:44
  • Thanks cnoon... I will create my own instance.. Please provide any additional info available, it will be helpful for me to understand it better – Arasan Rajendren Aug 15 '15 at 05:50
  • @cnoon For a self-signed certificate, is it necessary to .disableEvaluation completely, or is there another setting possible that accepts self-signed? – jrf Oct 15 '15 at 14:26
  • 2
    @jrf you'll need to use `.DisableEvaluation`. There is no concept of self-signed certificates. They are invalid since they are not signed by a trusted root authority. If you need a bit more custom behavior, then you could always roll your own with the `.CustomEvaluation` case. – cnoon Oct 18 '15 at 23:21
  • There is a typo on sharedInstace, it should be sharedInstance – RPallas Feb 08 '16 at 08:48
  • Thanks @RPallas, it has been fixed. – cnoon Feb 08 '16 at 14:48
6

Another approach for my project. The ServerTrustPolicyManager is an open class, and it's serverTrustPolicy function is open too. So it can be override.

// For Swift 3 and Alamofire 4.0
open class MyServerTrustPolicyManager: ServerTrustPolicyManager {

    // Override this function in order to trust any self-signed https
    open override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
        return ServerTrustPolicy.disableEvaluation

        // or, if `host` contains substring, return `disableEvaluation`
        // Ex: host contains `my_company.com`, then trust it.
    }
}

Then,

    let trustPolicies = MyServerTrustPolicyManager(policies: [:])
    let manager = Alamofire.SessionManager(configuration: sessionConfig, delegate: SessionDelegate(), serverTrustPolicyManager: trustPolicies)

UPDATE @2018,01

In order to trigger the ServerTrustPolicyManager, the project's Info.plist needs to be configured. I found the solution, detail at this post, cnoon's comment @ 1 Nov 2015.

enter image description here

For example, if there are urls named site1.foo.com, site2.foo.com, .... Then add App Transport Security Settings -> Exception Domains -> foo.com dictionary, with following entries.

  • NSExceptionRequiresForwardSecrecy : NO
  • NSExceptionAllowsInsecureHTTPLoads : YES
  • NSIncludesSubdomains : YES

More detail you can refer the post.

AechoLiu
  • 17,522
  • 9
  • 100
  • 118
1

Anyway, the answer of @cnoon almost full. But I met another trouble of the ssl validation, so I want to put my code here if someone can get help from it.The manager init as:

private var manager: Manager?
// Import the certificates like xxx.cer to your project(anywhere will be fine), then the ServerTrustPolicy.certificatesInBundle() can find them
let serverTrustPolicy = ServerTrustPolicy.PinCertificates(
            certificates: ServerTrustPolicy.certificatesInBundle(),
            validateCertificateChain: false,
            validateHost: true
        )
let serverTrustPolicies: [String : ServerTrustPolicy] = [
            "sub.server.com": .DisableEvaluation, // because the certificates only add the main domain, so disable evaluation for subdomain
            "192.168.0.2:8090": .DisableEvaluation, // the IP address for request data
            "www.server.com": serverTrustPolicy
        ]
manager = Manager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))

Then use the manager to request:

// this function in the class which for manager the Alamofire request
public func request(method: Alamofire.Method, _ URLString: URLStringConvertible,
                        parameters: [String : AnyObject]?) -> Alamofire.Request
    {
        // we do not need use Alamofire.request now, just use the manager you have initialized
        return manager!.request(method, URLString, parameters: parameters,
                                 headers: ["tokenId": UserManager_Inst.tokenID])
    }

p.s.: it is the swift 2.3 sample

Raymond Liao
  • 1,799
  • 3
  • 20
  • 32