Created
November 7, 2011 01:42
-
-
Save haikusw/1343978 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "AFRestClient+OAuth.h" | |
NSString * const kAFOAuthBasicGrantType = @"user_basic"; | |
NSString * const kAFOauthRefreshGrantType = @"refresh_token"; | |
@implementation AFRestClient (OAuth) | |
- (void)authenticateUsingOAuthWithPath:(NSString *)path | |
username:(NSString *)username | |
password:(NSString *)password | |
clientID:(NSString *)clientID | |
secret:(NSString *)secret | |
success:(void (^)(TTTOAuthAccount *account))success | |
failure:(void (^)(NSError *error))failure | |
{ | |
NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; | |
[parameters setObject:kAFOAuthBasicGrantType forKey:@"grant_type"]; | |
[parameters setObject:clientID forKey:@"client_id"]; | |
[parameters setObject:secret forKey:@"client_secret"]; | |
[parameters setObject:username forKey:@"username"]; | |
[parameters setObject:password forKey:@"password"]; | |
[self authenticateUsingOAuthWithPath:path parameters:parameters success:success failure:failure]; | |
} | |
- (void)authenticateUsingOAuthWithPath:(NSString *)path | |
refreshToken:(NSString *)refreshToken | |
clientID:(NSString *)clientID | |
secret:(NSString *)secret | |
success:(void (^)(TTTOAuthAccount *account))success | |
failure:(void (^)(NSError *error))failure | |
{ | |
NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; | |
[parameters setObject:kAFOauthRefreshGrantType forKey:@"grant_type"]; | |
[parameters setObject:clientID forKey:@"client_id"]; | |
[parameters setObject:secret forKey:@"client_secret"]; | |
[parameters setObject:refreshToken forKey:@"refresh_token"]; | |
[self authenticateUsingOAuthWithPath:path parameters:parameters success:success failure:failure]; | |
} | |
- (void)authenticateUsingOAuthWithPath:(NSString *)path | |
parameters:(NSDictionary *)parameters | |
success:(void (^)(TTTOAuthAccount *account))success | |
failure:(void (^)(NSError *error))failure | |
{ | |
[self clearAuthorizationHeader]; | |
[self postPath:path parameters:parameters success:^(id response) { | |
TTTOauthAccountCredential *credential = [TTTOauthAccountCredential credentialWithOAuthToken:[response valueForKey:@"access_token"] tokenSecret:[parameters valueForKey:@"client_secret"]]; | |
[credential setRefreshToken:[response valueForKey:@"refresh_token"] expiration:[NSDate dateWithTimeIntervalSinceNow:[[response valueForKey:@"expires_in"] integerValue]]]; | |
TTTOAuthAccount *account = [TTTOAuthAccount accountWithUsername:[response valueForKey:@"username"] serviceProviderIdentifier:kTTTGowallaServiceProviderIdentifier credential:credential]; | |
if ([credential isExpired]) { | |
if (![[parameters valueForKey:@"grant_type"] isEqualToString:kAFOauthRefreshGrantType]) { | |
[self authenticateUsingOAuthWithPath:path refreshToken:credential.refreshToken clientID:[parameters valueForKey:@"client_id"] secret:[parameters valueForKey:@"client_secret"] success:success failure:failure]; | |
} else { | |
if (failure) { | |
NSLog(@"Expired Token issued in Refresh"); | |
failure(nil); | |
} | |
} | |
} else { | |
NSLog(@"New access token: %@", credential.accessToken); | |
[self setAuthorizationHeaderWithToken:credential.accessToken]; | |
[TTTOAuthAccountStore storeAccount:account error:nil]; | |
if (success) { | |
success(account); | |
} | |
} | |
} failure:^(NSError *error) { | |
if (failure) { | |
failure(error); | |
} | |
}]; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "AFRestClient+OAuth.h" | |
NSString * const kAFOAuthBasicGrantType = @"user_basic"; | |
NSString * const kAFOauthRefreshGrantType = @"refresh_token"; | |
@implementation AFRestClient (OAuth) | |
- (void)authenticateUsingOAuthWithPath:(NSString *)path | |
username:(NSString *)username | |
password:(NSString *)password | |
clientID:(NSString *)clientID | |
secret:(NSString *)secret | |
success:(void (^)(TTTOAuthAccount *account))success | |
failure:(void (^)(NSError *error))failure | |
{ | |
NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; | |
[parameters setObject:kAFOAuthBasicGrantType forKey:@"grant_type"]; | |
[parameters setObject:clientID forKey:@"client_id"]; | |
[parameters setObject:secret forKey:@"client_secret"]; | |
[parameters setObject:username forKey:@"username"]; | |
[parameters setObject:password forKey:@"password"]; | |
[self authenticateUsingOAuthWithPath:path parameters:parameters success:success failure:failure]; | |
} | |
- (void)authenticateUsingOAuthWithPath:(NSString *)path | |
refreshToken:(NSString *)refreshToken | |
clientID:(NSString *)clientID | |
secret:(NSString *)secret | |
success:(void (^)(TTTOAuthAccount *account))success | |
failure:(void (^)(NSError *error))failure | |
{ | |
NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; | |
[parameters setObject:kAFOauthRefreshGrantType forKey:@"grant_type"]; | |
[parameters setObject:clientID forKey:@"client_id"]; | |
[parameters setObject:secret forKey:@"client_secret"]; | |
[parameters setObject:refreshToken forKey:@"refresh_token"]; | |
[self authenticateUsingOAuthWithPath:path parameters:parameters success:success failure:failure]; | |
} | |
- (void)authenticateUsingOAuthWithPath:(NSString *)path | |
parameters:(NSDictionary *)parameters | |
success:(void (^)(TTTOAuthAccount *account))success | |
failure:(void (^)(NSError *error))failure | |
{ | |
[self clearAuthorizationHeader]; | |
[self postPath:path parameters:parameters success:^(id response) { | |
TTTOauthAccountCredential *credential = [TTTOauthAccountCredential credentialWithOAuthToken:[response valueForKey:@"access_token"] tokenSecret:[parameters valueForKey:@"client_secret"]]; | |
[credential setRefreshToken:[response valueForKey:@"refresh_token"] expiration:[NSDate dateWithTimeIntervalSinceNow:[[response valueForKey:@"expires_in"] integerValue]]]; | |
TTTOAuthAccount *account = [TTTOAuthAccount accountWithUsername:[response valueForKey:@"username"] serviceProviderIdentifier:kTTTGowallaServiceProviderIdentifier credential:credential]; | |
if ([credential isExpired]) { | |
if (![[parameters valueForKey:@"grant_type"] isEqualToString:kAFOauthRefreshGrantType]) { | |
[self authenticateUsingOAuthWithPath:path refreshToken:credential.refreshToken clientID:[parameters valueForKey:@"client_id"] secret:[parameters valueForKey:@"client_secret"] success:success failure:failure]; | |
} else { | |
if (failure) { | |
NSLog(@"Expired Token issued in Refresh"); | |
failure(nil); | |
} | |
} | |
} else { | |
NSLog(@"New access token: %@", credential.accessToken); | |
[self setAuthorizationHeaderWithToken:credential.accessToken]; | |
[TTTOAuthAccountStore storeAccount:account error:nil]; | |
if (success) { | |
success(account); | |
} | |
} | |
} failure:^(NSError *error) { | |
if (failure) { | |
failure(error); | |
} | |
}]; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Security/Security.h> | |
#import "TTTOAuthAccount.h" | |
static NSString * const kTTTOauthKeychainIdentifier = @"com.mattt.keychain.oauth"; | |
NSString * const kTTTGowallaServiceProviderIdentifier = @"gowalla.com"; | |
@interface TTTOauthAccountCredential () | |
@property (readwrite, nonatomic, copy) NSString *accessToken; | |
@property (readwrite, nonatomic, copy) NSString *secret; | |
@property (readwrite, nonatomic, copy) NSString *refreshToken; | |
@property (readwrite, nonatomic, retain) NSDate *expiration; | |
@end | |
@implementation TTTOauthAccountCredential | |
@synthesize accessToken = _accessToken; | |
@synthesize secret = _secret; | |
@synthesize refreshToken = _refreshToken; | |
@synthesize expiration = _expiration; | |
@dynamic expired; | |
+ (id)credentialWithOAuthToken:(NSString *)token tokenSecret:(NSString *)secret { | |
return [[[self alloc] initWithOAuthToken:token tokenSecret:secret] autorelease]; | |
} | |
- (id)initWithOAuthToken:(NSString *)token tokenSecret:(NSString *)secret { | |
self = [super init]; | |
if (!self) { | |
return nil; | |
} | |
self.accessToken = token; | |
self.secret = secret; | |
return self; | |
} | |
- (void)dealloc { | |
[_accessToken release]; | |
[_secret release]; | |
[_refreshToken release]; | |
[_expiration release]; | |
[super dealloc]; | |
} | |
- (void)setRefreshToken:(NSString *)refreshToken expiration:(NSDate *)expiration { | |
if (!refreshToken || !expiration) { | |
return; | |
} | |
self.refreshToken = refreshToken; | |
self.expiration = expiration; | |
} | |
- (BOOL)isExpired { | |
return [self.expiration compare:[NSDate date]] == NSOrderedAscending; | |
} | |
- (NSString *)description { | |
return [NSString stringWithFormat:@"<%@ accessToken:\"%@\" secret:\"%@ refreshToken:\"%@\" expiration:\"%@\">", [self class], self.accessToken, self.secret, self.refreshToken, self.expiration]; | |
} | |
#pragma mark - NSCoding | |
- (id)initWithCoder:(NSCoder *)decoder { | |
self = [super init]; | |
self.accessToken = [decoder decodeObjectForKey:@"accessToken"]; | |
self.secret = [decoder decodeObjectForKey:@"secret"]; | |
self.refreshToken = [decoder decodeObjectForKey:@"refreshToken"]; | |
self.expiration = [decoder decodeObjectForKey:@"expiration"]; | |
return self; | |
} | |
- (void)encodeWithCoder:(NSCoder *)encoder { | |
[encoder encodeObject:self.accessToken forKey:@"accessToken"]; | |
[encoder encodeObject:self.secret forKey:@"secret"]; | |
[encoder encodeObject:self.refreshToken forKey:@"refreshToken"]; | |
[encoder encodeObject:self.expiration forKey:@"expiration"]; | |
} | |
@end | |
#pragma mark - | |
@interface TTTOAuthAccount () | |
@property (readwrite, nonatomic, copy) NSString *username; | |
@property (readwrite, nonatomic, copy) NSString *serviceProviderIdentifier; | |
@property (readwrite, nonatomic, retain) TTTOauthAccountCredential *credential; | |
- (NSDictionary *)genericPasswordAttributes; | |
@end | |
@implementation TTTOAuthAccount | |
@synthesize username = _username; | |
@synthesize serviceProviderIdentifier = _serviceProviderIdentifier; | |
@synthesize credential = _credential; | |
+ (id)accountWithUsername:(NSString *)username serviceProviderIdentifier:(NSString *)identifier credential:(TTTOauthAccountCredential *)credential { | |
return [[[self alloc] initWithUsername:username serviceProviderIdentifier:identifier credential:credential] autorelease]; | |
} | |
- (id)initWithUsername:(NSString *)username serviceProviderIdentifier:(NSString *)identifier credential:(TTTOauthAccountCredential *)credential { | |
self = [super init]; | |
if (!self) { | |
return nil; | |
} | |
self.username = username; | |
self.serviceProviderIdentifier = identifier; | |
self.credential = credential; | |
return self; | |
} | |
- (void)dealloc { | |
[_username release]; | |
[_serviceProviderIdentifier release]; | |
[_credential release]; | |
[super dealloc]; | |
} | |
// TODO: put this in the store as convenience method / function? | |
- (NSDictionary *)genericPasswordAttributes { | |
NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionary]; | |
[mutableAttributes setObject:(id)kSecClassGenericPassword | |
forKey:(id)kSecClass]; | |
[mutableAttributes setObject:(id)kTTTOauthKeychainIdentifier | |
forKey:(id)kSecAttrGeneric]; | |
[mutableAttributes setObject:(id)self.username | |
forKey:(id)kSecAttrAccount]; | |
[mutableAttributes setObject:(id)self.serviceProviderIdentifier | |
forKey:(id)kSecAttrService]; | |
return [NSDictionary dictionaryWithDictionary:mutableAttributes]; | |
} | |
- (NSString *)description { | |
return [NSString stringWithFormat:@"<%@ provider:\"%@\" username:\"%@\" credential:%@>", [self class], self.serviceProviderIdentifier, self.username, self.credential]; | |
} | |
@end | |
#pragma mark - | |
@implementation TTTOAuthAccountStore | |
+ (TTTOauthAccountCredential *)credentialsForAccountWithUsername:(NSString *)username serviceProviderIdentifier:(NSString *)identifier error:(NSError **)error { | |
NSMutableDictionary *mutableQuery = [NSMutableDictionary dictionary]; | |
[mutableQuery setObject:(id)kSecClassGenericPassword | |
forKey:(id)kSecClass]; | |
[mutableQuery setObject:(id)kTTTOauthKeychainIdentifier | |
forKey:(id)kSecAttrGeneric]; | |
[mutableQuery setObject:username | |
forKey:(id)kSecAttrAccount]; | |
[mutableQuery setObject:identifier | |
forKey:(id)kSecAttrService]; | |
NSDictionary *query = [NSDictionary dictionaryWithDictionary:mutableQuery]; | |
OSStatus status = noErr; | |
NSData *resultData = nil; | |
NSMutableDictionary *dataQuery = [[query mutableCopy] autorelease]; | |
[dataQuery setObject:(id)kCFBooleanTrue | |
forKey:(id)kSecReturnData]; | |
status = SecItemCopyMatching((CFDictionaryRef)dataQuery, (CFTypeRef *)&resultData); | |
TTTOauthAccountCredential *credential = [NSKeyedUnarchiver unarchiveObjectWithData:resultData]; | |
return credential; | |
} | |
+ (void)storeCredential:(TTTOauthAccountCredential *)credential forAccountWithUsername:(NSString *)username serviceProviderIdentifier:(NSString *)identifier error:(NSError **)error { | |
TTTOAuthAccount *account = [[[TTTOAuthAccount alloc] initWithUsername:username serviceProviderIdentifier:identifier credential:credential] autorelease]; | |
[self storeAccount:account error:error]; | |
} | |
+ (void)storeAccount:(TTTOAuthAccount *)account error:(NSError **)error { | |
// OSStatus status = SecItemAdd((CFDictionaryRef)[account genericPasswordAttributes], NULL); | |
NSMutableDictionary *mutableQuery = [NSMutableDictionary dictionary]; | |
[mutableQuery setObject:(id)kSecClassGenericPassword | |
forKey:(id)kSecClass]; | |
[mutableQuery setObject:(id)kTTTOauthKeychainIdentifier | |
forKey:(id)kSecAttrGeneric]; | |
[mutableQuery setObject:account.username | |
forKey:(id)kSecAttrAccount]; | |
[mutableQuery setObject:account.serviceProviderIdentifier | |
forKey:(id)kSecAttrService]; | |
NSDictionary *query = [NSDictionary dictionaryWithDictionary:mutableQuery]; | |
SecItemDelete((CFDictionaryRef)query); | |
NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:[account genericPasswordAttributes]]; | |
[mutableAttributes setObject:(id)[NSKeyedArchiver archivedDataWithRootObject:account.credential] forKey:(id)kSecValueData]; | |
SecItemAdd((CFDictionaryRef)mutableAttributes, NULL); | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment