Conversation
.swift-version
Outdated
| @@ -1 +1 @@ | |||
| 4.1.2 | |||
| 4.1 | |||
| // Check if there exists a self-signed certificate and whether it's a secure connection | ||
| private let isSecure: Bool | ||
| private let isSelfSigned: Bool | ||
| private let certificateName: String |
There was a problem hiding this comment.
Wouldn't this make more sense as an optional? Also, better named clientCertificateName? Also, comment needed.
| Log.warning(warning) | ||
| fallthrough | ||
| } | ||
| if let _ = NSData(contentsOfFile: Bundle.main.path(forResource: self.certificateName, ofType: "der") ?? "") { |
There was a problem hiding this comment.
Why create an NSData then throw it away?
| if let serverCertificate = SecTrustGetCertificateAtIndex(trust, 0) { | ||
| let certificate: SecCertificate = serverCertificate | ||
| var identity: SecIdentity? = nil | ||
| let _: OSStatus = SecIdentityCreateWithCertificate(nil, certificate, &identity) |
There was a problem hiding this comment.
Shouldn't we check the result?
| } | ||
| if let _ = NSData(contentsOfFile: Bundle.main.path(forResource: self.certificateName, ofType: "der") ?? "") { | ||
| if let serverCertificate = SecTrustGetCertificateAtIndex(trust, 0) { | ||
| let certificate: SecCertificate = serverCertificate |
There was a problem hiding this comment.
Why do we need to do this?
| #if !os(Linux) | ||
| if let certificatePath = self.certificatePath { | ||
| // Get the bundle path from the Certificates directory for a certificate that matches clientCertificateName's name | ||
| if let bundle = Bundle.path(forResource: self.clientCertificateName, ofType: "der", inDirectory: certificatePath) { |
There was a problem hiding this comment.
Please call this path.
| // Convert the bundle path to NSData | ||
| if let key: NSData = NSData(base64Encoded: bundle, options: .ignoreUnknownCharacters) { | ||
| // Create a secure certificate from the NSData | ||
| if let certificate: SecCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, key) { |
There was a problem hiding this comment.
Do you need the : SecCertificate or would the compiler infer it?
| if let certificate: SecCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, key) { | ||
| // Create a secure identity from the certificate | ||
| var identity: SecIdentity? = nil | ||
| let _: OSStatus = SecIdentityCreateWithCertificate(nil, certificate, &identity) |
There was a problem hiding this comment.
https://developer.apple.com/documentation/security/1401160-secidentitycreatewithcertificate says "Call the CFRelease function to release this object when you are finished with it." so I guess we need to do that?
There was a problem hiding this comment.
When attempting to use it, it returns the following error: 'CFRelease' is unavailable: Core Foundation objects are automatically memory managed, suggesting that this is handled by itself.
| switch (method, host) { | ||
| case (NSURLAuthenticationMethodClientCertificate, baseHost): | ||
| #if !os(Linux) | ||
| if let certificatePath = self.certificatePath { |
There was a problem hiding this comment.
Can you guard let in here to reduce the nesting?
| let host = challenge.protectionSpace.host | ||
|
|
||
| guard let url = URLComponents(string: self.url), let baseHost = url.host else { | ||
| guard let url = URLComponents(string: self.url), let baseHost = url.host, let certificatePath = self.certificatePath else { |
There was a problem hiding this comment.
This doesn't look right, we'll never get to the switch if certificatePath is nil.
| } | ||
| // Get the bundle path from the Certificates directory for a certificate that matches clientCertificateName's name | ||
| if let path = Bundle.path(forResource: self.clientCertificateName, ofType: "der", inDirectory: certificatePath) { | ||
| // Convert the bundle path to NSData |
There was a problem hiding this comment.
This comment isn't correct, it's not the path that's being converted, it's the contents of the file. Would this be better?
// Read the certificate data from disk
| // Get the bundle path from the Certificates directory for a certificate that matches clientCertificateName's name | ||
| if let path = Bundle.path(forResource: self.clientCertificateName, ofType: "der", inDirectory: certificatePath) { | ||
| // Convert the bundle path to NSData | ||
| if let key: NSData = NSData(base64Encoded: path, options: .ignoreUnknownCharacters) { |
There was a problem hiding this comment.
I think the compiler can infer the type.
There was a problem hiding this comment.
Do we really want to .ignoreUnknownCharacters? Would it be safer not to?
| switch (method, host) { | ||
| case (NSURLAuthenticationMethodClientCertificate, baseHost): | ||
| #if !os(Linux) | ||
| guard let certificatePath = self.certificatePath else { |
There was a problem hiding this comment.
I think we should guard let clientCertificateName = self.clientCertificateName too, just in case someone passes us a path but no name?
| /// - Parameters: | ||
| /// - url: URL string to use for network request | ||
| public init(method: HTTPMethod = .get, url: String, containsSelfSignedCert: Bool? = false) { | ||
| public init(method: HTTPMethod = .get, url: String, containsSelfSignedCert: Bool? = false, certificateName: String? = nil, certificatePath: String? = nil) { |
There was a problem hiding this comment.
Do you think it would be better to define a
public struct ClientCertificate {
let name: String
let path: String
}and pass one of those in here?
|
|
||
| self.isSecure = url.contains("https") | ||
| self.isSelfSigned = containsSelfSignedCert ?? false | ||
| self.clientCertificateName = clientCertificate?.name |
There was a problem hiding this comment.
Why not just store the passed in ClientCertificate?
self.clientCertificate = clientCertificateThen we can add things to ClientCertificate if we need to, without having to update RestRequest as well.
|
|
||
| } | ||
|
|
||
| public struct ClientCertificate { |
There was a problem hiding this comment.
Comments needed in here.
gen.sh
Outdated
| @@ -0,0 +1,17 @@ | |||
| podspec="Pod::Spec.new do |s|\ns.name = \"$projectName\"\ns.version = \"$TRAVIS_TAG\"\ns.summary = \"$TRAVIS_DESCRIPTION\"\ns.homepage = \"https://github.com/IBM-Swift/$projectName\"\ns.license = { :type => \"Apache License, Version 2.0\" }\ns.author = \"IBM\"\ns.module_name = '$projectName'\ns.requires_arc = true\ns.ios.deployment_target = \"10.0\"\ns.source = { :git => \"https://github.com/IBM-Swift/$projectName.git\", :tag => s.version }\ns.source_files = \"Sources/$projectName/*.swift\"\ns.pod_target_xcconfig = {\n'SWIFT_VERSION' => '4.0.3',\n}" | |||
There was a problem hiding this comment.
I don't think this file should be here!
| /// Struct to store client certificate name and path | ||
| public struct ClientCertificate { | ||
| /// The name for the client certificate | ||
| let name: String |
There was a problem hiding this comment.
Can you mark these public please.
…SwiftyRequest into clientCertificateAuth
|
🎉 |
This PR aims to add client certificate authentication, in relation to this issue: #33 (comment)