Skip to content
This repository was archived by the owner on May 4, 2023. It is now read-only.
Open
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
34 changes: 33 additions & 1 deletion BDBOAuth1Manager/BDBOAuth1RequestSerializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ FOUNDATION_EXPORT NSString * const BDBOAuth1OAuthCallbackParameter;

#pragma mark -
@interface BDBOAuth1Credential : NSObject
<NSCoding, NSCopying>
<NSSecureCoding, NSCopying>

/**
* Token ('oauth_token')
Expand Down Expand Up @@ -130,6 +130,10 @@ FOUNDATION_EXPORT NSString * const BDBOAuth1OAuthCallbackParameter;
*/
@property (nonatomic, copy, readonly) BDBOAuth1Credential *accessToken;

/**
* Clock offset from the system time to use when calculating the date for the OAuth timestamp parameter
*/
@property (nonatomic, assign) NSTimeInterval clockOffset;

/**
* ---------------------------------------------------------------------------------------
Expand Down Expand Up @@ -164,6 +168,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
101 changes: 79 additions & 22 deletions BDBOAuth1Manager/BDBOAuth1RequestSerializer.m
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ - (BOOL)isExpired {
}
}

#pragma mark NSCoding
#pragma mark NSSecureCoding
+ (BOOL)supportsSecureCoding {
return YES;
}

- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];

Expand Down Expand Up @@ -173,6 +177,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 +219,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 @@ -286,8 +310,13 @@ - (NSDictionary *)OAuthParameters {
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[BDBOAuth1SignatureVersionParameter] = @"1.0";
parameters[BDBOAuth1SignatureConsumerKeyParameter] = self.consumerKey;
parameters[BDBOAuth1SignatureTimestampParameter] = [@(floor([[NSDate date] timeIntervalSince1970])) stringValue];
parameters[BDBOAuth1SignatureMethodParameter] = @"HMAC-SHA1";
parameters[BDBOAuth1SignatureTimestampParameter] = [@(floor([[NSDate dateWithTimeIntervalSinceNow:self.clockOffset] timeIntervalSince1970])) stringValue];

if (self.RSAPrivateKey) {
parameters[BDBOAuth1SignatureMethodParameter] = @"RSA-SHA1";
} else {
parameters[BDBOAuth1SignatureMethodParameter] = @"HMAC-SHA1";
}

CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
CFUUIDBytes uuidBytes = CFUUIDGetUUIDBytes(uuid);
Expand All @@ -302,14 +331,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 +343,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 +393,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 +426,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