2016-10-11 25 views
8

Alamofire 4.0とSwift 3.0の使用方法を解明しようとしています(必要に応じてPEM証明書と鍵を持っています)。認証のためのウェブサイト。私が見てきたすべての例は、Swift 2.0のためのものであり、正確には私が探しているものではありません。私のマックのサファリでは、キーチェーンにp12を入れ、サファリが尋ねるときに送信することでサイトにアクセスできるので、その部分が動作することがわかります。アプリケーションでAlamofire 4.0とSwift 3.0を使用する方法の例を教えてもらえるかどうかはわかりません。証明書は自己署名されています。Swift 3とAlamofire 4を使用した相互認証のためのクライアント証明書の取得

どのような考えや助け?私はちょうどクライアントの鍵として証明書をピン止めするために探していますし、アクセスするためにサーバに証明書を送る必要があります...

+0

私は同じことが必要です – DoubleK

+0

私はそれを理解したように答えを追加します –

答えて

7

私はそれを働かせることができました。いくつかの問題がありました。まず、IOSが自己署名証明書を受け入れるようにする必要があります。あなたがクライアント証明書を送信するためにsessionDidRecieveChallengeをオーバーライドする必要があり、

let serverTrustPolicies: [String: ServerTrustPolicy] = [ 
     "your-domain.com": .disableEvaluation 
    ] 

self.sessionManager = Alamofire.SessionManager(
     serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies) 
    ) 

そこから:これはAlamoFire serverTrustPolicyを設定する必要があります。私は私が他の場所で見つかったいくつかのコードを修正P12ファイルを使用していたので作るために(申し訳ありませんが私はもうソースを持っていないが)基礎クラスを使用してP12をインポートする3.0スウィフトです:

import Foundation 

public class PKCS12 { 
    var label:String? 
    var keyID:Data? 
    var trust:SecTrust? 
    var certChain:[SecTrust]? 
    var identity:SecIdentity? 

    let securityError:OSStatus 

    public init(data:Data, password:String) { 

     //self.securityError = errSecSuccess 

     var items:CFArray? 
     let certOptions:NSDictionary = [kSecImportExportPassphrase as NSString:password as NSString] 

     // import certificate to read its entries 
     self.securityError = SecPKCS12Import(data as NSData, certOptions, &items); 

     if securityError == errSecSuccess { 
      let certItems:Array = (items! as Array) 
      let dict:Dictionary<String, AnyObject> = certItems.first! as! Dictionary<String, AnyObject>; 

      self.label = dict[kSecImportItemLabel as String] as? String; 
      self.keyID = dict[kSecImportItemKeyID as String] as? Data; 
      self.trust = dict[kSecImportItemTrust as String] as! SecTrust?; 
      self.certChain = dict[kSecImportItemCertChain as String] as? Array<SecTrust>; 
      self.identity = dict[kSecImportItemIdentity as String] as! SecIdentity?; 
     } 


    } 

    public convenience init(mainBundleResource:String, resourceType:String, password:String) { 
     self.init(data: NSData(contentsOfFile: Bundle.main.path(forResource: mainBundleResource, ofType:resourceType)!)! as Data, password: password); 
    } 

    public func urlCredential() -> URLCredential { 
     return URLCredential(
      identity: self.identity!, 
      certificates: self.certChain!, 
      persistence: URLCredential.Persistence.forSession); 

    } 



} 

これは私ができるようになりますファイルをインポートしてクライアントに送り返します。

let cert = PKCS12.init(mainBundleResource: "cert", resourceType: "p12", password: "password"); 

self.sessionManager.delegate.sessionDidReceiveChallenge = { session, challenge in 
     if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { 
      return (URLSession.AuthChallengeDisposition.useCredential, self.cert.urlCredential()); 
     } 
     if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { 
      return (URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)); 
     } 
     return (URLSession.AuthChallengeDisposition.performDefaultHandling, Optional.none); 
    } 

ここでセッションマネージャを使用して、必要なだけ多くの呼び出しを作成できます。注意点としては

、私はまた、新しいiOSの機能で新しいセキュリティ機能を回避するためにお奨めとしてのInfo.plistに次を追加しました:

<key>NSAppTransportSecurity</key> 
    <dict> 
     <key>NSAllowsArbitraryLoads</key> 
     <true/> 
     <key>NSExceptionDomains</key> 
     <dict> 
      <key>your-domain.com</key> 
      <dict> 
       <key>NSIncludesSubdomains</key> 
       <true/> 
       <key>NSExceptionRequiresForwardSecrecy</key> 
       <false/> 
       <key>NSExceptionAllowsInsecureHTTPLoads</key> 
       <true/> 
      </dict> 
     </dict> 
    </dict> 

