I'm trying to implement certificate pinning using Alamofire.
I have added mydomain to "Exception Domains" in .plist file and set keys:
NSExceptionAllowsInsecureHTTPLoads: true
NSIncludesSubdomains: true
NSExceptionRequiresForwardSecrecy: false
Then, I create SessionManager this way:
let serverTrustPolicies: [String: ServerTrustPolicy] = [
"mydomain": .pinCertificates(certificates: [],
validateCertificateChain: true,
validateHost: true)
]
let configuration = URLSessionConfiguration.default
sessionManager = SessionManager(configuration: configuration,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
When I run my app, all requests succeed, but the expected result is Alamofire rejecting them. I've set breakpoints to all "didReceiveChallenge" methods and they're not even executed.
When I change the configuration to
let configuration = URLSessionConfiguration.background(withIdentifier: "background")
Then cert pinning works as expected (rejecting all requests)
Anyone has an idea why it happens and how to fix it using default configuration?
Note: When I pass my .der file to certificates in .pinCertificates policy, background configuration also works as expected
I've finally found a reason - Wormholy. I had to remove this library to make cert pinning working
Related
I am trying to integrate SSL public key pinning in Alamofire swift 5, but I found ServerTrustPolicyManager which is deprecated. Please help me to integrate. Thanks.
To integrate SSL public key pinning you first have to add your SSL certificate in your project's target by dragging and dropping it.
To test if your certificate is in the correct format you can try to get the value from publicKeys parameter of the AlamofireExtension in your main Bundle, like this:
print("Bundle public keys: \(Bundle.main.af.publicKeys)")
If that array have at least one element, then you are ready. If it does not, then try importing your SSL certificate to your Mac's Keychain, then export it as .cer and then add it to your project's target. (this should work)
To check if the public key of the SSL certificate is the one that you import in your project you can use the Alamofire's ServerTrustManager with a PublicKeysTrustEvaluator instance, when you create your Session:
let evaluators: [String: ServerTrustEvaluating] = [
"your.domain.com": PublicKeysTrustEvaluator()
]
let serverTrustManager = ServerTrustManager(evaluators: evaluators)
let session = Session(serverTrustManager: serverTrustManager)
Make sure that in the evaluators dictionary, the key ("your.domain.com" in the code above) is your servers domain and if you don't want for Alamofire to perform the default validation and/or validate the host you can pass false to those parameters in PublicKeysTrustEvaluator's initializer:
let evaluators: [String: ServerTrustEvaluating] = [
"your.domain.com": PublicKeysTrustEvaluator(
performDefaultValidation: false,
validateHost: false
)
]
let serverTrustManager = ServerTrustManager(evaluators: evaluators)
let session = Session(serverTrustManager: serverTrustManager)
Then you have to use this Session instance to make any request in your domain, like this:
let url = "https://your.domain.com/path/to/api"
session.request(url, method: .post, parameters: parameters).responseDecodable { response in
}
As #JonShier pointed out in the comments: You need to keep your Session alive beyond the declaring scope. Usually this is done through a single or other outside reference.
I'm trying to set up an NWConnection that does client side certs:
self.connection = NWConnection(
host: NWEndpoint.Host("servername"),
port: NWEndpoint.Port(integerLiteral: 8899),
using: .tls)
But I think that simple .tls class var needs to be a much more involved NWParameters object, but I'm at a complete loss (documentation is pretty sparse) as to what I create there to attach the client certs to the parameters. Nor do I know how I even move from .crt/.pem file to something the app manages programatically.
What is an example of how one would configure the NWParameters to support the client certs?
Context
I'm trying to set up a client connection to communicate with an MQTT broker using client side certificates. I've been able to proof-of-concept this all on the Linux side using command line. The MQTT broker is set to require client cert, and a command like:
mosquitto_pub -h servername -p 8899 -t 1234/2/Q/8 -m myMessage --cafile myChain.crt --cert client.crt --key client.pem
does the job nicely. But OpenSSL is enough a black box (to me) on iOS that I don't know where to go from here. I have been able to get all of the other MQTT communications work with my NWConnection instances, including server side TLS and even if it's self signed.
The kind folks on the Apple Developer Forums helped work this out. On iOS you have to use the p12 import ability:
let importOptions = [ kSecImportExportPassphrase as String: "" ]
var rawItems: CFArray?
let status = SecPKCS12Import(P12Data as CFData, importOptions as CFDictionary, &rawItems)
let items = rawItems! as! Array<Dictionary<String, Any>>
let firstItem = items[0]
let clientIdentity = firstItem[kSecImportItemIdentity as String]! as! SecIdentity
print("clientIdentity \(clientIdentity)")
Now that one has an identity, you can use that to configure the securityProtocolOptions of the the TLS options:
let options = NWProtocolTLS.Options()
sec_protocol_options_set_local_identity(options.securityProtocolOptions, sec_identity_create(clientIdentity)!)
sec_protocol_options_set_challenge_block(options.securityProtocolOptions, { (_, completionHandler) in
completionHandler(sec_identity_create(clientIdentity)!)
}, .main)
let parameters = NWParameters(tls: options) // use this in the NWConnection creation
For reference, the Apple Developer Forum topic where this is discussed.
I am trying to use couchbase DB and set up authentication for it using Authorization Code flow. I followed the steps in this link. I prepared ConfigJson accordingly. Using Pods i installed Couchbase lite for ios and gave the authenticator in following way:
let url = URL.init(string: "http://my-ip:4984/project_name/_oidc")!
pusher = database.createPushReplication(url)
pusher.continuous = true
let authenticator = CBLAuthenticator.openIDConnect({(loginURL: URL, redirectURL: URL, Nonnull: CBLOIDCLoginContinuation) -> Void in
print(loginURL,redirectURL)
})
pusher.authenticator = authenticator
pusher.start()
But when I Checked it in terminal "http://my-ip:4984/project_name/_oidc/_session" is hit instead and I am not receiving any callback to the mobile. What am i doing wrong? Sorry I am just a beginner. Why is _session added at the end?
You need to set URL of Your database instead of setting _oidc endpoint. Authentification steps are taken care of by Couchbase Lite's Open ID Connect authenticator.
So, You need to use let url = URL.init(string: "http://my-ip:4984/project_name/")!
I cannot authorize Google OAuth on ios, safari always say
400 That's an error.
Invalid parameter value for redirect_uri:
Missing scheme: com.googleusercontent.apps.984813079630-3lmlrubo9345ng4qhtf62ud1i02m6ta8
I have checked API Key, Client_ID, client_secret on Google Console page many times and also create url scheme in the xcode.
Here are my Swift code:
oauthswift = OAuth2Swift(
consumerKey: "xxxxx-3lmlrubo9345ng4qhtf62ud1i02m6ta8.apps.googleusercontent.com",
consumerSecret: "xxxtg6qslUOC2np1sBg0hnWgBcpZb4",
authorizeUrl: "https://accounts.google.com/o/oauth2/v2/auth",
responseType: "token"
)
let handle = oauthswift.authorize(
withCallbackURL: URL(string: "com.googleusercontent.apps.984813079630-3lmlrubo9345ng4qhtf62ud1i02m6ta8")!,
scope: "profile", state:"GOOGLE",
success: { credential, response, parameters in
print(credential.oauthToken)
// Do your request
},
failure: { error in
print(error.localizedDescription)
}
)
Could you help me ?
It is pretty simple fix for this issue:
just set prefix before your schema.
Example:
your schema parameter:
com.googleusercontent.apps.984813079630-3lmlrubo9345ng4qhtf62ud1i02m6ta8
the identifier of your iOS application:
net.the-red-queen.www
so, value for your redirect URI parameter is:
net.the-red-queen.www:com.googleusercontent.apps.984813079630-3lmlrubo9345ng4qhtf62ud1i02m6ta8
I think the actual issue is that you didn't specify a full URI. (The schema doesn't have a colon and then a path.) Try making your redirect_uri look something like the following (properly encoded, of course):
com.googleusercontent.apps.984813079630-3lmlrubo9345ng4qhtf62ud1i02m6ta8:/oauth
You should probably recheck the Google Dev Console. Your clientID might be wrongly registered for Javascript Web Apps rather than Mobile Apps
I'm writing an Android client, and this information helped, but wasn't quite what I needed. I found that I had to make the redirect uri a little differently.
Take the uri that you're using as a target on the phone (usually the package name, but it can be different if re-defined in the applicationId in the app's build.gradle file).
Append this at the end of the target: :/oauth2callback
So my package is com.fooboy.testapp3. Add the above bit and the redirect uri becomes:
com.foobly.testapp3:/oauth2callback.
There are a lot of other things that need to be just right (especially in the google api console), but this was the final trick for me.
Good luck (you'll need it)!
So I have an app that makes frequent requests to various endpoints on our API, and every request pretty much has the same custom headers sent with it. I'd like to know if there is a way to globally set custom header using NSURLSessionConfiguration, and if so...what is the syntax in Swift and where would I put it? AppDelegate? I've done some searching and can't seem to find a good example of this. Is it a bad practice? Not doable?
EDIT:
I'm using Alamofire for request/response, so I need something that sets them globally so that that library (and others that happen to use NSURLSession) will send the headers along by default.
We have this documented right in the README.
var defaultHeaders = Alamofire.Manager.sharedInstance.session.configuration.HTTPAdditionalHeaders ?? [:]
defaultHeaders["DNT"] = "1 (Do Not Track Enabled)"
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = defaultHeaders
let manager = Alamofire.Manager(configuration: configuration)
Then you need to use the new manager instead of the global Alamofire singleton.
manager.request(.GET, "https://httpbin.org/get")
.responseJSON { _, _, result in
debugPrint(result)
}
This will attach the DNT header to every request that is sent through this manager instance.
Each Manager instance has its own internal NSURLSession which also has its own configuration. Therefore, this override only works for this Manager instance. If you need these headers on a different Manager instance, you'll have to set it up the same way.