Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions BDBOAuth1Manager.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://github.com/bdbergeron/BDBOAuth1Manager.git', :tag => s.version.to_s }
s.requires_arc = true

s.ios.deployment_target = '6.0'
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.8'

s.source_files = 'BDBOAuth1Manager/**/*.{h,m}'

s.dependency 'AFNetworking/NSURLConnection', '~> 2.5.0'
s.dependency 'AFNetworking/NSURLSession', '~> 2.5.0'
s.dependency 'AFNetworking/NSURLConnection', '~> 2.6.0'
s.dependency 'AFNetworking/NSURLSession', '~> 2.6.0'
end
28 changes: 28 additions & 0 deletions BDBOAuth1Manager/BDBOAuth1RequestSerializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,34 @@ FOUNDATION_EXPORT NSString * const BDBOAuth1OAuthCallbackParameter;
consumerKey:(NSString *)consumerKey
consumerSecret:(NSString *)consumerSecret;

#if TARGET_OS_IPHONE
/**
* Create a new BDBOAuth1RequestSerializer instance for the given service with its consumerKey and RSAPrivateKey
*
* @param service Service (base URL) this request serializer is used for.
* @param consumerKey OAuth consumer key
* @param RSAPrivateKey RSA private key
*
* @return New BDBOAuth1RequestSerializer for the specified service
*/
+ (instancetype)serializerForService:(NSString *)service
withConsumerKey:(NSString *)consumerKey
RSAPrivateKey:(id)RSAPrivateKey;

/**
* Instantiate a new BDBOAuth1RequestSerializer instance for the given service with its consumerKey and RSAPrivateKey
*
* @param service Service (base URL) this request serializer is used for.
* @param consumerKey OAuth consumer key
* @param RSAPrivateKey RSA private key
*
* @return New BDBOAuth1RequestSerializer for the specified service
*/
- (instancetype)initWithService:(NSString *)service
consumerKey:(NSString *)consumerKey
RSAPrivateKey:(id)RSAPrivateKey;
#endif


