我在OS X应用程序上遇到网络问题。它不会被沙箱化。我正在使用NSURLSession的数据任务连接到一个服务器,该服务器的证书是根据TN2326的自签名CA创建的。我用URL https://rc2dev.rc2.io:8443/login
调用它,它在我的开发盒上映射到linux vm的内部ip地址。
url适用于curl和nscurl,因此它不是服务器问题。在钥匙串中,我将我的CA标记为可信任,这就是nscurl工作的原因。
我将代码包装到一个隔离NSURLSession代码的包装类中:
public class LoginHandler: NSObject, NSURLSessionDataDelegate {
let urlConfig:NSURLSessionConfiguration
let baseUrl:NSURL
var loggedInHandler:LoginHandler?
var urlSession:NSURLSession!
var loginResponse:NSURLResponse?
var responseData:NSMutableData = NSMutableData()
public typealias LoginHandler = (data:NSData?, response:NSHTTPURLResponse?, error:NSError?) -> Void
init(config:NSURLSessionConfiguration, baseUrl:NSURL) {
self.urlConfig = config
self.baseUrl = baseUrl
super.init()
}
public func login(login:String, password:String, handler:LoginHandler) {
self.urlSession = NSURLSession(configuration: urlConfig, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
loggedInHandler = handler
let url = NSURL(string: "login", relativeToURL: baseUrl)
let req = NSMutableURLRequest(URL: url!)
req.HTTPMethod = "POST"
req.addValue("application/json", forHTTPHeaderField:"Content-Type")
req.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(["login":login, "password":password], options: [])
let task = urlSession.dataTaskWithRequest(req);
task.resume()
}
public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)
{
log.info("challenge 1")
guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
let serverTrust = challenge.protectionSpace.serverTrust,
let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 0),
let certPath = NSBundle.mainBundle().URLForResource("server", withExtension: "cer"),
let storedData = NSData(contentsOfURL: certPath) where
storedData.isEqualToData(SecCertificateCopyData(serverCert)) else
{
completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil)
return
}
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, nil)
}
public func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)
{
log.info("challenge 2")
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, nil)
}
public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void)
{
self.loginResponse = response
completionHandler(NSURLSessionResponseDisposition.Allow)
}
public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)
{
responseData.appendData(data)
}
public func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?)
{
if error != nil {
loggedInHandler!(data: nil, response:loginResponse as! NSHTTPURLResponse!, error: error)
} else {
loggedInHandler!(data:responseData, response:loginResponse as! NSHTTPURLResponse!, error:nil)
}
urlSession.invalidateAndCancel()
}
调用的唯一委托方法是didCompleteWithError。传递给它的错误对象是
打印错误说明: ▿可选(错误域= NSURLErrorDomain代码= -1004“无法连接到服务器。”UserInfo = {NSUnderlyingError = 0x61000005b270 {错误域= kCFErrorDomainCFNetwork代码= -1004“(null)”UserInfo = {_ kCFStreamErrorCodeKey = 61,_kCFStreamErrorDomainKey = 1 },NSErrorFailingURLStringKey = http://192.168.212.128:8088/login,NSErrorFailingURLKey = http://192.168.212.128:8088/login,_ kCFStreamErrorDomainKey = 1,_kCFStreamErrorCodeKey = 61,NSLocalizedDescription =无法连接到服务器。})
以下是命令行中发生的情况。需要自定义身份验证头,因此响应应为401。
mlilback@Morticia$curl -vi https://rc2dev.rc2.io:8443/login
* Trying 192.168.212.128...
* Connected to rc2dev.rc2.io (192.168.212.128) port 8443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: Rc2Stat
> GET /login HTTP/1.1
> Host: rc2dev.rc2.io:8443
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
HTTP/1.1 401 Unauthorized
< Date: Fri, 18 Mar 2016 10:06:53 GMT
Date: Fri, 18 Mar 2016 10:06:53 GMT
< Content-Length: 13
Content-Length: 13
<
unauthorized
* Connection #0 to host rc2dev.rc2.io left intact
mlilback@Morticia$nscurl --verbose https://rc2dev.rc2.io:8443/login
unauthorized
启用CFNetworkDiagnostics除了从调试器获得的相同错误外,不会返回任何有用的内容。
至于ATS,我的info.plist包括:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
我完全不知道问题是什么。有什么想法吗?