Skip to content

Commit

Permalink
Merge branch 'master' into feature/opening_up_request
Browse files Browse the repository at this point in the history
# Conflicts:
#	Source/Request.swift
  • Loading branch information
cnoon committed Jul 24, 2015
2 parents 2401f6c + 70b1982 commit 71f33cc
Show file tree
Hide file tree
Showing 39 changed files with 2,959 additions and 272 deletions.
200 changes: 188 additions & 12 deletions Alamofire.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

68 changes: 63 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

[![Build Status](https://travis-ci.org/Alamofire/Alamofire.svg)](https://travis-ci.org/Alamofire/Alamofire)
[![Cocoapods Compatible](https://img.shields.io/cocoapods/v/Alamofire.svg)](https://img.shields.io/cocoapods/v/Alamofire.svg)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/Alamofire.svg?style=flat&color=gray)](http://cocoadocs.org/docsets/Alamofire)
[![Platform](https://img.shields.io/cocoapods/p/Alamofire.svg?style=flat)](http://cocoadocs.org/docsets/Alamofire)
[![Twitter](https://img.shields.io/badge/[email protected]?style=flat)](http://twitter.com/AlamofireSF)

Alamofire is an HTTP networking library written in Swift.

Expand Down Expand Up @@ -293,7 +296,7 @@ Adding a custom HTTP header to a `Request` is supported directly in the global `
```swift
let headers = [
"Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
"Content-Type": "application/x-www-form-urlencoded"
]

Expand Down Expand Up @@ -882,6 +885,59 @@ enum Router: URLRequestConvertible {
Alamofire.request(Router.ReadUser("mattt")) // GET /users/mattt
```

### Security

Using a secure HTTPS connection when communicating with servers and web services is an important step in securing sensitive data. By default, Alamofire will evaluate the certificate chain provided by the server using Apple's built in validation provided by the Security framework. While this guarantees the certificate chain is valid, it does not prevent man-in-the-middle (MITM) attacks or other potential vulnerabilities. In order to mitigate MITM attacks, applications dealing with sensitive customer data or financial information should use certificate or public key pinning provided by the `ServerTrustPolicy`.

#### ServerTrustPolicy

The `ServerTrustPolicy` enumeration evaluates the server trust generally provided by an `NSURLAuthenticationChallenge` when connecting to a server over a secure HTTPS connection.

```swift
let serverTrustPolicy = ServerTrustPolicy.PinCertificates(
certificates: ServerTrustPolicy.certificatesInBundle(),
validateCertificateChain: true,
validateHost: true
)
```

There are many different cases of server trust evaluation giving you complete control over the validation process:

* `PerformDefaultEvaluation`: Uses the default server trust evaluation while allowing you to control whether to validate the host provided by the challenge.
* `PinCertificates`: Uses the pinned certificates to validate the server trust. The server trust is considered valid if one of the pinned certificates match one of the server certificates.
* `PinPublicKeys`: Uses the pinned public keys to validate the server trust. The server trust is considered valid if one of the pinned public keys match one of the server certificate public keys.
* `DisableEvaluation`: Disables all evaluation which in turn will always consider any server trust as valid.
* `CustomEvaluation`: Uses the associated closure to evaluate the validity of the server trust thus giving you complete control over the validation process. Use with caution.

#### Server Trust Policy Manager

The `ServerTrustPolicyManager` is responsible for storing an internal mapping of server trust policies to a particular host. This allows Alamofire to evaluate each host against a different server trust policy.

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

let manager = Manager(
configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
```

These server trust policies will result in the following behavior:

* `test.example.com` will always use certificate pinning with certificate chain and host validation enabled thus requiring the following criteria to be met to allow the TLS handshake to succeed:
* Certificate chain MUST be valid.
* Certificate chain MUST include one of the pinned certificates.
* Challenge host MUST match the host in the certificate chain's leaf certificate.
* `insecure.expired-apis.com` will never evaluate the certificate chain and will always allow the TLS handshake to succeed.
* All other hosts will use the default evaluation provided by Apple.

* * *

## FAQ
Expand All @@ -899,8 +955,6 @@ AFNetworking remains the premiere networking library available for OS X and iOS,
Use AFNetworking for any of the following:

- UIKit extensions, such as asynchronously loading images to `UIImageView`
- TLS verification, using `AFSecurityManager`
- Situations requiring `NSOperation` or `NSURLConnection`, using `AFURLConnectionOperation`
- Network reachability monitoring, using `AFNetworkReachabilityManager`

### What's the origin of the name Alamofire?
Expand All @@ -911,7 +965,11 @@ Alamofire is named after the [Alamo Fire flower](https://aggie-horticulture.tamu

## Credits

Alamofire is owned and maintained by the [Alamofire Software Foundation](http://alamofire.org).
Alamofire is owned and maintained by the [Alamofire Software Foundation](http://alamofire.org). You can follow them on Twitter at [@AlamofireSF](https://twitter.com/AlamofireSF) for project updates and releases.

### Security Disclosure

If you believe you have identified a security vulnerability with Alamofire, you should report it as soon as possible via email to [email protected]. Please do not post it to a public issue tracker.

## License

Expand Down
15 changes: 14 additions & 1 deletion Source/Download.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@ extension Manager {
}

let request = Request(session: self.session, task: downloadTask)

if let downloadDelegate = request.delegate as? Request.DownloadTaskDelegate {
downloadDelegate.downloadTaskDidFinishDownloadingToURL = { session, downloadTask, URL in
return destination(URL, downloadTask.response as! NSHTTPURLResponse)
}
}

self.delegate[request.delegate.task] = request.delegate

if self.startRequestsImmediately {
Expand Down Expand Up @@ -132,14 +134,25 @@ extension Request {
}
}

/// The resume data of the underlying download task if available after a failure.
public var resumeData: NSData? {
var data: NSData?

if let delegate = self.delegate as? DownloadTaskDelegate {
data = delegate.resumeData
}

return data
}

// MARK: - DownloadTaskDelegate

class DownloadTaskDelegate: TaskDelegate, NSURLSessionDownloadDelegate {
var downloadTask: NSURLSessionDownloadTask? { return self.task as? NSURLSessionDownloadTask }
var downloadProgress: ((Int64, Int64, Int64) -> Void)?

var resumeData: NSData?
override var data: NSData? { return resumeData }
override var data: NSData? { return self.resumeData }

// MARK: - NSURLSessionDownloadDelegate

Expand Down
42 changes: 32 additions & 10 deletions Source/Manager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ public class Manager {

var mutableUserAgent = NSMutableString(string: "\(executable)/\(bundle) (\(version); OS \(os))") as CFMutableString
let transform = NSString(string: "Any-Latin; Latin-ASCII; [:^ASCII:] Remove") as CFString

if CFStringTransform(mutableUserAgent, nil, transform, 0) == 1 {
return mutableUserAgent as NSString as! String
return mutableUserAgent as String
}
}

Expand Down Expand Up @@ -104,11 +105,15 @@ public class Manager {
// MARK: - Lifecycle

/**
:param: configuration The configuration used to construct the managed session.
Initializes the Manager instance with the given configuration and server trust policy.

:param: configuration The configuration used to construct the managed session. `nil` by default.
:param: serverTrustPolicyManager The server trust policy manager to use for evaluating all server trust challenges. `nil` by default.
*/
required public init(configuration: NSURLSessionConfiguration? = nil) {
required public init(configuration: NSURLSessionConfiguration? = nil, serverTrustPolicyManager: ServerTrustPolicyManager? = nil) {
self.delegate = SessionDelegate()
self.session = NSURLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
self.session.serverTrustPolicyManager = serverTrustPolicyManager

self.delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
if let strongSelf = self {
Expand Down Expand Up @@ -157,13 +162,14 @@ public class Manager {
:returns: The created request.
*/
public func request(URLRequest: URLRequestConvertible) -> Request {
var dataTask: NSURLSessionDataTask?
var dataTask: NSURLSessionDataTask!

dispatch_sync(self.queue) {
dataTask = self.session.dataTaskWithRequest(URLRequest.URLRequest)
}

let request = Request(session: self.session, task: dataTask!)
self.delegate[request.delegate.task] = request.delegate
let request = Request(session: self.session, task: dataTask)
delegate[request.delegate.task] = request.delegate

if self.startRequestsImmediately {
request.resume()
Expand Down Expand Up @@ -218,11 +224,28 @@ public class Manager {
}

public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void)) {
var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
var credential: NSURLCredential!

if let sessionDidReceiveChallenge = self.sessionDidReceiveChallenge {
completionHandler(sessionDidReceiveChallenge(session, challenge))
} else {
completionHandler(.PerformDefaultHandling, nil)
(disposition, credential) = sessionDidReceiveChallenge(session, challenge)
} else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
let host = challenge.protectionSpace.host

if let
serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
serverTrust = challenge.protectionSpace.serverTrust
{
if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
disposition = .UseCredential
credential = NSURLCredential(forTrust: serverTrust)
} else {
disposition = .CancelAuthenticationChallenge
}
}
}

completionHandler(disposition, credential)
}

public func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
Expand Down Expand Up @@ -291,7 +314,6 @@ public class Manager {
taskDidComplete(session, task, error)
} else if let delegate = self[task] {
delegate.URLSession(session, task: task, didCompleteWithError: error)

self[task] = nil
}
}
Expand Down
Loading

0 comments on commit 71f33cc

Please sign in to comment.