Skip to content

Instantly share code, notes, and snippets.

@haikusw
Created November 7, 2011 01:42
Show Gist options
  • Save haikusw/1343978 to your computer and use it in GitHub Desktop.
Save haikusw/1343978 to your computer and use it in GitHub Desktop.
#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
#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
#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