mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-23 04:20:21 +08:00
Merging SSL certificate validation support from #131
This commit is contained in:
@@ -130,6 +130,8 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
BOOL _serviceUnavailableAlertEnabled;
|
||||
RKRequestCache* _cache;
|
||||
RKRequestCachePolicy _cachePolicy;
|
||||
NSMutableSet *_additionalRootCertificates;
|
||||
BOOL _disableCertificateValidation;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
@@ -146,6 +148,22 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
*/
|
||||
@property(nonatomic, readonly) NSMutableDictionary* HTTPHeaders;
|
||||
|
||||
#ifdef RESTKIT_SSL_VALIDATION
|
||||
/**
|
||||
* A set of additional certificates to be used in evaluating server
|
||||
* SSL certificates.
|
||||
*/
|
||||
@property(nonatomic, readonly) NSSet* additionalRootCertificates;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Accept all SSL certificates. This is a potential security exposure,
|
||||
* and should be used ONLY while debugging in a controlled environment.
|
||||
*
|
||||
* *Default*: _NO_
|
||||
*/
|
||||
@property(nonatomic, assign) BOOL disableCertificateValidation;
|
||||
|
||||
/**
|
||||
* Will check for network connectivity to the host specified in the baseURL
|
||||
*
|
||||
@@ -164,6 +182,16 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
*/
|
||||
- (void)setValue:(NSString*)value forHTTPHeaderField:(NSString*)header;
|
||||
|
||||
#ifdef RESTKIT_SSL_VALIDATION
|
||||
/**
|
||||
* Adds an additional certificate that will be used to evaluate server SSL certs
|
||||
*
|
||||
* @param cert The HTTP header to add
|
||||
* @see additionalRootCertificates
|
||||
*/
|
||||
- (void)addRootCertificate:(SecCertificateRef)cert;
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
/// @name HTTP Authentication
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -88,6 +88,10 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
@synthesize password = _password;
|
||||
@synthesize forceBasicAuthentication = _forceBasicAuthentication;
|
||||
@synthesize HTTPHeaders = _HTTPHeaders;
|
||||
#ifdef RESTKIT_SSL_VALIDATION
|
||||
@synthesize additionalRootCertificates = _additionalRootCertificates;
|
||||
#endif
|
||||
@synthesize disableCertificateValidation = _disableCertificateValidation;
|
||||
@synthesize baseURLReachabilityObserver = _baseURLReachabilityObserver;
|
||||
@synthesize serviceUnavailableAlertTitle = _serviceUnavailableAlertTitle;
|
||||
@synthesize serviceUnavailableAlertMessage = _serviceUnavailableAlertMessage;
|
||||
@@ -121,6 +125,7 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_HTTPHeaders = [[NSMutableDictionary alloc] init];
|
||||
_additionalRootCertificates = [[NSMutableSet alloc] init];
|
||||
self.serviceUnavailableAlertEnabled = NO;
|
||||
self.serviceUnavailableAlertTitle = NSLocalizedString(@"Service Unavailable", nil);
|
||||
self.serviceUnavailableAlertMessage = NSLocalizedString(@"The remote resource is unavailable. Please try again later.", nil);
|
||||
@@ -158,6 +163,7 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
self.serviceUnavailableAlertMessage = nil;
|
||||
self.cache = nil;
|
||||
[_HTTPHeaders release];
|
||||
[_additionalRootCertificates release];
|
||||
[_baseURLReachabilityObserver release];
|
||||
|
||||
[super dealloc];
|
||||
@@ -209,6 +215,12 @@ NSString* RKPathAppendQueryParams(NSString* resourcePath, NSDictionary* queryPar
|
||||
[_HTTPHeaders setValue:value forKey:header];
|
||||
}
|
||||
|
||||
#ifdef RESTKIT_SSL_VALIDATION
|
||||
- (void)addRootCertificate:(SecCertificateRef)cert {
|
||||
[_additionalRootCertificates addObject:(id)cert];
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)setBaseURL:(NSString*)baseURL {
|
||||
[_baseURL release];
|
||||
_baseURL = nil;
|
||||
|
||||
@@ -76,4 +76,9 @@
|
||||
*/
|
||||
- (RKParamsAttachment*)setFile:(NSString*)filePath MIMEType:(NSString*)MIMEType fileName:(NSString*)fileName forParam:(NSString*)param DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
* Resets the state of the RKParams stream
|
||||
*/
|
||||
- (void)reset;
|
||||
|
||||
@end
|
||||
|
||||
@@ -127,6 +127,12 @@ NSString* const kRKStringBoundary = @"0xKhTmLbOuNdArY";
|
||||
return _length;
|
||||
}
|
||||
|
||||
- (void)reset {
|
||||
_bytesDelivered = 0;
|
||||
_length = 0;
|
||||
_streamStatus = NSStreamStatusNotOpen;
|
||||
}
|
||||
|
||||
- (NSInputStream*)HTTPBodyStream {
|
||||
// Open each of our attachments
|
||||
[_attachments makeObjectsPerformSelector:@selector(open)];
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#import "RKNetwork.h"
|
||||
#import "RKLog.h"
|
||||
#import "RKParserRegistry.h"
|
||||
#import "RKClient.h"
|
||||
|
||||
// Set Logging Component
|
||||
#undef RKLogComponent
|
||||
@@ -87,26 +88,90 @@ extern NSString* cacheURLKey;
|
||||
return _request.username && _request.password;
|
||||
}
|
||||
|
||||
// Handle basic auth
|
||||
- (BOOL)isServerTrusted:(SecTrustRef)trust {
|
||||
RKClient* client = [RKClient sharedClient];
|
||||
BOOL proceed = NO;
|
||||
|
||||
if( client.disableCertificateValidation ) {
|
||||
proceed = YES;
|
||||
}
|
||||
#ifdef RESTKIT_SSL_VALIDATION
|
||||
else if( [client.additionalRootCertificates count] > 0 ) {
|
||||
CFArrayRef rootCerts = (CFArrayRef)[client.additionalRootCertificates allObjects];
|
||||
SecTrustResultType result;
|
||||
OSStatus returnCode;
|
||||
|
||||
if( rootCerts && CFArrayGetCount(rootCerts) ) {
|
||||
// this could fail, but the trust evaluation will proceed (it's likely to fail, of course)
|
||||
SecTrustSetAnchorCertificates(trust, rootCerts);
|
||||
}
|
||||
|
||||
returnCode = SecTrustEvaluate(trust, &result);
|
||||
|
||||
if( returnCode == errSecSuccess ) {
|
||||
proceed = (result == kSecTrustResultProceed || result == kSecTrustResultConfirm || result == kSecTrustResultUnspecified);
|
||||
if( result == kSecTrustResultRecoverableTrustFailure ) {
|
||||
// TODO: should try to recover here
|
||||
// call SecTrustGetCssmResult() for more information about the failure
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return proceed;
|
||||
}
|
||||
|
||||
// Handle basic auth & SSL certificate validation
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
RKLogDebug(@"Received authentication challenge");
|
||||
if (! [self hasCredentials]) {
|
||||
RKLogWarning(@"Received an authentication challenge without any credentials to satify the request.");
|
||||
[[challenge sender] cancelAuthenticationChallenge:challenge];
|
||||
return;
|
||||
|
||||
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
|
||||
SecTrustRef trust = [[challenge protectionSpace] serverTrust];
|
||||
if ([self isServerTrusted:trust]) {
|
||||
[challenge.sender useCredential:[NSURLCredential credentialForTrust:trust] forAuthenticationChallenge:challenge];
|
||||
} else {
|
||||
[[challenge sender] cancelAuthenticationChallenge:challenge];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ([challenge previousFailureCount] == 0) {
|
||||
NSURLCredential *newCredential;
|
||||
newCredential=[NSURLCredential credentialWithUser:[NSString stringWithFormat:@"%@", _request.username]
|
||||
password:[NSString stringWithFormat:@"%@", _request.password]
|
||||
persistence:RKNetworkGetGlobalCredentialPersistence()];
|
||||
[[challenge sender] useCredential:newCredential
|
||||
forAuthenticationChallenge:challenge];
|
||||
} else {
|
||||
RKLogWarning(@"Failed authentication challenge after %d failures", [challenge previousFailureCount]);
|
||||
[[challenge sender] cancelAuthenticationChallenge:challenge];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)space {
|
||||
RKLogDebug(@"Asked if canAuthenticateAgainstProtectionSpace: with authenticationMethod = %@", [space authenticationMethod]);
|
||||
if ([[space authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) {
|
||||
// server is using an SSL certificate that the OS can't validate
|
||||
// see whether the client settings allow validation here
|
||||
RKClient* client = [RKClient sharedClient];
|
||||
if (client.disableCertificateValidation
|
||||
#ifdef RESTKIT_SSL_VALIDATION
|
||||
|| [client.additionalRootCertificates count] > 0
|
||||
#endif
|
||||
) {
|
||||
return YES;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle non-SSL challenges
|
||||
BOOL hasCredentials = [self hasCredentials];
|
||||
if (! hasCredentials) {
|
||||
RKLogWarning(@"Received an authentication challenge without any credentials to satisfy the request.");
|
||||
}
|
||||
|
||||
if ([challenge previousFailureCount] == 0) {
|
||||
NSURLCredential *newCredential;
|
||||
newCredential = [NSURLCredential credentialWithUser:[NSString stringWithFormat:@"%@", _request.username]
|
||||
password:[NSString stringWithFormat:@"%@", _request.password]
|
||||
persistence:RKNetworkGetGlobalCredentialPersistence()];
|
||||
[[challenge sender] useCredential:newCredential
|
||||
forAuthenticationChallenge:challenge];
|
||||
} else {
|
||||
RKLogWarning(@"Failed authentication challenge after %d failures", [challenge previousFailureCount]);
|
||||
[[challenge sender] cancelAuthenticationChallenge:challenge];
|
||||
}
|
||||
return hasCredentials;
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
||||
|
||||
Reference in New Issue
Block a user