From 572f9623d1577baf22cd4a31b2c1ba8dd1bce774 Mon Sep 17 00:00:00 2001 From: Mahendra Nimishakavi Date: Mon, 20 Nov 2017 18:14:03 +0530 Subject: [PATCH 1/8] initial code related to browser based authentication --- MASFoundation.xcodeproj/project.pbxproj | 16 ++ MASFoundation/Classes/MAS.h | 9 + MASFoundation/Classes/MAS.m | 6 + .../categories/UIAlertController+MAS.h | 69 ++++++ .../categories/UIAlertController+MAS.m | 172 ++++++++++++++ .../_private_/services/MASServiceRegistry.h | 11 + .../_private_/services/MASServiceRegistry.m | 15 ++ .../services/model/MASModelService.h | 17 ++ .../services/model/MASModelService.m | 30 ++- .../models/MASBrowserBasedAuthentication.h | 34 +++ .../models/MASBrowserBasedAuthentication.m | 218 ++++++++++++++++++ 11 files changed, 594 insertions(+), 3 deletions(-) create mode 100644 MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h create mode 100644 MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m create mode 100644 MASFoundation/Classes/models/MASBrowserBasedAuthentication.h create mode 100644 MASFoundation/Classes/models/MASBrowserBasedAuthentication.m diff --git a/MASFoundation.xcodeproj/project.pbxproj b/MASFoundation.xcodeproj/project.pbxproj index cac3bf9e..237e62ba 100644 --- a/MASFoundation.xcodeproj/project.pbxproj +++ b/MASFoundation.xcodeproj/project.pbxproj @@ -293,6 +293,10 @@ A4F671331BAFC345000E2223 /* NSString+MASPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = A4F671311BAFC345000E2223 /* NSString+MASPrivate.m */; }; A858C6651D0978A6001FB9AD /* MASOTPService.h in Headers */ = {isa = PBXBuildFile; fileRef = A858C6631D0978A6001FB9AD /* MASOTPService.h */; }; A858C6661D0978A6001FB9AD /* MASOTPService.m in Sources */ = {isa = PBXBuildFile; fileRef = A858C6641D0978A6001FB9AD /* MASOTPService.m */; }; + C81CC3CC1FC2EA190058718E /* MASBrowserBasedAuthentication.h in Headers */ = {isa = PBXBuildFile; fileRef = C81CC3CA1FC2EA190058718E /* MASBrowserBasedAuthentication.h */; }; + C81CC3CD1FC2EA190058718E /* MASBrowserBasedAuthentication.m in Sources */ = {isa = PBXBuildFile; fileRef = C81CC3CB1FC2EA190058718E /* MASBrowserBasedAuthentication.m */; }; + C81CC3D01FC2EFBB0058718E /* UIAlertController+MAS.h in Headers */ = {isa = PBXBuildFile; fileRef = C81CC3CE1FC2EFBB0058718E /* UIAlertController+MAS.h */; }; + C81CC3D11FC2EFBB0058718E /* UIAlertController+MAS.m in Sources */ = {isa = PBXBuildFile; fileRef = C81CC3CF1FC2EFBB0058718E /* UIAlertController+MAS.m */; }; CB0A8ADF1D01F64F00B1DCCC /* MASProximityLogin.h in Headers */ = {isa = PBXBuildFile; fileRef = CB0A8ADD1D01F64F00B1DCCC /* MASProximityLogin.h */; settings = {ATTRIBUTES = (Public, ); }; }; CB0A8AE01D01F64F00B1DCCC /* MASProximityLogin.m in Sources */ = {isa = PBXBuildFile; fileRef = CB0A8ADE1D01F64F00B1DCCC /* MASProximityLogin.m */; }; CB0B58591E258C2A00BC0163 /* MASAuthorizationResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = CB0B58571E258C2A00BC0163 /* MASAuthorizationResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -720,6 +724,10 @@ A4F671311BAFC345000E2223 /* NSString+MASPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+MASPrivate.m"; sourceTree = ""; }; A858C6631D0978A6001FB9AD /* MASOTPService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASOTPService.h; sourceTree = ""; }; A858C6641D0978A6001FB9AD /* MASOTPService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASOTPService.m; sourceTree = ""; }; + C81CC3CA1FC2EA190058718E /* MASBrowserBasedAuthentication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MASBrowserBasedAuthentication.h; sourceTree = ""; }; + C81CC3CB1FC2EA190058718E /* MASBrowserBasedAuthentication.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MASBrowserBasedAuthentication.m; sourceTree = ""; }; + C81CC3CE1FC2EFBB0058718E /* UIAlertController+MAS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertController+MAS.h"; sourceTree = ""; }; + C81CC3CF1FC2EFBB0058718E /* UIAlertController+MAS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertController+MAS.m"; sourceTree = ""; }; CB0A8ADD1D01F64F00B1DCCC /* MASProximityLogin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASProximityLogin.h; sourceTree = ""; }; CB0A8ADE1D01F64F00B1DCCC /* MASProximityLogin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASProximityLogin.m; sourceTree = ""; }; CB0B58571E258C2A00BC0163 /* MASAuthorizationResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASAuthorizationResponse.h; sourceTree = ""; }; @@ -1348,6 +1356,8 @@ CBA3EB2D1E945F2400E64D9D /* MASClaims.m */, CB1FD1491FB23701000AFA25 /* MASSharedStorage.h */, CB1FD14A1FB23701000AFA25 /* MASSharedStorage.m */, + C81CC3CA1FC2EA190058718E /* MASBrowserBasedAuthentication.h */, + C81CC3CB1FC2EA190058718E /* MASBrowserBasedAuthentication.m */, ); path = models; sourceTree = ""; @@ -1402,6 +1412,8 @@ A4F6712F1BAFC321000E2223 /* categories */ = { isa = PBXGroup; children = ( + C81CC3CE1FC2EFBB0058718E /* UIAlertController+MAS.h */, + C81CC3CF1FC2EFBB0058718E /* UIAlertController+MAS.m */, CB1907ED1C1794F400A5EF16 /* MASIKeyChainStore+MASPrivate.h */, CB1907EE1C1794F400A5EF16 /* MASIKeyChainStore+MASPrivate.m */, A483C1FF1BE6D0C5007572CE /* CBCentralManager+MASPrivate.h */, @@ -1724,9 +1736,11 @@ 105B2F4B1CA6B3EA0005A2D0 /* ripemd.h in Headers */, A46F49F11C2F5FC500A4C370 /* MASINTULocationRequestDefines.h in Headers */, CB5E4C641C1D1B56001B3B8A /* MASGetURLRequest.h in Headers */, + C81CC3CC1FC2EA190058718E /* MASBrowserBasedAuthentication.h in Headers */, 105B2F471CA6B3EA0005A2D0 /* pqueue.h in Headers */, 105B2F371CA6B3EA0005A2D0 /* kssl.h in Headers */, 105B2F511CA6B3EA0005A2D0 /* srtp.h in Headers */, + C81CC3D01FC2EFBB0058718E /* UIAlertController+MAS.h in Headers */, CBFA70F41F1ED5D6006D025D /* MASSecurityPolicy.h in Headers */, CBD25AF51E78C47C00DFB47F /* JWTCryptoKeyExtractor.h in Headers */, 105B2F5F1CA6B3EA0005A2D0 /* x509_vfy.h in Headers */, @@ -2092,6 +2106,7 @@ A4150EFC1BF16EE200037E27 /* MASKeyChainService.m in Sources */, A47F12811C1D73530008E3F2 /* MASBluetoothPeripheral.m in Sources */, CBD25B061E78C47C00DFB47F /* JWTCoding+VersionThree.m in Sources */, + C81CC3D11FC2EFBB0058718E /* UIAlertController+MAS.m in Sources */, CBD25AED1E78C47C00DFB47F /* JWTAlgorithmDataHolderChain.m in Sources */, A46F49DA1C2F5FC500A4C370 /* MASINetworkActivityIndicatorManager.m in Sources */, A4831AAE1BD1A551007B4AE6 /* MASConfiguration.m in Sources */, @@ -2152,6 +2167,7 @@ A46F49C51C2F5FC500A4C370 /* MASIHTTPRequestOperation.m in Sources */, A4150E701BF1643900037E27 /* MASIJSONResponseSerializer+MASPrivate.m in Sources */, A417BA521BF033C300EC9BCB /* CLLocation+MASPrivate.m in Sources */, + C81CC3CD1FC2EA190058718E /* MASBrowserBasedAuthentication.m in Sources */, 69B7DF6D1F96756B0056DD3A /* MASRequest+MASPrivate.m in Sources */, A4831AB21BD1A551007B4AE6 /* MASFile.m in Sources */, CB0B585A1E258C2A00BC0163 /* MASAuthorizationResponse.m in Sources */, diff --git a/MASFoundation/Classes/MAS.h b/MASFoundation/Classes/MAS.h index 8d290576..1e10044a 100644 --- a/MASFoundation/Classes/MAS.h +++ b/MASFoundation/Classes/MAS.h @@ -110,6 +110,15 @@ + (void)setOTPCredentialsBlock:(MASOTPCredentialsBlock _Nullable)oneTimePassword; +/** + * Sets Bool indicator of Browser Based Authentication (templatized login) enabled or not for authorization process. + * By default, it is disabled. + + @param enable BOOL value indicating whether Browser Based Authentication is enabled or not. + */ ++(void)enableBrowserBasedAuthentication:(BOOL)enable; + + /** * Sets the gateway monitoring block defined by the GatewayMonitorStatusBlock type. diff --git a/MASFoundation/Classes/MAS.m b/MASFoundation/Classes/MAS.m index 6f470ced..98787fd9 100644 --- a/MASFoundation/Classes/MAS.m +++ b/MASFoundation/Classes/MAS.m @@ -92,6 +92,12 @@ + (void)setOTPCredentialsBlock:(MASOTPCredentialsBlock)oneTimePassword } ++(void)enableBrowserBasedAuthentication:(BOOL)enable +{ + [[MASModelService sharedService] setBrowserBasedLogin:enable]; +} + + + (void)setGatewayMonitor:(MASGatewayMonitorStatusBlock)monitor { [MASNetworkingService setGatewayMonitor:monitor]; diff --git a/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h new file mode 100644 index 00000000..7b158d89 --- /dev/null +++ b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h @@ -0,0 +1,69 @@ +// +// UIAlertController+MAS.h +// MASFoundation +// +// Created by nimma01 on 11/10/17. +// Copyright © 2017 CA Technologies. All rights reserved. +// + +#import + +@interface UIAlertController (MAS) +///-------------------------------------- +/// @name Authentication Alerts +///------------------------------------- + +# pragma mark - Authentication Alerts + +/** + * Displays on screen an authentication UIAlertController modally in the currently + * visible UIViewController. + */ ++ (void)popupAuthenticationAlert; + + +/** + * Displays on screen an authentication UIAlertController modally in the selected + * UIViewController modally. + * + * @param viewController The UIViewController in which to present the modal UIAlertController. + */ ++ (void)popupAuthenticationAlertInViewController:(UIViewController *)viewController; + + + +///-------------------------------------- +/// @name Error Alerts +///------------------------------------- + +# pragma mark - Error Alerts + +/** + * Displays on screen an error UIAlertController modally in the currently + * visible UIViewController. + */ ++ (void)popupErrorAlert:(NSError *)error; + + +/** + * Displays on screen an error UIAlertController modally in the selected + * UIViewController modally. + * + * @param error The NSError contents to show in the UIAlertController. + * @param viewController The UIViewController in which to present the modal UIAlertController. + */ ++ (void)popupErrorAlert:(NSError *)error inViewController:(UIViewController *)viewController; + + + +///-------------------------------------- +/// @name Public +///------------------------------------- + +# pragma mark - Public + +/** + * Retrieve the currently visible UIViewController. + */ ++ (UIViewController *)rootViewController; +@end diff --git a/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m new file mode 100644 index 00000000..a34df9a5 --- /dev/null +++ b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m @@ -0,0 +1,172 @@ +// +// UIAlertController+MAS.m +// MASFoundation +// +// Created by nimma01 on 11/10/17. +// Copyright © 2017 CA Technologies. All rights reserved. +// + +#import "UIAlertController+MAS.h" +#import "MASUser.h" +@implementation UIAlertController (MAS) +# pragma mark - Authentication Alerts + ++ (void)popupAuthenticationAlert +{ + [self popupAuthenticationAlertInViewController:[self rootViewController]]; +} + + ++ (void)popupAuthenticationAlertInViewController:(UIViewController *)viewController +{ + // + // Ensure this is done in the main UI thread. We don't know where the call is coming from + // + dispatch_async(dispatch_get_main_queue(), ^ + { + // + // Create alert controller + // + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Sign In (MASUI)" + message:@"You need to sign in with your user credentials" + preferredStyle:UIAlertControllerStyleAlert]; + + // + // Username text field + // + [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) + { + textField.placeholder = NSLocalizedString(@"username", nil); + }]; + + // + // Password text field + // + [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) + { + textField.placeholder = NSLocalizedString(@"password", nil); + textField.secureTextEntry = YES; + }]; + + // + // OK Action + // + UIAlertAction *okAction = [UIAlertAction + actionWithTitle:NSLocalizedString(@"OK", @"OK action") + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) + { + UITextField *usernameTextField = alertController.textFields.firstObject; + UITextField *passwordTextField = alertController.textFields.lastObject; + + // + // Attempt to authenticate + // + [MASUser loginWithUserName:usernameTextField.text password:passwordTextField.text completion:^(BOOL completed, NSError *error) { + + DLog(@"viewController received authentication response completed: %@ or error: %@", + (completed ? @"Yes" : @"No"), [error debugDescription]); + + if(error) + { + [UIAlertController popupErrorAlert:error]; + return; + } + }]; + }]; + + [alertController addAction:okAction]; + + // + // Cancel Action + // + UIAlertAction *cancelAction = [UIAlertAction + actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel action") + style:UIAlertActionStyleDefault + handler:nil]; + + [alertController addAction:cancelAction]; + + [viewController presentViewController:alertController animated:YES completion:nil]; + }); +} + + +# pragma mark - Error Alert + ++ (void)popupErrorAlert:(NSError *)error +{ + [self popupErrorAlert:error inViewController:[self rootViewController]]; +} + + ++ (void)popupErrorAlert:(NSError *)error inViewController:(UIViewController *)viewController +{ + // + // Ensure this is done in the main UI thread. We don't know where the call is coming from + // + dispatch_async(dispatch_get_main_queue(), ^ + { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Error" + message:[error localizedDescription] + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) + { + [alertController dismissViewControllerAnimated:YES completion:nil]; + }]; + + [alertController addAction:ok]; + + [viewController presentViewController:alertController animated:NO completion:nil]; + }); +} + + ++ (UIViewController *) presentedViewController:(id)viewController +{ + if ([viewController isKindOfClass:[UINavigationController class]]) + { + UINavigationController *navigationController = (UINavigationController *)viewController; + return [self presentedViewController:navigationController.topViewController]; + } + if ([viewController isKindOfClass:[UIViewController class]]) + { + if ([viewController presentedViewController]) + { + if ([[viewController presentedViewController] isKindOfClass:[UINavigationController class]]) + { + UINavigationController *navigationController = (UINavigationController *)[viewController presentedViewController]; + + if (navigationController.isBeingDismissed) + { + return viewController; + } + } + + return [self presentedViewController:[viewController presentedViewController]]; + } + else { + return viewController; + } + } + else if ([viewController isKindOfClass:[UITabBarController class]]) + { + UITabBarController *tabBarController = (UITabBarController *)viewController; + return [self presentedViewController:tabBarController.presentedViewController]; + } + else { + return nil; + } +} + + +# pragma mark - Public + ++ (UIViewController *)rootViewController +{ + return [self presentedViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; +} +@end diff --git a/MASFoundation/Classes/_private_/services/MASServiceRegistry.h b/MASFoundation/Classes/_private_/services/MASServiceRegistry.h index 694f9508..34b5ec54 100644 --- a/MASFoundation/Classes/_private_/services/MASServiceRegistry.h +++ b/MASFoundation/Classes/_private_/services/MASServiceRegistry.h @@ -187,4 +187,15 @@ typedef NS_ENUM(NSInteger, MASRegistryState) - (BOOL)uiServiceWillHandleOTPChannelSelection:(NSArray *)supportedChannels otpGenerationBlock:(MASOTPGenerationBlock)generationBlock; + +/** + * Calling this method will attempt to launch a browser which handles the user authentication steps. + * For this method to handle authentication it requires browser based login to be enabled. + * @see enableBrowserBasedAuthentication + * + * @param bbaLoginBlock The MASCompletionErrorBlock to receive login result. + * @return Return YES if handled, NO if not. + */ +-(BOOL)browserBasedLoginWillHandleAuthentication : (MASCompletionErrorBlock)bbaLoginBlock; + @end diff --git a/MASFoundation/Classes/_private_/services/MASServiceRegistry.m b/MASFoundation/Classes/_private_/services/MASServiceRegistry.m index 9c375214..b0788eeb 100644 --- a/MASFoundation/Classes/_private_/services/MASServiceRegistry.m +++ b/MASFoundation/Classes/_private_/services/MASServiceRegistry.m @@ -15,6 +15,8 @@ #import "MASConfigurationService.h" #import "MASModelService.h" #import "MASService.h" +#import "MASServiceRegistry.h" +#import "MASBrowserBasedAuthentication.h" // @@ -932,4 +934,17 @@ - (BOOL)uiServiceWillHandleOTPChannelSelection:(NSArray *)supportedChannels return YES; } + +-(BOOL)browserBasedLoginWillHandleAuthentication : (MASCompletionErrorBlock)bbaLoginBlock +{ + if(![[MASModelService sharedService] browserBasedLogin]) + { + return NO; + } + + [[MASBrowserBasedAuthentication sharedInstance] loadWebLoginTemplate:bbaLoginBlock]; + return YES; + +} + @end diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.h b/MASFoundation/Classes/_private_/services/model/MASModelService.h index 50b63377..4155579d 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.h +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.h @@ -82,6 +82,23 @@ - (void)setUserObject:(MASUser *)user; +/** + * Sets the browser based authentication property. Default is NO. + * + * @param browserBasedLogin The state of browser based authentication. + * If this is set to true, a URL which has a templatized login is launched in a browser and this would disable the Social Login, Proximity Login and also prevents the launch of MASUI. + */ +-(void)setBrowserBasedLogin : (BOOL)browserBasedLogin; + + +/** + * The current state of browser based login. + * + * @return BOOL value is returned. + */ +-(BOOL)browserBasedLogin; + + ///-------------------------------------- /// @name Application ///-------------------------------------- diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.m b/MASFoundation/Classes/_private_/services/model/MASModelService.m index e89189f2..ce60366d 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.m +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.m @@ -29,6 +29,7 @@ @interface MASModelService () @property (nonatomic, strong, readwrite) MASAuthenticationProviders *currentProviders; +@property (nonatomic) BOOL isBrowserBasedLogin; @end @@ -39,7 +40,6 @@ @implementation MASModelService static MASUserLoginWithUserCredentialsBlock _userLoginBlock_ = nil; static MASUserAuthCredentialsBlock _userAuthCredentialsBlock_ = nil; - # pragma mark - Properties @@ -71,6 +71,19 @@ - (void)setUserObject:(MASUser *)user _currentUser = user; } + +-(void)setBrowserBasedLogin : (BOOL)browserBasedLogin +{ + self.isBrowserBasedLogin = browserBasedLogin; +} + + +-(BOOL)browserBasedLogin +{ + return self.isBrowserBasedLogin; +} + + # pragma mark - Shared Service + (instancetype)sharedService @@ -367,7 +380,7 @@ - (void)retrieveAuthenticationProviders:(MASObjectResponseErrorBlock)completion // // If the user was already authenticated, we don't have to retrieve the authentication provider // - if (([MASApplication currentApplication].isAuthenticated && [MASApplication currentApplication].authenticationStatus == MASAuthenticationStatusLoginWithUser) || [MASAccess currentAccess].isSessionLocked) + if (([MASApplication currentApplication].isAuthenticated && [MASApplication currentApplication].authenticationStatus == MASAuthenticationStatusLoginWithUser) || [MASAccess currentAccess].isSessionLocked || self.isBrowserBasedLogin) { // @@ -906,9 +919,15 @@ - (void)registerDeviceWithCompletion:(MASCompletionErrorBlock)completion @"\n\n********************************************************\n\n\n"); // - // If the UI handling framework is present and will handle this stop here + // If the UI handling framework or browser based login is present and will handle this stop here // MASServiceRegistry *serviceRegistry = [MASServiceRegistry sharedRegistry]; + + if([serviceRegistry browserBasedLoginWillHandleAuthentication:completion]) + { + return; + } + if([serviceRegistry uiServiceWillHandleWithAuthCredentialsBlock:authCredentialsBlock]) { return; @@ -1712,6 +1731,11 @@ - (void)loginUsingUserCredentials:(MASCompletionErrorBlock)completion // If the UI handling framework is present and will handle this stop here // MASServiceRegistry *serviceRegistry = [MASServiceRegistry sharedRegistry]; + if([serviceRegistry browserBasedLoginWillHandleAuthentication:completion]) + { + return; + } + if([serviceRegistry uiServiceWillHandleWithAuthCredentialsBlock:authCredentialsBlock]) { return; diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h new file mode 100644 index 00000000..e0b79d3c --- /dev/null +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h @@ -0,0 +1,34 @@ +// +// MASBrowserBasedAuthentication.h +// MASFoundation +// +// Created by nimma01 on 20/11/17. +// Copyright © 2017 CA Technologies. All rights reserved. +// + +#import +#import "MASConstants.h" + +@interface MASBrowserBasedAuthentication : NSObject +{ + +} + + +/** + * Retrieve the shared MASBrowserBasedAuthentication singleton. + * + * @return Returns the shared MASBrowserBasedAuthentication singleton. + */ ++ (instancetype)sharedInstance; + + + +/** + * Method to load the browser with a URL that loads a templatized login page. + * + * @param webLoginBlock completion MASCompletionErrorBlock that receives the results. + */ +-(void)loadWebLoginTemplate : (MASCompletionErrorBlock)webLoginBlock; + +@end diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m new file mode 100644 index 00000000..a303bf7b --- /dev/null +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m @@ -0,0 +1,218 @@ +// +// MASBrowserBasedAuthentication.m +// MASFoundation +// +// Created by nimma01 on 20/11/17. +// Copyright © 2017 CA Technologies. All rights reserved. +// + +#import "MASBrowserBasedAuthentication.h" +#import +#import "MASAuthorizationResponse.h" +#import "UIAlertController+MAS.h" +#import "MASConfigurationService.h" +#import "MASAccessService.h" +#import "MASGetURLRequest.h" +#import "MASModelService.h" + +@interface MASBrowserBasedAuthentication () +{ + +} + +@property (nonatomic) SFSafariViewController* safariViewController; +@property (nonatomic) MASCompletionErrorBlock webLoginCallBack; + +@end + +@implementation MASBrowserBasedAuthentication + + +# pragma mark - Shared Service + ++ (instancetype)sharedInstance +{ + static id sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^ + { + sharedInstance = [[MASBrowserBasedAuthentication alloc] init]; + }); + + return sharedInstance; +} + + +-(void)loadWebLoginTemplate : (MASCompletionErrorBlock)webLoginBlock +{ + self.webLoginCallBack = webLoginBlock; + MASModelService* service = [MASModelService sharedService]; + [[MASAuthorizationResponse sharedInstance] setDelegate:self]; + __block MASBrowserBasedAuthentication *blockSelf = self; + + // + // Try to register so that all the essential things are set up in that API call and we get a valid URL. If Application is already registered the API returns without doing any work. + // + [service registerApplication:^(BOOL completed, NSError *error) { + + NSURL* url = [blockSelf getURLForWebLogin]; + DLog(@"url used for browser based authentication is %@",url.absoluteString); + blockSelf.safariViewController = [[SFSafariViewController alloc] initWithURL:url]; + __block UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:blockSelf.safariViewController]; + + dispatch_async(dispatch_get_main_queue(), ^ + { + [UIAlertController rootViewController].modalTransitionStyle = UIModalTransitionStyleCoverVertical; + + [[UIAlertController rootViewController] presentViewController:navigationController animated:YES + completion:^{ + + navigationController = nil; + }]; + + return; + }); + }]; +} + + +- (NSURL*)getURLForWebLogin +{ + // + // Endpoint + // + NSString *endPoint = [MASConfiguration currentConfiguration].authorizationEndpointPath; + + // + // Headers + // + MASIMutableOrderedDictionary *headerInfo = [MASIMutableOrderedDictionary new]; + + // + // Parameters + // + MASIMutableOrderedDictionary *parameterInfo = [MASIMutableOrderedDictionary new]; + + // ClientId + parameterInfo[MASClientKeyRequestResponseKey] = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyClientId]; + + // RedirectUri + parameterInfo[MASRedirectUriRequestResponseKey] = [[MASApplication currentApplication].redirectUri absoluteString]; + + // Scope + NSString *scope = [MASApplication currentApplication].scopeAsString; + + //Remove register scopes if device is already registered (required for BBA to work) + /* if([[MASDevice currentDevice] isRegistered]) + { + scope = [scope stringByReplacingOccurrencesOfString:@"msso_client_register" withString:@""]; + scope = [scope stringByReplacingOccurrencesOfString:@"msso_register" withString:@""]; + + }*/ + + // + // Workaround - msso_register scope should NOT be used to retrieve authenticationProviders when it is going to be used to "authenticate" + // msso_register scope should only contain for device registration with authorizationCode. + // When the authroizationCode was granted with msso_register scope and used to retrieve the tokens, it will FAIL with unknown error from the server. + // + if (scope && [[MASDevice currentDevice] isRegistered]) + { + scope = [scope replaceStringWithRegexPattern:@"\\bmsso_register\\b" withString:@""]; + } + + // + // If sso is disabled, manually remove msso scope, as it will create id_token with msso scope + // + if (scope && ![MASConfiguration currentConfiguration].ssoEnabled) + { + scope = [scope replaceStringWithRegexPattern:@"\\bmsso\\b" withString:@""]; + } + + parameterInfo[MASScopeRequestResponseKey] = scope; + + // ResponseType + parameterInfo[MASRequestResponseTypeRequestResponseKey] = @"code"; + + // Display + parameterInfo[MASDisplayRequestResponseKey] = @"template"; + + // PKCE Support - generate code verifier + [[MASAccessService sharedService].currentAccessObj generateCodeVerifier]; + + // PKCE Support - generate state + [[MASAccessService sharedService].currentAccessObj generatePKCEState]; + + // Retrieve code verifier + NSString *codeVerifier = [[MASAccessService sharedService].currentAccessObj retrieveCodeVerifier]; + + // Retrieve state + NSString *pkceState = [[MASAccessService sharedService].currentAccessObj retrievePKCEState]; + + if (codeVerifier) + { + // SHA256 the code verifier and encode it with base64url + NSString *codeChallenge = [NSString base64URLWithNSData:[codeVerifier sha256Data]]; + + if (codeChallenge) + { + parameterInfo[MASPKCECodeChallengeRequestResponseKey] = codeChallenge; + // + // code_challenge_method should be S256 if the code challenge is hashed; + // + // Otherwise, make code_challenge = code_verifier, and send code_challenge_method as plan, MASPKCECodeChallengeMethodPlainKey + // + parameterInfo[MASPKCECodeChallengeMethodRequestResponseKey] = MASPKCECodeChallengeMethodSHA256Key; + + parameterInfo[MASPKCEStateRequestResponseKey] = pkceState; + } + } + + //Put the mag-identifier in the url as query parameter for the device to be identified + NSString* magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier]; + //DLog(@"mag-identifier is %@",magIdentifier); + if(magIdentifier && magIdentifier.length > 0) + { + parameterInfo[MASMagIdentifierRequestResponseKey] = magIdentifier; + } + + return [MASGetURLRequest requestForEndpoint:endPoint withParameters:parameterInfo andHeaders:headerInfo requestType:MASRequestResponseTypeUnknown responseType:MASRequestResponseTypeUnknown isPublic:YES].URL; +} + + +#pragma mark - Authorization Response delegate + +-(void)didReceiveAuthorizationCode:(NSString *)code +{ + __block MASBrowserBasedAuthentication *blockSelf = self; + [MASUser loginWithAuthorizationCode:code completion:^(BOOL completed,NSError* error){ + [blockSelf dismissBrowser]; + if(error) + { + DLog(@"error occured %@",error.localizedDescription); + blockSelf.webLoginCallBack(completed, error); + return; + } + + DLog(@"Browser Based Login Successful"); + blockSelf.webLoginCallBack(completed, error); + + + }]; +} + + +-(void)didReceiveError:(NSError *)error +{ + self.webLoginCallBack(NO, error); +} + +#pragma mark - UI + +-(void)dismissBrowser +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIAlertController rootViewController] dismissViewControllerAnimated:YES completion:nil]; + }); +} + +@end From db7ccbb8193c94dac532750d6bacc05d39b62b83 Mon Sep 17 00:00:00 2001 From: Mahendra Nimishakavi Date: Tue, 21 Nov 2017 14:16:40 +0530 Subject: [PATCH 2/8] added code for explicit login in MASUser class --- .../Classes/models/MASBrowserBasedAuthentication.m | 13 +++++++++++-- MASFoundation/Classes/models/MASUser.h | 10 ++++++++++ MASFoundation/Classes/models/MASUser.m | 12 ++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m index a303bf7b..e1826078 100644 --- a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m @@ -15,7 +15,7 @@ #import "MASGetURLRequest.h" #import "MASModelService.h" -@interface MASBrowserBasedAuthentication () +@interface MASBrowserBasedAuthentication () { } @@ -49,7 +49,7 @@ -(void)loadWebLoginTemplate : (MASCompletionErrorBlock)webLoginBlock MASModelService* service = [MASModelService sharedService]; [[MASAuthorizationResponse sharedInstance] setDelegate:self]; __block MASBrowserBasedAuthentication *blockSelf = self; - + __weak __typeof__(self) weakSelf = self; // // Try to register so that all the essential things are set up in that API call and we get a valid URL. If Application is already registered the API returns without doing any work. // @@ -58,6 +58,7 @@ -(void)loadWebLoginTemplate : (MASCompletionErrorBlock)webLoginBlock NSURL* url = [blockSelf getURLForWebLogin]; DLog(@"url used for browser based authentication is %@",url.absoluteString); blockSelf.safariViewController = [[SFSafariViewController alloc] initWithURL:url]; + blockSelf.safariViewController.delegate = weakSelf; __block UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:blockSelf.safariViewController]; dispatch_async(dispatch_get_main_queue(), ^ @@ -179,6 +180,14 @@ - (NSURL*)getURLForWebLogin } +#pragma mark - SafariViewController Delegates + +-(void)safariViewControllerDidFinish:(SFSafariViewController *)controller +{ + self.webLoginCallBack(NO, nil); +} + + #pragma mark - Authorization Response delegate -(void)didReceiveAuthorizationCode:(NSString *)code diff --git a/MASFoundation/Classes/models/MASUser.h b/MASFoundation/Classes/models/MASUser.h index ff7c6507..d79c09a6 100644 --- a/MASFoundation/Classes/models/MASUser.h +++ b/MASFoundation/Classes/models/MASUser.h @@ -261,6 +261,16 @@ +/** + Authenticate a user by launching a Browser which in turn loads a URL (templatized). + + @param completion The MASCompletionErrorBlock block that receives the results. On a successful completion, the user + available via [MASUser currentUser] has been updated with the new information. + */ ++(void)initializeBrowserBasedLoginWithCompletion : (MASCompletionErrorBlock _Nullable)completion; + + + /** * Requesting userInfo for the MASUser object. * This method will retrieve additional information on the MASUser object. diff --git a/MASFoundation/Classes/models/MASUser.m b/MASFoundation/Classes/models/MASUser.m index 9cc8fc67..9c751916 100644 --- a/MASFoundation/Classes/models/MASUser.m +++ b/MASFoundation/Classes/models/MASUser.m @@ -250,6 +250,18 @@ + (void)loginWithAuthCredentials:(MASAuthCredentials *_Nonnull)authCredentials c } ++(void)initializeBrowserBasedLoginWithCompletion : (MASCompletionErrorBlock _Nullable)completion +{ + if ([MASUser currentUser] && [MASUser currentUser].isAuthenticated) + { + if(completion) completion(NO, [NSError errorUserAlreadyAuthenticated]); + + return; + } + + [[MASModelService sharedService] validateCurrentUserSession:completion]; +} + - (void)requestUserInfoWithCompletion:(MASUserResponseErrorBlock)completion { [[MASModelService sharedService] requestUserInfoWithCompletion:completion]; From bb0a2a5c0136a4f9abbdb901c604b6b6d1caa6a1 Mon Sep 17 00:00:00 2001 From: Mahendra Nimishakavi Date: Wed, 22 Nov 2017 19:08:28 +0530 Subject: [PATCH 3/8] added some code to handle the redirection and load the template --- .../_private_/services/MASServiceRegistry.h | 4 +- .../_private_/services/MASServiceRegistry.m | 2 +- .../services/model/MASModelService.m | 4 +- .../services/network/MASNetworkingService.h | 7 +- .../services/network/MASNetworkingService.m | 8 +- .../network/internal/MASURLSessionManager.h | 1 + .../network/internal/MASURLSessionManager.m | 8 ++ .../models/MASBrowserBasedAuthentication.h | 2 +- .../models/MASBrowserBasedAuthentication.m | 88 +++++++++++++++---- 9 files changed, 97 insertions(+), 27 deletions(-) diff --git a/MASFoundation/Classes/_private_/services/MASServiceRegistry.h b/MASFoundation/Classes/_private_/services/MASServiceRegistry.h index 34b5ec54..781e5f37 100644 --- a/MASFoundation/Classes/_private_/services/MASServiceRegistry.h +++ b/MASFoundation/Classes/_private_/services/MASServiceRegistry.h @@ -193,9 +193,9 @@ typedef NS_ENUM(NSInteger, MASRegistryState) * For this method to handle authentication it requires browser based login to be enabled. * @see enableBrowserBasedAuthentication * - * @param bbaLoginBlock The MASCompletionErrorBlock to receive login result. + * @param bbaLoginBlock The MASAuthCredentialsBlock to receive login result. * @return Return YES if handled, NO if not. */ --(BOOL)browserBasedLoginWillHandleAuthentication : (MASCompletionErrorBlock)bbaLoginBlock; +-(BOOL)browserBasedLoginWillHandleAuthentication : (MASAuthCredentialsBlock)bbaLoginBlock; @end diff --git a/MASFoundation/Classes/_private_/services/MASServiceRegistry.m b/MASFoundation/Classes/_private_/services/MASServiceRegistry.m index b0788eeb..5f759f10 100644 --- a/MASFoundation/Classes/_private_/services/MASServiceRegistry.m +++ b/MASFoundation/Classes/_private_/services/MASServiceRegistry.m @@ -935,7 +935,7 @@ - (BOOL)uiServiceWillHandleOTPChannelSelection:(NSArray *)supportedChannels } --(BOOL)browserBasedLoginWillHandleAuthentication : (MASCompletionErrorBlock)bbaLoginBlock +-(BOOL)browserBasedLoginWillHandleAuthentication : (MASAuthCredentialsBlock)bbaLoginBlock { if(![[MASModelService sharedService] browserBasedLogin]) { diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.m b/MASFoundation/Classes/_private_/services/model/MASModelService.m index ce60366d..c4b2ad8e 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.m +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.m @@ -923,7 +923,7 @@ - (void)registerDeviceWithCompletion:(MASCompletionErrorBlock)completion // MASServiceRegistry *serviceRegistry = [MASServiceRegistry sharedRegistry]; - if([serviceRegistry browserBasedLoginWillHandleAuthentication:completion]) + if([serviceRegistry browserBasedLoginWillHandleAuthentication:authCredentialsBlock]) { return; } @@ -1731,7 +1731,7 @@ - (void)loginUsingUserCredentials:(MASCompletionErrorBlock)completion // If the UI handling framework is present and will handle this stop here // MASServiceRegistry *serviceRegistry = [MASServiceRegistry sharedRegistry]; - if([serviceRegistry browserBasedLoginWillHandleAuthentication:completion]) + if([serviceRegistry browserBasedLoginWillHandleAuthentication:authCredentialsBlock]) { return; } diff --git a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h index 6653a47c..ca85efab 100644 --- a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h +++ b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h @@ -9,10 +9,11 @@ // #import "MASService.h" - #import "MASConstantsPrivate.h" + #import "MASAuthValidationOperation.h" +typedef NSURLRequest* (^MASSessionDataTaskHTTPRedirectBlock)(NSURLSession *_Nonnull session, NSURLSessionTask *_Nonnull task, NSURLResponse * _Nonnull response, NSURLRequest *_Nonnull request); @interface MASNetworkingService : MASService @@ -26,6 +27,10 @@ @property (nonatomic, assign, readonly) MASGatewayMonitoringStatus monitoringStatus; +@property (nonatomic) MASSessionDataTaskHTTPRedirectBlock httpRedirectionBlock; + +//@property (nonatomic, copy) MASSessionDataTask1CompletionBlock httpBlock; + /** Constructs, if not exist, the shared operation that validates current session's registration and authentication status diff --git a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.m b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.m index c4415cac..d016e392 100644 --- a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.m +++ b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.m @@ -11,7 +11,6 @@ #import "MASNetworkingService.h" #import "MASAccessService.h" -#import "MASConstantsPrivate.h" #import "MASConfigurationService.h" #import "MASLocationService.h" #import "MASModelService.h" @@ -657,6 +656,7 @@ - (MASSessionDataTaskCompletionBlock)sessionDataTaskCompletionBlockWithEndPoint: } + - (BOOL)isMAGEndpoint:(NSString *)endpoint { BOOL isMAGEndpoint = NO; @@ -1273,6 +1273,11 @@ - (void)httpRequest:(NSString *)httpMethod endPoint:(NSString *)endPoint paramet // // Construct MASSessionDataTaskOperation with request, and completion block to handle any responsive re-authentication or re-registration. // + if(self.httpRedirectionBlock) + { + [_sessionManager setSessionDidReceiveHTTPRedirectBlock:self.httpRedirectionBlock]; + } + MASSessionDataTaskOperation *operation = [_sessionManager dataOperationWithRequest:request completionHandler:[self sessionDataTaskCompletionBlockWithEndPoint:endPoint parameters:parameterInfo @@ -1283,6 +1288,7 @@ - (void)httpRequest:(NSString *)httpMethod endPoint:(NSString *)endPoint paramet isPublic:isPublic completionBlock:blockCompletion]]; + if (![self isMAGEndpoint:endPoint]) { // diff --git a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h index ad42a64c..a2c67eb5 100644 --- a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h +++ b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h @@ -149,5 +149,6 @@ typedef void (^MASNetworkSessionDidFinishEventsForBackgroundURLSessionBlock)(NSU */ - (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential **credential))block; +-(void)setSessionDidReceiveHTTPRedirectBlock : (NSURLRequest* (^)(NSURLSession *session,NSURLSessionTask *task, NSURLResponse* response,NSURLRequest *request))block; @end diff --git a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.m b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.m index 52f37c81..f35e4139 100644 --- a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.m +++ b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.m @@ -17,6 +17,7 @@ @interface MASURLSessionManager () Date: Thu, 23 Nov 2017 18:35:06 +0530 Subject: [PATCH 4/8] included review comments - filter the redirection only to BBA , made Static properties on MASModelService and fixed other comments. --- MASFoundation/Classes/MAS.m | 2 +- MASFoundation/Classes/MASConstants.h | 4 + .../_private_/categories/NSError+MASPrivate.h | 10 +- .../_private_/categories/NSError+MASPrivate.m | 11 +- .../categories/UIAlertController+MAS.h | 46 ------- .../categories/UIAlertController+MAS.m | 113 ------------------ .../_private_/services/MASServiceRegistry.m | 2 +- .../services/model/MASModelService.h | 4 +- .../services/model/MASModelService.m | 14 +-- .../network/requests/MASGetURLRequest.m | 2 +- .../models/MASBrowserBasedAuthentication.h | 8 +- .../models/MASBrowserBasedAuthentication.m | 74 ++++++------ MASFoundation/Classes/models/MASUser.h | 2 +- MASFoundation/Classes/models/MASUser.m | 8 +- 14 files changed, 82 insertions(+), 218 deletions(-) diff --git a/MASFoundation/Classes/MAS.m b/MASFoundation/Classes/MAS.m index 98787fd9..ef590fcd 100644 --- a/MASFoundation/Classes/MAS.m +++ b/MASFoundation/Classes/MAS.m @@ -94,7 +94,7 @@ + (void)setOTPCredentialsBlock:(MASOTPCredentialsBlock)oneTimePassword +(void)enableBrowserBasedAuthentication:(BOOL)enable { - [[MASModelService sharedService] setBrowserBasedLogin:enable]; + [MASModelService setBrowserBasedAuthentication:enable]; } diff --git a/MASFoundation/Classes/MASConstants.h b/MASFoundation/Classes/MASConstants.h index 2505b83e..bfaa6848 100644 --- a/MASFoundation/Classes/MASConstants.h +++ b/MASFoundation/Classes/MASConstants.h @@ -459,6 +459,10 @@ typedef NS_ENUM(NSInteger, MASFoundationErrorCode) MASFoundationErrorCodeJWTUnexpectedClassType = 170002, MASFoundationErrorCodeJWTSerializationError = 170003, + // + // Browser Based Login + // + MASFoundationErrorCodeBBANotEnabled = 180000, // // SharedStorage // diff --git a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.h b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.h index b20b0bb4..a41079e6 100644 --- a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.h +++ b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.h @@ -644,9 +644,17 @@ /** * Create MASFoundationErrorDomainLocal NSError for MASFoundationErrorCodeProximityLoginInvalidAuthorizeURL. * - * @return REturns an NSError instance with the domain MASFoundationErrorDomainLocal and + * @return Returns an NSError instance with the domain MASFoundationErrorDomainLocal and * error MASFoundationErrorCodeProximityLoginInvalidAuthorizeURL */ + (NSError *)errorProximityLoginInvalidAuthroizeURL; + +/** + * Create MASFoundationErrorDomainLocal NSError for MASFoundationErrorCodeBBANotEnabled. + * + * @return Returns an NSError instance with the domain MASFoundationErrorDomainLocal and + * error MASFoundationErrorCodeBBANotEnabled + */ ++ (NSError *)errorBrowserBasedAuthenticaionNotEnabled; @end diff --git a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m index 51ecb6bc..43e31a42 100644 --- a/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m +++ b/MASFoundation/Classes/_private_/categories/NSError+MASPrivate.m @@ -835,6 +835,11 @@ + (NSError *)errorProximityLoginInvalidAuthroizeURL } ++ (NSError *)errorBrowserBasedAuthenticaionNotEnabled +{ + return [self errorForFoundationCode:MASFoundationErrorCodeBBANotEnabled errorDomain:MASFoundationErrorDomainLocal]; +} + # pragma mark - Foundation Errors Private + (MASFoundationErrorCode)foundationErrorCodeForApiCode:(MASApiErrorCode)apiCode @@ -1107,7 +1112,11 @@ + (NSString *)descriptionForFoundationErrorCode:(MASFoundationErrorCode)errorCod // Shared Storage // case MASFoundationErrorCodeSharedStorageNotNilKey: return @"Data key cannot be nil or empty string."; - + + // + // Browser Based Authentication + // + case MASFoundationErrorCodeBBANotEnabled : return @"MAS Browser Based Authentication is Not Enabled"; // // Default // diff --git a/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h index 7b158d89..ec8de498 100644 --- a/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h +++ b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.h @@ -9,52 +9,6 @@ #import @interface UIAlertController (MAS) -///-------------------------------------- -/// @name Authentication Alerts -///------------------------------------- - -# pragma mark - Authentication Alerts - -/** - * Displays on screen an authentication UIAlertController modally in the currently - * visible UIViewController. - */ -+ (void)popupAuthenticationAlert; - - -/** - * Displays on screen an authentication UIAlertController modally in the selected - * UIViewController modally. - * - * @param viewController The UIViewController in which to present the modal UIAlertController. - */ -+ (void)popupAuthenticationAlertInViewController:(UIViewController *)viewController; - - - -///-------------------------------------- -/// @name Error Alerts -///------------------------------------- - -# pragma mark - Error Alerts - -/** - * Displays on screen an error UIAlertController modally in the currently - * visible UIViewController. - */ -+ (void)popupErrorAlert:(NSError *)error; - - -/** - * Displays on screen an error UIAlertController modally in the selected - * UIViewController modally. - * - * @param error The NSError contents to show in the UIAlertController. - * @param viewController The UIViewController in which to present the modal UIAlertController. - */ -+ (void)popupErrorAlert:(NSError *)error inViewController:(UIViewController *)viewController; - - ///-------------------------------------- /// @name Public diff --git a/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m index a34df9a5..cbd86f3e 100644 --- a/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m +++ b/MASFoundation/Classes/_private_/categories/UIAlertController+MAS.m @@ -9,122 +9,9 @@ #import "UIAlertController+MAS.h" #import "MASUser.h" @implementation UIAlertController (MAS) -# pragma mark - Authentication Alerts - -+ (void)popupAuthenticationAlert -{ - [self popupAuthenticationAlertInViewController:[self rootViewController]]; -} - - -+ (void)popupAuthenticationAlertInViewController:(UIViewController *)viewController -{ - // - // Ensure this is done in the main UI thread. We don't know where the call is coming from - // - dispatch_async(dispatch_get_main_queue(), ^ - { - // - // Create alert controller - // - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Sign In (MASUI)" - message:@"You need to sign in with your user credentials" - preferredStyle:UIAlertControllerStyleAlert]; - - // - // Username text field - // - [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) - { - textField.placeholder = NSLocalizedString(@"username", nil); - }]; - - // - // Password text field - // - [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) - { - textField.placeholder = NSLocalizedString(@"password", nil); - textField.secureTextEntry = YES; - }]; - - // - // OK Action - // - UIAlertAction *okAction = [UIAlertAction - actionWithTitle:NSLocalizedString(@"OK", @"OK action") - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *action) - { - UITextField *usernameTextField = alertController.textFields.firstObject; - UITextField *passwordTextField = alertController.textFields.lastObject; - - // - // Attempt to authenticate - // - [MASUser loginWithUserName:usernameTextField.text password:passwordTextField.text completion:^(BOOL completed, NSError *error) { - - DLog(@"viewController received authentication response completed: %@ or error: %@", - (completed ? @"Yes" : @"No"), [error debugDescription]); - - if(error) - { - [UIAlertController popupErrorAlert:error]; - return; - } - }]; - }]; - - [alertController addAction:okAction]; - - // - // Cancel Action - // - UIAlertAction *cancelAction = [UIAlertAction - actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel action") - style:UIAlertActionStyleDefault - handler:nil]; - - [alertController addAction:cancelAction]; - - [viewController presentViewController:alertController animated:YES completion:nil]; - }); -} - # pragma mark - Error Alert -+ (void)popupErrorAlert:(NSError *)error -{ - [self popupErrorAlert:error inViewController:[self rootViewController]]; -} - - -+ (void)popupErrorAlert:(NSError *)error inViewController:(UIViewController *)viewController -{ - // - // Ensure this is done in the main UI thread. We don't know where the call is coming from - // - dispatch_async(dispatch_get_main_queue(), ^ - { - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Error" - message:[error localizedDescription] - preferredStyle:UIAlertControllerStyleAlert]; - - UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" - style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) - { - [alertController dismissViewControllerAnimated:YES completion:nil]; - }]; - - [alertController addAction:ok]; - - [viewController presentViewController:alertController animated:NO completion:nil]; - }); -} - - + (UIViewController *) presentedViewController:(id)viewController { if ([viewController isKindOfClass:[UINavigationController class]]) diff --git a/MASFoundation/Classes/_private_/services/MASServiceRegistry.m b/MASFoundation/Classes/_private_/services/MASServiceRegistry.m index 5f759f10..d7148fc4 100644 --- a/MASFoundation/Classes/_private_/services/MASServiceRegistry.m +++ b/MASFoundation/Classes/_private_/services/MASServiceRegistry.m @@ -937,7 +937,7 @@ - (BOOL)uiServiceWillHandleOTPChannelSelection:(NSArray *)supportedChannels -(BOOL)browserBasedLoginWillHandleAuthentication : (MASAuthCredentialsBlock)bbaLoginBlock { - if(![[MASModelService sharedService] browserBasedLogin]) + if(![MASModelService browserBasedAuthentication]) { return NO; } diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.h b/MASFoundation/Classes/_private_/services/model/MASModelService.h index 4155579d..f7b6b2bc 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.h +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.h @@ -88,7 +88,7 @@ * @param browserBasedLogin The state of browser based authentication. * If this is set to true, a URL which has a templatized login is launched in a browser and this would disable the Social Login, Proximity Login and also prevents the launch of MASUI. */ --(void)setBrowserBasedLogin : (BOOL)browserBasedLogin; ++(void)setBrowserBasedAuthentication : (BOOL)browserBasedAuthentication; /** @@ -96,7 +96,7 @@ * * @return BOOL value is returned. */ --(BOOL)browserBasedLogin; ++(BOOL)browserBasedAuthentication; ///-------------------------------------- diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.m b/MASFoundation/Classes/_private_/services/model/MASModelService.m index c4b2ad8e..6026fde9 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.m +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.m @@ -29,7 +29,7 @@ @interface MASModelService () @property (nonatomic, strong, readwrite) MASAuthenticationProviders *currentProviders; -@property (nonatomic) BOOL isBrowserBasedLogin; + @end @@ -39,7 +39,7 @@ @implementation MASModelService static MASGrantFlow _grantFlow_ = MASGrantFlowClientCredentials; static MASUserLoginWithUserCredentialsBlock _userLoginBlock_ = nil; static MASUserAuthCredentialsBlock _userAuthCredentialsBlock_ = nil; - +static BOOL _isBrowserBasedAuthentication_; # pragma mark - Properties @@ -72,15 +72,15 @@ - (void)setUserObject:(MASUser *)user } --(void)setBrowserBasedLogin : (BOOL)browserBasedLogin ++(void)setBrowserBasedAuthentication : (BOOL)browserBasedAuthentication { - self.isBrowserBasedLogin = browserBasedLogin; + _isBrowserBasedAuthentication_ = browserBasedAuthentication; } --(BOOL)browserBasedLogin ++(BOOL)browserBasedAuthentication { - return self.isBrowserBasedLogin; + return _isBrowserBasedAuthentication_; } @@ -380,7 +380,7 @@ - (void)retrieveAuthenticationProviders:(MASObjectResponseErrorBlock)completion // // If the user was already authenticated, we don't have to retrieve the authentication provider // - if (([MASApplication currentApplication].isAuthenticated && [MASApplication currentApplication].authenticationStatus == MASAuthenticationStatusLoginWithUser) || [MASAccess currentAccess].isSessionLocked || self.isBrowserBasedLogin) + if (([MASApplication currentApplication].isAuthenticated && [MASApplication currentApplication].authenticationStatus == MASAuthenticationStatusLoginWithUser) || [MASAccess currentAccess].isSessionLocked || _isBrowserBasedAuthentication_) { // diff --git a/MASFoundation/Classes/_private_/services/network/requests/MASGetURLRequest.m b/MASFoundation/Classes/_private_/services/network/requests/MASGetURLRequest.m index 74b1d3fb..f17f61d8 100644 --- a/MASFoundation/Classes/_private_/services/network/requests/MASGetURLRequest.m +++ b/MASFoundation/Classes/_private_/services/network/requests/MASGetURLRequest.m @@ -46,7 +46,7 @@ + (MASGetURLRequest *)requestForEndpoint:(NSString *)endPoint NSURL *url = [NSURL URLWithString:endPointWithQueryParameters relativeToURL:[MASConfiguration currentConfiguration].gatewayUrl]; NSAssert(url, @"URL cannot be nil"); - + NSLog(@"url in sdk is %@",url.absoluteString); // // Create the request // diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h index 2cafa95f..0994c69b 100644 --- a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h @@ -2,8 +2,10 @@ // MASBrowserBasedAuthentication.h // MASFoundation // -// Created by nimma01 on 20/11/17. -// Copyright © 2017 CA Technologies. All rights reserved. +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. // #import @@ -29,6 +31,6 @@ * * @param webLoginBlock completion MASCompletionErrorBlock that receives the results. */ --(void)loadWebLoginTemplate : (MASAuthCredentialsBlock)webLoginBlock; +-(void)loadWebLoginTemplate:(MASAuthCredentialsBlock)webLoginBlock; @end diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m index 891bb8bc..1eca7f30 100644 --- a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m @@ -2,8 +2,10 @@ // MASBrowserBasedAuthentication.m // MASFoundation // -// Created by nimma01 on 20/11/17. -// Copyright © 2017 CA Technologies. All rights reserved. +// Copyright (c) 2017 CA. All rights reserved. +// +// This software may be modified and distributed under the terms +// of the MIT license. See the LICENSE file for details. // #import "MASBrowserBasedAuthentication.h" @@ -43,7 +45,7 @@ + (instancetype)sharedInstance } --(void)loadWebLoginTemplate : (MASAuthCredentialsBlock)webLoginBlock +-(void)loadWebLoginTemplate:(MASAuthCredentialsBlock)webLoginBlock { self.webLoginCallBack = webLoginBlock; MASModelService* service = [MASModelService sharedService]; @@ -54,36 +56,14 @@ -(void)loadWebLoginTemplate : (MASAuthCredentialsBlock)webLoginBlock // Try to register so that all the essential things are set up in that API call and we get a valid URL. If Application is already registered the API returns without doing any work. // [service registerApplication:^(BOOL completed, NSError *error) { - - NSURL* url = [blockSelf getURLForWebLogin]; + [blockSelf getURLForWebLogin]; DLog(@"url used for browser based authentication is %@",url.absoluteString); - /* blockSelf.safariViewController = [[SFSafariViewController alloc] initWithURL:url]; - blockSelf.safariViewController.delegate = weakSelf; - __block UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:blockSelf.safariViewController]; - - dispatch_async(dispatch_get_main_queue(), ^ - { - [UIAlertController rootViewController].modalTransitionStyle = UIModalTransitionStyleCoverVertical; - - [[UIAlertController rootViewController] presentViewController:navigationController animated:YES - completion:^{ - - navigationController = nil; - }]; - - return; - });*/ - }]; + }]; } -- (NSURL*)getURLForWebLogin +- (void)getURLForWebLogin { - // - // Endpoint - // - NSString *endPoint = [MASConfiguration currentConfiguration].authorizationEndpointPath; - // // Headers // @@ -176,42 +156,51 @@ - (NSURL*)getURLForWebLogin parameterInfo[MASMagIdentifierRequestResponseKey] = magIdentifier; } + // + // Endpoint + // + NSString *endPoint = [MASConfiguration currentConfiguration].authorizationEndpointPath; + [[MASNetworkingService sharedService] setHttpRedirectionBlock:[self getRedirectionBlock]]; - [[MASNetworkingService sharedService] getFrom:@"/auth/oauth/v2/authorize" withParameters:parameterInfo andHeaders:headerInfo requestType:MASRequestResponseTypeWwwFormUrlEncoded responseType:MASRequestResponseTypeWwwFormUrlEncoded isPublic:YES completion:^(NSDictionary* response, NSError* error){ + [[MASNetworkingService sharedService] getFrom:endPoint withParameters:parameterInfo andHeaders:headerInfo requestType:MASRequestResponseTypeWwwFormUrlEncoded responseType:MASRequestResponseTypeWwwFormUrlEncoded completion:^(NSDictionary* response, NSError* error){ if(error) { - NSLog(@"error is %@",error.localizedDescription); + DLog(@"error is %@",error.localizedDescription); } - NSLog(@"response is %@",response); + DLog(@"response is %@",response); }]; - - - - return [MASGetURLRequest requestForEndpoint:endPoint withParameters:parameterInfo andHeaders:headerInfo requestType:MASRequestResponseTypeUnknown responseType:MASRequestResponseTypeUnknown isPublic:YES].URL; } -(MASSessionDataTaskHTTPRedirectBlock)getRedirectionBlock { MASSessionDataTaskHTTPRedirectBlock redirectionBlock = ^(NSURLSession *session, NSURLSessionTask *task, NSURLResponse * response, NSURLRequest *request){ NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - if(httpResponse.statusCode == 302) + if(httpResponse.statusCode == 302 && [self isBBARedirection:task.originalRequest]) { - NSLog(@"all headers %@",httpResponse.allHeaderFields); + DLog(@"all headers %@",httpResponse.allHeaderFields); NSString* locationURL = [httpResponse.allHeaderFields objectForKey:@"Location"]; NSURL* redirectURL = [NSURL URLWithString:locationURL]; [task cancel]; [self launchBrowserWithURL:redirectURL]; } - return request; }; return redirectionBlock; } +-(BOOL)isBBARedirection : (NSURLRequest*)request +{ + if([request.URL.absoluteString containsString:[MASConfiguration currentConfiguration].authorizationEndpointPath] && [request.URL.absoluteString containsString:@"display=template"]) + { + return YES; + } + return NO; +} + -(void)launchBrowserWithURL : (NSURL*)templatizedURL { __block MASBrowserBasedAuthentication *blockSelf = self; @@ -239,7 +228,12 @@ -(void)launchBrowserWithURL : (NSURL*)templatizedURL -(void)safariViewControllerDidFinish:(SFSafariViewController *)controller { - //self.webLoginCallBack(NO, nil); + self.webLoginCallBack(nil, YES, ^(BOOL completed, NSError* error){ + if(error) + { + DLog(@"Browser dismissed"); + } + }); } @@ -254,7 +248,7 @@ -(void)didReceiveAuthorizationCode:(NSString *)code { //error } - NSLog(@"successfully logged in"); + DLog(@"successfully logged in"); [self dismissBrowser]; }); } diff --git a/MASFoundation/Classes/models/MASUser.h b/MASFoundation/Classes/models/MASUser.h index d79c09a6..78f5c497 100644 --- a/MASFoundation/Classes/models/MASUser.h +++ b/MASFoundation/Classes/models/MASUser.h @@ -267,7 +267,7 @@ @param completion The MASCompletionErrorBlock block that receives the results. On a successful completion, the user available via [MASUser currentUser] has been updated with the new information. */ -+(void)initializeBrowserBasedLoginWithCompletion : (MASCompletionErrorBlock _Nullable)completion; ++(void)initializeBrowserBasedAuthenticationWithCompletion:(MASCompletionErrorBlock _Nullable)completion; diff --git a/MASFoundation/Classes/models/MASUser.m b/MASFoundation/Classes/models/MASUser.m index 9c751916..34eaded7 100644 --- a/MASFoundation/Classes/models/MASUser.m +++ b/MASFoundation/Classes/models/MASUser.m @@ -250,8 +250,14 @@ + (void)loginWithAuthCredentials:(MASAuthCredentials *_Nonnull)authCredentials c } -+(void)initializeBrowserBasedLoginWithCompletion : (MASCompletionErrorBlock _Nullable)completion ++(void)initializeBrowserBasedAuthenticationWithCompletion:(MASCompletionErrorBlock _Nullable)completion { + if(![MASModelService browserBasedAuthentication]) + { + if(completion) completion(NO, [NSError errorBrowserBasedAuthenticaionNotEnabled]); + return; + } + if ([MASUser currentUser] && [MASUser currentUser].isAuthenticated) { if(completion) completion(NO, [NSError errorUserAlreadyAuthenticated]); From 4e7e1850d0d95c7ea2a6d6e3714d51fbc89a62b8 Mon Sep 17 00:00:00 2001 From: Mahendra Nimishakavi Date: Fri, 24 Nov 2017 14:31:55 +0530 Subject: [PATCH 5/8] saved older redirection block if any and set it back after BBA --- .../Classes/models/MASBrowserBasedAuthentication.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m index 1eca7f30..7a9479af 100644 --- a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m @@ -57,7 +57,7 @@ -(void)loadWebLoginTemplate:(MASAuthCredentialsBlock)webLoginBlock // [service registerApplication:^(BOOL completed, NSError *error) { [blockSelf getURLForWebLogin]; - DLog(@"url used for browser based authentication is %@",url.absoluteString); + //DLog(@"url used for browser based authentication is %@",url.absoluteString); }]; } @@ -161,16 +161,16 @@ - (void)getURLForWebLogin // NSString *endPoint = [MASConfiguration currentConfiguration].authorizationEndpointPath; + MASSessionDataTaskHTTPRedirectBlock oldRedirectionBlock = [[MASNetworkingService sharedService] httpRedirectionBlock]; [[MASNetworkingService sharedService] setHttpRedirectionBlock:[self getRedirectionBlock]]; [[MASNetworkingService sharedService] getFrom:endPoint withParameters:parameterInfo andHeaders:headerInfo requestType:MASRequestResponseTypeWwwFormUrlEncoded responseType:MASRequestResponseTypeWwwFormUrlEncoded completion:^(NSDictionary* response, NSError* error){ if(error) { - DLog(@"error is %@",error.localizedDescription); - + DLog(@"original request to get the url cancelled"); } - - DLog(@"response is %@",response); + [[MASNetworkingService sharedService] setHttpRedirectionBlock:oldRedirectionBlock]; + //DLog(@"response is %@",response); }]; } From 92a60c9d8a7fdcf53b2f3c587619e9794525bd7c Mon Sep 17 00:00:00 2001 From: Mahendra Nimishakavi Date: Fri, 24 Nov 2017 14:39:07 +0530 Subject: [PATCH 6/8] handled error case when authorization code is not received --- .../Classes/models/MASBrowserBasedAuthentication.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m index 7a9479af..e4dcb265 100644 --- a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m @@ -256,7 +256,12 @@ -(void)didReceiveAuthorizationCode:(NSString *)code -(void)didReceiveError:(NSError *)error { - //self.webLoginCallBack(NO, error); + self.webLoginCallBack(nil, YES, ^(BOOL completed, NSError* error){ + if(error) + { + DLog(@"Did not receive Authorization code"); + } + }); } #pragma mark - UI From c48f6c4f1b166739c38bd635127046025b4ec303 Mon Sep 17 00:00:00 2001 From: Mahendra Nimishakavi Date: Fri, 24 Nov 2017 20:20:07 +0530 Subject: [PATCH 7/8] improvements and error handling across --- .../services/model/MASModelService.m | 2 +- .../models/MASBrowserBasedAuthentication.h | 5 ++ .../models/MASBrowserBasedAuthentication.m | 63 +++++++++++-------- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.m b/MASFoundation/Classes/_private_/services/model/MASModelService.m index 6026fde9..71b6213c 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.m +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.m @@ -39,7 +39,7 @@ @implementation MASModelService static MASGrantFlow _grantFlow_ = MASGrantFlowClientCredentials; static MASUserLoginWithUserCredentialsBlock _userLoginBlock_ = nil; static MASUserAuthCredentialsBlock _userAuthCredentialsBlock_ = nil; -static BOOL _isBrowserBasedAuthentication_; +static BOOL _isBrowserBasedAuthentication_ = NO; # pragma mark - Properties diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h index 0994c69b..12d7f7ae 100644 --- a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h @@ -16,6 +16,11 @@ } +///-------------------------------------- +/// @name Public +///-------------------------------------- + +# pragma mark - Browser Based Authentication /** * Retrieve the shared MASBrowserBasedAuthentication singleton. diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m index e4dcb265..99d9f23b 100644 --- a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m @@ -51,13 +51,12 @@ -(void)loadWebLoginTemplate:(MASAuthCredentialsBlock)webLoginBlock MASModelService* service = [MASModelService sharedService]; [[MASAuthorizationResponse sharedInstance] setDelegate:self]; __block MASBrowserBasedAuthentication *blockSelf = self; - __weak __typeof__(self) weakSelf = self; + // // Try to register so that all the essential things are set up in that API call and we get a valid URL. If Application is already registered the API returns without doing any work. // [service registerApplication:^(BOOL completed, NSError *error) { [blockSelf getURLForWebLogin]; - //DLog(@"url used for browser based authentication is %@",url.absoluteString); }]; } @@ -83,14 +82,6 @@ - (void)getURLForWebLogin // Scope NSString *scope = [MASApplication currentApplication].scopeAsString; - //Remove register scopes if device is already registered (required for BBA to work) - /* if([[MASDevice currentDevice] isRegistered]) - { - scope = [scope stringByReplacingOccurrencesOfString:@"msso_client_register" withString:@""]; - scope = [scope stringByReplacingOccurrencesOfString:@"msso_register" withString:@""]; - - }*/ - // // Workaround - msso_register scope should NOT be used to retrieve authenticationProviders when it is going to be used to "authenticate" // msso_register scope should only contain for device registration with authorizationCode. @@ -161,15 +152,24 @@ - (void)getURLForWebLogin // NSString *endPoint = [MASConfiguration currentConfiguration].authorizationEndpointPath; - MASSessionDataTaskHTTPRedirectBlock oldRedirectionBlock = [[MASNetworkingService sharedService] httpRedirectionBlock]; + // + // preserve the redirection block that was set earlier + // + MASSessionDataTaskHTTPRedirectBlock previousRedirectionBlock = [[MASNetworkingService sharedService] httpRedirectionBlock]; [[MASNetworkingService sharedService] setHttpRedirectionBlock:[self getRedirectionBlock]]; + // + // This get request would result in a redirection which contains the actual URL to be loaded into browser and hence this would be canceled after the redirection + // [[MASNetworkingService sharedService] getFrom:endPoint withParameters:parameterInfo andHeaders:headerInfo requestType:MASRequestResponseTypeWwwFormUrlEncoded responseType:MASRequestResponseTypeWwwFormUrlEncoded completion:^(NSDictionary* response, NSError* error){ if(error) { + // + // This error is expected as we cancel the Get request after the redirection + // DLog(@"original request to get the url cancelled"); } - [[MASNetworkingService sharedService] setHttpRedirectionBlock:oldRedirectionBlock]; + [[MASNetworkingService sharedService] setHttpRedirectionBlock:previousRedirectionBlock]; //DLog(@"response is %@",response); }]; } @@ -192,7 +192,7 @@ -(MASSessionDataTaskHTTPRedirectBlock)getRedirectionBlock return redirectionBlock; } --(BOOL)isBBARedirection : (NSURLRequest*)request +-(BOOL)isBBARedirection:(NSURLRequest*)request { if([request.URL.absoluteString containsString:[MASConfiguration currentConfiguration].authorizationEndpointPath] && [request.URL.absoluteString containsString:@"display=template"]) { @@ -201,25 +201,31 @@ -(BOOL)isBBARedirection : (NSURLRequest*)request return NO; } --(void)launchBrowserWithURL : (NSURL*)templatizedURL +-(void)launchBrowserWithURL:(NSURL*)templatizedURL { __block MASBrowserBasedAuthentication *blockSelf = self; __weak __typeof__(self) weakSelf = self; blockSelf.safariViewController = [[SFSafariViewController alloc] initWithURL:templatizedURL]; + + if (@available(iOS 11.0, *)) { + blockSelf.safariViewController.dismissButtonStyle = SFSafariViewControllerDismissButtonStyleCancel; + } else { + // Fallback on earlier versions + } blockSelf.safariViewController.delegate = weakSelf; + __block UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:blockSelf.safariViewController]; - dispatch_async(dispatch_get_main_queue(), ^ - { - [UIAlertController rootViewController].modalTransitionStyle = UIModalTransitionStyleCoverVertical; - - [[UIAlertController rootViewController] presentViewController:navigationController animated:YES - completion:^{ - - navigationController = nil; - }]; - - return; + dispatch_async(dispatch_get_main_queue(), ^{ + [UIAlertController rootViewController].modalTransitionStyle = UIModalTransitionStyleCoverVertical; + + [[UIAlertController rootViewController] presentViewController:navigationController animated:YES + completion:^{ + + navigationController = nil; + }]; + + return; }); } @@ -231,7 +237,7 @@ -(void)safariViewControllerDidFinish:(SFSafariViewController *)controller self.webLoginCallBack(nil, YES, ^(BOOL completed, NSError* error){ if(error) { - DLog(@"Browser dismissed"); + DLog(@"Browser cancel clicked"); } }); } @@ -244,9 +250,12 @@ -(void)didReceiveAuthorizationCode:(NSString *)code MASAuthCredentialsAuthorizationCode *authCredentials = [MASAuthCredentialsAuthorizationCode initWithAuthorizationCode:code]; [[MASNetworkingService sharedService] setHttpRedirectionBlock:nil]; self.webLoginCallBack(authCredentials, NO, ^(BOOL completed, NSError* error){ + // + // In either success or error case dismiss the browser and just log the status. The caller would pass the error state/success back to user. + // if(error) { - //error + DLog(@"successfully logged in"); } DLog(@"successfully logged in"); [self dismissBrowser]; From 6a086c5c23b4bfdc32ddf15b92c037f02b8036ab Mon Sep 17 00:00:00 2001 From: Mahendra Nimishakavi Date: Mon, 27 Nov 2017 12:58:14 +0530 Subject: [PATCH 8/8] Taken care of all the indentation and spacing and complied to code guidelines of MAS --- MASFoundation/Classes/MAS.h | 3 +- MASFoundation/Classes/MAS.m | 2 +- .../services/model/MASModelService.h | 6 +- .../services/model/MASModelService.m | 4 +- .../services/network/MASNetworkingService.h | 4 +- .../network/internal/MASURLSessionManager.h | 9 ++- .../models/MASBrowserBasedAuthentication.h | 13 ++-- .../models/MASBrowserBasedAuthentication.m | 59 ++++++++++--------- 8 files changed, 56 insertions(+), 44 deletions(-) diff --git a/MASFoundation/Classes/MAS.h b/MASFoundation/Classes/MAS.h index 1e10044a..65d8de1c 100644 --- a/MASFoundation/Classes/MAS.h +++ b/MASFoundation/Classes/MAS.h @@ -110,13 +110,14 @@ + (void)setOTPCredentialsBlock:(MASOTPCredentialsBlock _Nullable)oneTimePassword; + /** * Sets Bool indicator of Browser Based Authentication (templatized login) enabled or not for authorization process. * By default, it is disabled. @param enable BOOL value indicating whether Browser Based Authentication is enabled or not. */ -+(void)enableBrowserBasedAuthentication:(BOOL)enable; ++ (void)enableBrowserBasedAuthentication:(BOOL)enable; diff --git a/MASFoundation/Classes/MAS.m b/MASFoundation/Classes/MAS.m index ef590fcd..ddda9014 100644 --- a/MASFoundation/Classes/MAS.m +++ b/MASFoundation/Classes/MAS.m @@ -92,7 +92,7 @@ + (void)setOTPCredentialsBlock:(MASOTPCredentialsBlock)oneTimePassword } -+(void)enableBrowserBasedAuthentication:(BOOL)enable ++ (void)enableBrowserBasedAuthentication:(BOOL)enable { [MASModelService setBrowserBasedAuthentication:enable]; } diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.h b/MASFoundation/Classes/_private_/services/model/MASModelService.h index f7b6b2bc..d2c356cd 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.h +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.h @@ -82,13 +82,15 @@ - (void)setUserObject:(MASUser *)user; + /** * Sets the browser based authentication property. Default is NO. * * @param browserBasedLogin The state of browser based authentication. * If this is set to true, a URL which has a templatized login is launched in a browser and this would disable the Social Login, Proximity Login and also prevents the launch of MASUI. */ -+(void)setBrowserBasedAuthentication : (BOOL)browserBasedAuthentication; ++ (void)setBrowserBasedAuthentication:(BOOL)browserBasedAuthentication; + /** @@ -96,7 +98,7 @@ * * @return BOOL value is returned. */ -+(BOOL)browserBasedAuthentication; ++ (BOOL)browserBasedAuthentication; ///-------------------------------------- diff --git a/MASFoundation/Classes/_private_/services/model/MASModelService.m b/MASFoundation/Classes/_private_/services/model/MASModelService.m index 71b6213c..205ce5e3 100644 --- a/MASFoundation/Classes/_private_/services/model/MASModelService.m +++ b/MASFoundation/Classes/_private_/services/model/MASModelService.m @@ -72,13 +72,13 @@ - (void)setUserObject:(MASUser *)user } -+(void)setBrowserBasedAuthentication : (BOOL)browserBasedAuthentication ++ (void)setBrowserBasedAuthentication : (BOOL)browserBasedAuthentication { _isBrowserBasedAuthentication_ = browserBasedAuthentication; } -+(BOOL)browserBasedAuthentication ++ (BOOL)browserBasedAuthentication { return _isBrowserBasedAuthentication_; } diff --git a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h index ca85efab..69fc55c1 100644 --- a/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h +++ b/MASFoundation/Classes/_private_/services/network/MASNetworkingService.h @@ -27,9 +27,11 @@ typedef NSURLRequest* (^MASSessionDataTaskHTTPRedirectBlock)(NSURLSession *_Nonn @property (nonatomic, assign, readonly) MASGatewayMonitoringStatus monitoringStatus; +/** + Http redirection block. Set this block only if you want to handle the redirection coming from the original NSURLRequest. + */ @property (nonatomic) MASSessionDataTaskHTTPRedirectBlock httpRedirectionBlock; -//@property (nonatomic, copy) MASSessionDataTask1CompletionBlock httpBlock; /** diff --git a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h index a2c67eb5..139d8155 100644 --- a/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h +++ b/MASFoundation/Classes/_private_/services/network/internal/MASURLSessionManager.h @@ -149,6 +149,13 @@ typedef void (^MASNetworkSessionDidFinishEventsForBackgroundURLSessionBlock)(NSU */ - (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential **credential))block; --(void)setSessionDidReceiveHTTPRedirectBlock : (NSURLRequest* (^)(NSURLSession *session,NSURLSessionTask *task, NSURLResponse* response,NSURLRequest *request))block; + + +/** + Set code block of session level redirection for the current NSURLRequest object. + + @param block http redirection code block. + */ +- (void)setSessionDidReceiveHTTPRedirectBlock:(NSURLRequest* (^)(NSURLSession *session,NSURLSessionTask *task, NSURLResponse* response,NSURLRequest *request))block; @end diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h index 12d7f7ae..235634cf 100644 --- a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.h @@ -11,14 +11,11 @@ #import #import "MASConstants.h" +/** + MASBrowserBasedAuthentication class is a helper class to utilize SFSafariViewController to launch a customized login template. + * This class will get the redirection to receive the authorization code to perform login. + */ @interface MASBrowserBasedAuthentication : NSObject -{ - -} - -///-------------------------------------- -/// @name Public -///-------------------------------------- # pragma mark - Browser Based Authentication @@ -36,6 +33,6 @@ * * @param webLoginBlock completion MASCompletionErrorBlock that receives the results. */ --(void)loadWebLoginTemplate:(MASAuthCredentialsBlock)webLoginBlock; +- (void)loadWebLoginTemplate:(MASAuthCredentialsBlock)webLoginBlock; @end diff --git a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m index 99d9f23b..56efa02a 100644 --- a/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m +++ b/MASFoundation/Classes/models/MASBrowserBasedAuthentication.m @@ -8,28 +8,27 @@ // of the MIT license. See the LICENSE file for details. // -#import "MASBrowserBasedAuthentication.h" -#import +#import "MASAccessService.h" #import "MASAuthorizationResponse.h" -#import "UIAlertController+MAS.h" +#import "MASBrowserBasedAuthentication.h" #import "MASConfigurationService.h" -#import "MASAccessService.h" #import "MASGetURLRequest.h" #import "MASModelService.h" +#import "UIAlertController+MAS.h" +#import @interface MASBrowserBasedAuthentication () { } -@property (nonatomic) SFSafariViewController* safariViewController; +@property (nonatomic) SFSafariViewController *safariViewController; @property (nonatomic) MASAuthCredentialsBlock webLoginCallBack; @end @implementation MASBrowserBasedAuthentication - # pragma mark - Shared Service + (instancetype)sharedInstance @@ -141,7 +140,7 @@ - (void)getURLForWebLogin //Put the mag-identifier in the url as query parameter for the device to be identified NSString* magIdentifier = [[MASAccessService sharedService] getAccessValueStringWithStorageKey:MASKeychainStorageKeyMAGIdentifier]; - //DLog(@"mag-identifier is %@",magIdentifier); + if(magIdentifier && magIdentifier.length > 0) { parameterInfo[MASMagIdentifierRequestResponseKey] = magIdentifier; @@ -157,36 +156,37 @@ - (void)getURLForWebLogin // MASSessionDataTaskHTTPRedirectBlock previousRedirectionBlock = [[MASNetworkingService sharedService] httpRedirectionBlock]; [[MASNetworkingService sharedService] setHttpRedirectionBlock:[self getRedirectionBlock]]; + // // This get request would result in a redirection which contains the actual URL to be loaded into browser and hence this would be canceled after the redirection // [[MASNetworkingService sharedService] getFrom:endPoint withParameters:parameterInfo andHeaders:headerInfo requestType:MASRequestResponseTypeWwwFormUrlEncoded responseType:MASRequestResponseTypeWwwFormUrlEncoded completion:^(NSDictionary* response, NSError* error){ - if(error) - { - // - // This error is expected as we cancel the Get request after the redirection - // - DLog(@"original request to get the url cancelled"); - } - [[MASNetworkingService sharedService] setHttpRedirectionBlock:previousRedirectionBlock]; - //DLog(@"response is %@",response); + if(error) + { + // + // This error is expected as we cancel the Get request after the redirection + // + DLog(@"original request to get the url cancelled"); + } + + [[MASNetworkingService sharedService] setHttpRedirectionBlock:previousRedirectionBlock]; }]; } -(MASSessionDataTaskHTTPRedirectBlock)getRedirectionBlock { MASSessionDataTaskHTTPRedirectBlock redirectionBlock = ^(NSURLSession *session, NSURLSessionTask *task, NSURLResponse * response, NSURLRequest *request){ - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - if(httpResponse.statusCode == 302 && [self isBBARedirection:task.originalRequest]) - { - DLog(@"all headers %@",httpResponse.allHeaderFields); - NSString* locationURL = [httpResponse.allHeaderFields objectForKey:@"Location"]; - NSURL* redirectURL = [NSURL URLWithString:locationURL]; - [task cancel]; - [self launchBrowserWithURL:redirectURL]; - } - return request; + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + if(httpResponse.statusCode == 302 && [self isBBARedirection:task.originalRequest]) + { + DLog(@"all headers %@",httpResponse.allHeaderFields); + NSString* locationURL = [httpResponse.allHeaderFields objectForKey:@"Location"]; + NSURL* redirectURL = [NSURL URLWithString:locationURL]; + [task cancel]; + [self launchBrowserWithURL:redirectURL]; + } + return request; }; return redirectionBlock; @@ -198,6 +198,7 @@ -(BOOL)isBBARedirection:(NSURLRequest*)request { return YES; } + return NO; } @@ -209,7 +210,8 @@ -(void)launchBrowserWithURL:(NSURL*)templatizedURL if (@available(iOS 11.0, *)) { blockSelf.safariViewController.dismissButtonStyle = SFSafariViewControllerDismissButtonStyleCancel; - } else { + } + else { // Fallback on earlier versions } blockSelf.safariViewController.delegate = weakSelf; @@ -222,7 +224,7 @@ -(void)launchBrowserWithURL:(NSURL*)templatizedURL [[UIAlertController rootViewController] presentViewController:navigationController animated:YES completion:^{ - navigationController = nil; + navigationController = nil; }]; return; @@ -249,6 +251,7 @@ -(void)didReceiveAuthorizationCode:(NSString *)code { MASAuthCredentialsAuthorizationCode *authCredentials = [MASAuthCredentialsAuthorizationCode initWithAuthorizationCode:code]; [[MASNetworkingService sharedService] setHttpRedirectionBlock:nil]; + self.webLoginCallBack(authCredentials, NO, ^(BOOL completed, NSError* error){ // // In either success or error case dismiss the browser and just log the status. The caller would pass the error state/success back to user.