diff --git a/ADNKit/ANKClient.h b/ADNKit/ANKClient.h index 45ec194..9830cc2 100644 --- a/ADNKit/ANKClient.h +++ b/ADNKit/ANKClient.h @@ -28,6 +28,17 @@ typedef NS_ENUM(NSUInteger, ANKAuthScope) { ANKAuthScopeExport = (1 << 9), // bulk export all of this user’s App.net data }; +extern NSString * const kANKAuthScopeNone; +extern NSString * const kANKAuthScopeBasic; +extern NSString * const kANKAuthScopeStream; +extern NSString * const kANKAuthScopeEmail; +extern NSString * const kANKAuthScopeWritePost; +extern NSString * const kANKAuthScopeFollow; +extern NSString * const kANKAuthScopePublicMessages; +extern NSString * const kANKAuthScopeMessages; +extern NSString * const kANKAuthScopeUpdateProfile; +extern NSString * const kANKAuthScopeFiles; +extern NSString * const kANKAuthScopeExport; typedef NS_ENUM(NSUInteger, ANKResponseDecodingType) { ANKResponseDecodingTypeModel = 0, // default - decodes server responses as model objects @@ -63,9 +74,25 @@ typedef void (^ANKClientCompletionBlock)(id responseObject, ANKAPIResponseMeta * #pragma mark - #pragma mark Authentication -// username/password authentication +/** Username/password authentication */ + +- (void)authenticateUsername:(NSString *)username + password:(NSString *)password + clientID:(NSString *)clientID + passwordGrantSecret:(NSString *)passwordGrantSecret + authScopeArray:(NSArray *)authScopes + completionHandler:(void (^)(BOOL success, NSError *error))completionHander; + +/** Username/password authentication */ - (void)authenticateUsername:(NSString *)username password:(NSString *)password clientID:(NSString *)clientID passwordGrantSecret:(NSString *)passwordGrantSecret authScopes:(ANKAuthScope)authScopes completionHandler:(void (^)(BOOL success, NSError *error))completionHander; +/** Web-style authentication. Call this method first, and then load the resulting URLRequest in a WebView. */ +- (NSURLRequest *)webAuthRequestForClientID:(NSString *)clientID + redirectURI:(NSString *)redirectURI + authScopeArray:(NSArray *)authScopes + state:(NSString *)state + appStoreCompliant:(BOOL)shouldBeAppStoreCompliant; + // web-style authentication. call this method first, and then load the resulting URLRequest is a webview - (NSURLRequest *)webAuthRequestForClientID:(NSString *)clientID redirectURI:(NSString *)redirectURI authScopes:(ANKAuthScope)authScopes state:(NSString *)state appStoreCompliant:(BOOL)shouldBeAppStoreCompliant; // once you have an access code, call this method to finish web auth @@ -74,6 +101,9 @@ typedef void (^ANKClientCompletionBlock)(id responseObject, ANKAPIResponseMeta * // returns the auth scope string expected by the server for the given scopes + (NSString *)scopeStringForAuthScopes:(ANKAuthScope)scopes; +/** Returns the auth scopes expected by the server for the given scopes */ ++ (NSArray *)scopeArrayForAuthScopes:(ANKAuthScope)scopes; + // to conform to the requirements of username/password auth, it is required to show the user what permissions they are authorizing for you by signing in. // this method returns full descriptions for the given scopes that can be placed in the UI + (NSArray *)scopeDescriptionsForScope:(ANKAuthScope)scope; diff --git a/ADNKit/ANKClient.m b/ADNKit/ANKClient.m index 182cd39..fcf411f 100644 --- a/ADNKit/ANKClient.m +++ b/ADNKit/ANKClient.m @@ -20,6 +20,16 @@ #import "ANKUser.h" #import "ANKClient+ANKTokenStatus.h" +NSString * const kANKAuthScopeBasic = @"basic"; +NSString * const kANKAuthScopeStream = @"stream"; +NSString * const kANKAuthScopeEmail = @"email"; +NSString * const kANKAuthScopeWritePost = @"write_post"; +NSString * const kANKAuthScopeFollow = @"follow"; +NSString * const kANKAuthScopePublicMessages = @"public_messages"; +NSString * const kANKAuthScopeMessages = @"messages"; +NSString * const kANKAuthScopeUpdateProfile = @"update_profile"; +NSString * const kANKAuthScopeFiles = @"export"; +NSString * const kANKAuthScopeExport = @"files"; @interface ANKClient () @@ -121,6 +131,27 @@ - (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)p #pragma mark - #pragma mark Authentication +- (void)authenticateUsername:(NSString *)username + password:(NSString *)password + clientID:(NSString *)clientID + passwordGrantSecret:(NSString *)passwordGrantSecret + authScopeArray:(NSArray *)authScopes + completionHandler:(void (^)(BOOL success, NSError *error))completionHander +{ + // http://developers.app.net/docs/authentication/flows/password/ + + NSDictionary *parameters = + @{@"client_id" : clientID, + @"password_grant_secret": passwordGrantSecret, + @"grant_type" : @"password", + @"username" : username, + @"password" : password, + @"scope" : [authScopes componentsJoinedByString:@","]}; + + [self authenticateWithParameters:parameters handler:completionHander]; +} + + - (void)authenticateUsername:(NSString *)username password:(NSString *)password clientID:(NSString *)clientID passwordGrantSecret:(NSString *)passwordGrantSecret authScopes:(ANKAuthScope)authScopes completionHandler:(void (^)(BOOL success, NSError *error))completionHander { // http://developers.app.net/docs/authentication/flows/password/ @@ -131,11 +162,28 @@ - (void)authenticateUsername:(NSString *)username password:(NSString *)password - (NSURLRequest *)webAuthRequestForClientID:(NSString *)clientID redirectURI:(NSString *)redirectURI authScopes:(ANKAuthScope)authScopes state:(NSString *)state appStoreCompliant:(BOOL)shouldBeAppStoreCompliant { // http://developers.app.net/docs/authentication/flows/web/ + + + return [self webAuthRequestForClientID:clientID + redirectURI:redirectURI + authScopeArray:[[self class] scopeArrayForAuthScopes:authScopes] + state:state + appStoreCompliant:shouldBeAppStoreCompliant]; +} + + +- (NSURLRequest *)webAuthRequestForClientID:(NSString *)clientID + redirectURI:(NSString *)redirectURI + authScopeArray:(NSArray *)authScopes + state:(NSString *)state + appStoreCompliant:(BOOL)shouldBeAppStoreCompliant +{ + self.webAuthRedirectURI = redirectURI; NSMutableString *URLString = [NSMutableString stringWithFormat:@"https://account.app.net/oauth/authenticate?client_id=%@&response_type=code", clientID]; - - if (authScopes) { - [URLString appendFormat:@"&scope=%@", [[self class] scopeStringForAuthScopes:authScopes]]; + + if (authScopes && authScopes.count > 0) { + [URLString appendFormat:@"&scope=%@", [authScopes componentsJoinedByString:@","]]; } if (redirectURI) { @@ -163,10 +211,17 @@ - (void)authenticateWebAuthAccessCode:(NSString *)accessCode forClientID:(NSStri + (NSString *)scopeStringForAuthScopes:(ANKAuthScope)scopes { - if (scopes == ANKAuthScopeNone) return nil; - + NSArray *scopeValues = [self scopeArrayForAuthScopes:scopes]; + + return [scopeValues componentsJoinedByString:@","]; +} + + ++ (NSArray *)scopeArrayForAuthScopes:(ANKAuthScope)scopes { + if (scopes == ANKAuthScopeNone) return @[]; + NSMutableArray *scopeValues = [NSMutableArray array]; - + if ((scopes & ANKAuthScopeBasic) == ANKAuthScopeBasic) [scopeValues addObject:@"basic"]; if ((scopes & ANKAuthScopeStream) == ANKAuthScopeStream) [scopeValues addObject:@"stream"]; if ((scopes & ANKAuthScopeEmail) == ANKAuthScopeEmail) [scopeValues addObject:@"email"]; @@ -177,8 +232,8 @@ + (NSString *)scopeStringForAuthScopes:(ANKAuthScope)scopes { if ((scopes & ANKAuthScopeUpdateProfile) == ANKAuthScopeUpdateProfile) [scopeValues addObject:@"update_profile"]; if ((scopes & ANKAuthScopeExport) == ANKAuthScopeExport) [scopeValues addObject:@"export"]; if ((scopes & ANKAuthScopeFiles) == ANKAuthScopeFiles) [scopeValues addObject:@"files"]; - - return [scopeValues componentsJoinedByString:@","]; + + return [scopeValues copy]; }