私はこれが役に立てば幸い!ここで

+0

私は同じ方法を実装していますが、私のAPIを出している間に、sessionManager.delegateのsessionDidReceiveChallengeメソッドを起動していません... – samridhgupta

+0

サムは、デリゲートを設定していないか、オブジェクトに設定しています –

3

はあなたのInfo.plist

<key>NSAppTransportSecurity</key> 
    <dict> 
     <key>NSAllowsArbitraryLoads</key> 
     <true/> 
     <key>NSExceptionDomains</key> 
     <dict> 
      <key>api.myappdev.com</key> 
      <dict> 
       <key>NSExceptionAllowsInsecureHTTPLoads</key> 
       <true/> 
       <key>NSExceptionRequiresForwardSecrecy</key> 
       <false/> 
       <key>NSIncludesSubdomains</key> 
       <true/> 
       <key>NSRequiresCertificateTransparency</key> 
       <false/> 
       <key>NSTemporaryExceptionMinimumTLSVersion</key> 
       <string>TLSv1.2</string> 
      </dict> 
     </dict> 
    </dict> 

、ここに次の誰か(Alamofire 4.0、スウィフト3、Xcodeの8)

import Alamofire 

class NetworkConnection { 
    let developmentDomain = Config.developmentDomain // "api.myappdev.com" 
    let productionDomain = Config.productionDomain // "api.myappprod.com" 
    let certificateFilename = Config.certificateFilename // "godaddy" 
    let certificateExtension = Config.certificateExtension // "der" 
    let useSSL = true 
    var manager: SessionManager! 
    var serverTrustPolicies: [String : ServerTrustPolicy] = [String:ServerTrustPolicy]() 
    static let sharedManager = NetworkConnection() 


    init(){ 
     if useSSL { 
      manager = initSafeManager() 
     } else { 
      manager = initUnsafeManager() 
     } 
    } 

    //USED FOR SITES WITH CERTIFICATE, OTHERWISE .DisableEvaluation 
    func initSafeManager() -> SessionManager { 
     setServerTrustPolicies() 

     manager = SessionManager(configuration: URLSessionConfiguration.default, delegate: SessionDelegate(), serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)) 

     return manager 
    } 

    //USED FOR SITES WITHOUT CERTIFICATE, DOESN'T CHECK FOR CERTIFICATE 
    func initUnsafeManager() -> SessionManager { 
     manager = Alamofire.SessionManager.default 

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

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

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

      return (disposition, credential) 
     } 

     return manager 
    } 

    func setServerTrustPolicies() { 
     let pathToCert = Bundle.main.path(forResource: certificateFilename, ofType: certificateExtension) 
     let localCertificate:Data = try! Data(contentsOf: URL(fileURLWithPath: pathToCert!)) 

     let serverTrustPolicies: [String: ServerTrustPolicy] = [ 
      productionDomain: .pinCertificates(
       certificates: [SecCertificateCreateWithData(nil, localCertificate as CFData)!], 
       validateCertificateChain: true, 
       validateHost: true 
      ), 
      developmentDomain: .disableEvaluation 
     ] 

     self.serverTrustPolicies = serverTrustPolicies 
    } 

    static func addAuthorizationHeader (_ token: String, tokenType: String) -> [String : String] { 
     let headers = [ 
      "Authorization": tokenType + " " + token 
     ] 

     return headers 
    } 

} 

アドオンを作るの一例であるに役立つかもしれないという私の例であります要求を

import Alamofire  

class ActionUserUpdate { 
     let url = "https://api.myappdev.com/v1/" 
     let manager = NetworkConnection.sharedManager.manager 

     func updateUser(_ token: String, tokenType: String, expiresIn: Int, params: [String : String]) { 
      let headers = NetworkConnection.addAuthorizationHeader(token, tokenType: tokenType) 
      manager?.request(url, method: .put, parameters: params, encoding: JSONEncoding.default, headers: headers).responseJSON { response in 
       print(response.description) 
       print(response.debugDescription) 
       print(response.request) // original URL request 
       print(response.response) // URL response 
       print(response.data)  // server data 
       print(response.result) // result of response serialization 
      } 
     }   
} 
+1

これは私が誤っていないと相互認証を提供しないので、私が探していたものとまったく同じように見えます。それはバンドルされた証明書に基づいてサーバを検証するだけです。それは証明書の確保のように思えます。 – luk2302

+0

真実、私の間違い、間違ったスレッド。私はそれを削除します – DoubleK

+1

nervermind、あなたはそれらの2つを混同する最初のものではありません。私の最初の2時間のグーグルでは、あなたのコードに似た結果しか得られませんでした;) – luk2302

関連する問題