/**
* ---------------------------------------------------------------------------------------
Expand Down
93 changes: 73 additions & 20 deletions BDBOAuth1Manager/BDBOAuth1RequestSerializer.m
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ @interface BDBOAuth1RequestSerializer ()
@property (nonatomic, copy) NSString *service;
@property (nonatomic, copy) NSString *consumerKey;
@property (nonatomic, copy) NSString *consumerSecret;
@property (nonatomic, copy) id RSAPrivateKey;

- (NSString *)OAuthSignatureForMethod:(NSString *)method
URLString:(NSString *)URLString
Expand Down Expand Up @@ -214,6 +215,25 @@ - (instancetype)initWithService:(NSString *)service
return self;
}

+ (instancetype)serializerForService:(NSString *)service
withConsumerKey:(NSString *)consumerKey
RSAPrivateKey:(id)RSAPrivateKey {
return [[[self class] alloc] initWithService:service consumerKey:consumerKey RSAPrivateKey:RSAPrivateKey];
}

- (instancetype)initWithService:(NSString *)service
consumerKey:(NSString *)consumerKey
RSAPrivateKey:(id)RSAPrivateKey {
self = [super init];

if (self) {
_service = service;
_consumerKey = consumerKey;
_RSAPrivateKey = RSAPrivateKey;
}
return self;
}

#pragma mark Storing the Access Token
static NSDictionary *OAuthKeychainDictionaryForService(NSString *service) {
return @{(__bridge id)kSecClass:(__bridge id)kSecClassGenericPassword,
Expand Down Expand Up @@ -287,7 +307,12 @@ - (NSDictionary *)OAuthParameters {
parameters[BDBOAuth1SignatureVersionParameter] = @"1.0";
parameters[BDBOAuth1SignatureConsumerKeyParameter] = self.consumerKey;
parameters[BDBOAuth1SignatureTimestampParameter] = [@(floor([[NSDate date] timeIntervalSince1970])) stringValue];
parameters[BDBOAuth1SignatureMethodParameter] = @"HMAC-SHA1";

if (self.RSAPrivateKey) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forget the truth table in Objective-C--this will be true if the RSAPrivateKey is initialized and not 0?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, unfortunately I cannot find a good reference Objective C truthy table though.

parameters[BDBOAuth1SignatureMethodParameter] = @"RSA-SHA1";
} else {
parameters[BDBOAuth1SignatureMethodParameter] = @"HMAC-SHA1";
}

CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
CFUUIDBytes uuidBytes = CFUUIDGetUUIDBytes(uuid);
Expand All @@ -302,14 +327,7 @@ - (NSDictionary *)OAuthParameters {
return parameters;
}

- (NSString *)OAuthSignatureForMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
error:(NSError *__autoreleasing *)error {
NSMutableURLRequest *request = [super requestWithMethod:@"GET" URLString:URLString parameters:parameters error:error];

[request setHTTPMethod:method];

- (NSString *)OAuthHMACSignatureForRequestData:(NSData *)requestData {
NSString *secret = @"";

if (self.accessToken) {
Expand All @@ -321,6 +339,43 @@ - (NSString *)OAuthSignatureForMethod:(NSString *)method
NSString *secretString = [[self.consumerSecret bdb_URLEncode] stringByAppendingFormat:@"&%@", [secret bdb_URLEncode]];
NSData *secretData = [secretString dataUsingEncoding:NSUTF8StringEncoding];

uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CCHmacContext context;
CCHmacInit(&context, kCCHmacAlgSHA1, [secretData bytes], [secretData length]);
CCHmacUpdate(&context, [requestData bytes], [requestData length]);
CCHmacFinal(&context, digest);

#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
return [[NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH] base64EncodedStringWithOptions:0];
#else
return [[NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH] base64Encoding];
#endif
}

#if TARGET_OS_IPHONE
- (NSString *)OAuthRSASignatureForRequestData:(NSData*)requestData {
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1([requestData bytes], (unsigned int)[requestData length], digest);

size_t signatureSize = SecKeyGetBlockSize((__bridge SecKeyRef)self.RSAPrivateKey);
uint8_t signature[signatureSize];
SecKeyRawSign((__bridge SecKeyRef)self.RSAPrivateKey, kSecPaddingPKCS1SHA1, digest, sizeof(digest), signature, &signatureSize);
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
return [[NSData dataWithBytes:signature length:signatureSize] base64EncodedStringWithOptions:0];
#else
return [[NSData dataWithBytes:signature length:signatureSize] base64Encoding];
#endif
}
#endif

- (NSString *)OAuthSignatureForMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
error:(NSError *__autoreleasing *)error {
NSMutableURLRequest *request = [super requestWithMethod:@"GET" URLString:URLString parameters:parameters error:error];

[request setHTTPMethod:method];

/**
* Create signature from request data
*
Expand All @@ -334,21 +389,19 @@ - (NSString *)OAuthSignatureForMethod:(NSString *)method
NSString *requestURL = [[[[request URL] absoluteString] componentsSeparatedByString:@"?"][0] bdb_URLEncode];

NSArray *sortedQueryString = [[[[request URL] query] componentsSeparatedByString:@"&"] sortedArrayUsingSelector:@selector(compare:)];
NSString *queryString = [[sortedQueryString componentsJoinedByString:@"&"] bdb_URLEncode];
NSString *queryString = [[[sortedQueryString componentsJoinedByString:@"&"] bdb_URLEncodeSlashesAndQuestionMarks] bdb_URLEncode];

NSString *requestString = [NSString stringWithFormat:@"%@&%@&%@", requestMethod, requestURL, queryString];
NSData *requestData = [requestString dataUsingEncoding:NSUTF8StringEncoding];

uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CCHmacContext context;
CCHmacInit(&context, kCCHmacAlgSHA1, [secretData bytes], [secretData length]);
CCHmacUpdate(&context, [requestData bytes], [requestData length]);
CCHmacFinal(&context, digest);

#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090)
return [[NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH] base64EncodedStringWithOptions:0];
#if TARGET_OS_IPHONE
if (self.RSAPrivateKey) {
return [self OAuthRSASignatureForRequestData:requestData];
} else {
return [self OAuthHMACSignatureForRequestData:requestData];
}
#else
return [[NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH] base64Encoding];
return [self OAuthHMACSignatureForRequestData:requestData];
#endif
}

Expand All @@ -369,7 +422,7 @@ - (NSString *)OAuthAuthorizationHeaderForMethod:(NSString *)method

NSMutableDictionary *mutableAuthorizationParameters = [NSMutableDictionary dictionary];

if (self.consumerKey && self.consumerSecret) {
if (self.consumerKey && (self.consumerSecret || self.RSAPrivateKey)) {
[mutableAuthorizationParameters addEntriesFromDictionary:[self OAuthParameters]];

NSString *token = self.accessToken.token;
Expand Down
10 changes: 10 additions & 0 deletions BDBOAuth1Manager/Categories/NSString+BDBOAuth1Manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,14 @@

- (NSString *)bdb_URLEncode;


/**
* Returns the given string with the '/' and '?' characters URL-encoded.
*
* AFNetworking 2.6 no longer encodes '/' and '?' characters. See https://github.com/AFNetworking/AFNetworking/pull/2908
*
* @return '?' and '/' URL-encoded string
*/
- (NSString *)bdb_URLEncodeSlashesAndQuestionMarks;

@end
6 changes: 6 additions & 0 deletions BDBOAuth1Manager/Categories/NSString+BDBOAuth1Manager.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,10 @@ - (NSString *)bdb_URLDecode {
kCFStringEncodingUTF8);
}

- (NSString *)bdb_URLEncodeSlashesAndQuestionMarks {
NSString *selfWithSlashesEscaped = [self stringByReplacingOccurrencesOfString:@"/" withString:@"%2F"];
NSString *selfWithQuestionMarksEscaped = [selfWithSlashesEscaped stringByReplacingOccurrencesOfString:@"?" withString:@"%3F"];
return selfWithQuestionMarksEscaped;
}

@end
Loading