├── .gitignore ├── AWSCognitoUserPoolsSignIn ├── AWSCognitoUserPoolsSignIn.h ├── AWSCognitoUserPoolsSignIn.modulemap ├── AWSCognitoUserPoolsSignInProvider.h └── AWSCognitoUserPoolsSignInProvider.m ├── AWSFacebookSignIn ├── AWSFacebookSignIn.h ├── AWSFacebookSignIn.modulemap ├── AWSFacebookSignInButton.h ├── AWSFacebookSignInButton.m ├── AWSFacebookSignInProvider.h └── AWSFacebookSignInProvider.m ├── AWSFacebookSignInResources ├── Images.xcassets │ ├── Contents.json │ └── fb-icon.imageset │ │ ├── Contents.json │ │ ├── facebook-icon.png │ │ ├── facebook-icon@2x.png │ │ └── facebook-icon@3x.png └── Info.plist ├── AWSGoogleSignIn ├── AWSGoogleSignIn.h ├── AWSGoogleSignIn.modulemap ├── AWSGoogleSignInButton.h ├── AWSGoogleSignInButton.m ├── AWSGoogleSignInProvider.h └── AWSGoogleSignInProvider.m ├── AWSGoogleSignInResources ├── Images.xcassets │ ├── Contents.json │ └── google-icon.imageset │ │ ├── Contents.json │ │ ├── google-icon.png │ │ ├── google-icon@2x.png │ │ └── google-icon@3x.png └── Info.plist ├── AWSMobileHubAuthorizers ├── AWSAuthorizationManager.h ├── AWSAuthorizationManager.m ├── AWSAuthorizer.h ├── AWSHubspotAuthorizationManager.h ├── AWSHubspotAuthorizationManager.m ├── AWSMSDynamicsAuthorizationManager.h ├── AWSMSDynamicsAuthorizationManager.m ├── AWSMarketoAuthorizationManager.h ├── AWSMarketoAuthorizationManager.m ├── AWSMobileHubAuthorizers.h ├── AWSMobileHubAuthorizers.modulemap ├── AWSQuickbooksAuthorizationManager.h ├── AWSQuickbooksAuthorizationManager.m ├── AWSSalesforceAuthorizationManager.h ├── AWSSalesforceAuthorizationManager.m ├── AWSZendeskAuthorizationManager.h └── AWSZendeskAuthorizationManager.m ├── AWSMobileHubHelper.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── AWSMobileHubHelper.xcworkspace └── contents.xcworkspacedata ├── AWSMobileHubHelper ├── AWSMobileHubHelper.h ├── AWSMobileHubHelper.modulemap ├── Authentication │ ├── AWSIdentityManager.h │ ├── AWSIdentityManager.m │ ├── AWSIdentityProfile.h │ ├── AWSIdentityProfileManager.h │ ├── AWSIdentityProfileManager.m │ ├── AWSSignInButtonView.h │ ├── AWSSignInManager.h │ ├── AWSSignInManager.m │ ├── AWSSignInProvider.h │ └── AWSSignInProviderApplicationIntercept.h ├── CloudLogic │ ├── AWSCloudLogic.h │ └── AWSCloudLogic.m ├── ContentDelivery │ ├── AWSContentManager.h │ └── AWSContentManager.m ├── Push │ ├── AWSPushManager.h │ └── AWSPushManager.m └── UserFiles │ ├── AWSUserFileManager.h │ └── AWSUserFileManager.m ├── AWSSamlSignIn ├── AWSSAMLSignInProvider.h ├── AWSSAMLSignInProvider.m ├── AWSSamlSignIn.h └── AWSSamlSignIn.modulemap ├── License.md ├── Podfile ├── README.md ├── Scripts ├── GenerateAllFrameworks.sh ├── GenerateHelperFramework.sh └── GenerateHelperFrameworkDocs.sh └── aws-ios-mobile-hub-helper.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | .DS_Store 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xcuserstate 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | Pods/ 38 | Podfile.lock 39 | 40 | Documentation/ 41 | builtFramework/ 42 | iOSInjectionProject/ 43 | -------------------------------------------------------------------------------- /AWSCognitoUserPoolsSignIn/AWSCognitoUserPoolsSignIn.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSCognitoUserPoolsSignIn.h 3 | // AWSCognitoUserPoolsSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSCognitoUserPoolsSignInProvider.h" 12 | -------------------------------------------------------------------------------- /AWSCognitoUserPoolsSignIn/AWSCognitoUserPoolsSignIn.modulemap: -------------------------------------------------------------------------------- 1 | framework module AWSCognitoUserPoolsSignIn { 2 | umbrella header "AWSCognitoUserPoolsSignIn.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /AWSCognitoUserPoolsSignIn/AWSCognitoUserPoolsSignInProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSCognitoUserPoolsSignInProvider.h 3 | // AWSCognitoUserPoolsSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | #import 11 | #import 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | FOUNDATION_EXPORT NSString *const AWSCognitoUserPoolsSignInProviderKey; 17 | 18 | @protocol AWSCognitoUserPoolsSignInHandler 19 | 20 | /** 21 | * This method is called when `loginWithSignInProvider` is called by `AWSIdentityManager`. 22 | * This method should handle the input from the user and set the `taskCompletionSource` result required by Cognito Idp SDK. 23 | */ 24 | - (void)handleUserPoolSignInFlowStart; 25 | 26 | @end 27 | 28 | /** 29 | * `AWSCognitoUserPoolsSignInProvider` adopts the `AWSSignInProvider` protocol. 30 | * 31 | * It works with the AWS Cognito User Pools SDK internally. 32 | */ 33 | @interface AWSCognitoUserPoolsSignInProvider : NSObject 34 | 35 | /** 36 | * Registers the cognito pool with specified configuration. The pool object can be accessed by using the `CognitoIdentityUserPoolForKey:` method using `AWSCognitoUserPoolsSignInProviderKey` as the identifier key. 37 | * 38 | * @param cognitoIdentityUserPoolId The Cognito Identity User Pool Id 39 | * @param cognitoIdentityUserPoolAppClientId The Cognito Identity User Pool Client Id 40 | * @param cognitoIdentityUserPoolAppClientSecret The Cognito Identity User Pool Client Secret 41 | * @param region The Cognito Identity User Pool Service Region 42 | */ 43 | + (void)setupUserPoolWithId:(NSString *)cognitoIdentityUserPoolId 44 | cognitoIdentityUserPoolAppClientId:(NSString *)cognitoIdentityUserPoolAppClientId 45 | cognitoIdentityUserPoolAppClientSecret:(NSString *)cognitoIdentityUserPoolAppClientSecret 46 | region:(AWSRegionType)region; 47 | 48 | /** 49 | Fetches the shared instance for AWSCognitoUserPoolsSignInProvider. The method `setupUserPoolWithId:cognitoIdentityUserPoolAppClientId:cognitoIdentityUserPoolAppClientSecret:region` has to be called once before accessing the shared instance. 50 | 51 | @return the single instance of AWSCognitoUserPoolsSignInProvider 52 | */ 53 | + (instancetype)sharedInstance; 54 | 55 | /** 56 | * Set the instance of the class adopting the `AWSCognitoIdentityInteractiveAuthenticationDelegate` protocol of Cognito Idp SDK. 57 | * 58 | * @param interactiveAuthDelegate A class adopting the `AWSCognitoIdentityInteractiveAuthenticationDelegate` protocol 59 | */ 60 | - (void)setInteractiveAuthDelegate:(id)interactiveAuthDelegate; 61 | 62 | /** 63 | * Returns the status of the current user pool user. 64 | * 65 | * @return `YES` if the user is signed in. 66 | */ 67 | - (BOOL)isLoggedIn; 68 | 69 | /** 70 | * Returns the configured underlying user pool client. 71 | * 72 | * @return the configured user pool instance 73 | */ 74 | - (AWSCognitoIdentityUserPool *)getUserPool; 75 | 76 | 77 | @end 78 | 79 | NS_ASSUME_NONNULL_END 80 | -------------------------------------------------------------------------------- /AWSCognitoUserPoolsSignIn/AWSCognitoUserPoolsSignInProvider.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSCognitoUserPoolsSignInProvider.m 3 | // AWSCognitoUserPoolsSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSCognitoUserPoolsSignInProvider.h" 12 | #import 13 | 14 | NSString *const AWSCognitoUserPoolsSignInProviderKey = @"CognitoUserPools"; 15 | 16 | typedef void (^AWSSignInManagerCompletionBlock)(id result, AWSIdentityManagerAuthState authState, NSError *error); 17 | 18 | @interface AWSSignInManager() 19 | 20 | - (void)completeLogin; 21 | 22 | @end 23 | 24 | @interface AWSCognitoUserPoolsSignInProvider() 25 | 26 | @property (strong, nonatomic) UIViewController *signInViewController; 27 | @property (atomic, copy) AWSSignInManagerCompletionBlock completionHandler; 28 | @property (strong, nonatomic) id interactiveAuthenticationDelegate; 29 | 30 | @end 31 | 32 | @implementation AWSCognitoUserPoolsSignInProvider 33 | 34 | static NSString *idpName; 35 | 36 | + (void)setupUserPoolWithId:(NSString *)cognitoIdentityUserPoolId 37 | cognitoIdentityUserPoolAppClientId:(NSString *)cognitoIdentityUserPoolAppClientId 38 | cognitoIdentityUserPoolAppClientSecret:(NSString *)cognitoIdentityUserPoolAppClientSecret 39 | region:(AWSRegionType)region{ 40 | AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:region credentialsProvider:nil]; 41 | AWSCognitoIdentityUserPoolConfiguration *configuration = [[AWSCognitoIdentityUserPoolConfiguration alloc] 42 | initWithClientId:cognitoIdentityUserPoolAppClientId 43 | clientSecret:cognitoIdentityUserPoolAppClientSecret 44 | poolId:cognitoIdentityUserPoolId]; 45 | [AWSCognitoIdentityUserPool registerCognitoIdentityUserPoolWithConfiguration:serviceConfiguration userPoolConfiguration:configuration forKey:AWSCognitoUserPoolsSignInProviderKey]; 46 | 47 | idpName = [[NSString alloc] initWithFormat:@"cognito-idp.%@.amazonaws.com/%@", [cognitoIdentityUserPoolId componentsSeparatedByString:@"_"][0], cognitoIdentityUserPoolId ]; 48 | 49 | } 50 | 51 | + (instancetype)sharedInstance { 52 | if (![AWSCognitoIdentityUserPool CognitoIdentityUserPoolForKey:AWSCognitoUserPoolsSignInProviderKey]) { 53 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 54 | reason:@"User Pool not registered. The method `setupUserPoolWithId:cognitoIdentityUserPoolAppClientId:cognitoIdentityUserPoolAppClientSecret:region` has to be called once before accessing the shared instance." 55 | userInfo:nil]; 56 | return nil; 57 | } 58 | static AWSCognitoUserPoolsSignInProvider *_sharedInstance = nil; 59 | static dispatch_once_t onceToken; 60 | dispatch_once(&onceToken, ^{ 61 | _sharedInstance = [[AWSCognitoUserPoolsSignInProvider alloc] init]; 62 | }); 63 | 64 | return _sharedInstance; 65 | } 66 | 67 | - (AWSCognitoIdentityUserPool *)getUserPool { 68 | return [AWSCognitoIdentityUserPool CognitoIdentityUserPoolForKey:AWSCognitoUserPoolsSignInProviderKey]; 69 | } 70 | 71 | - (void)setViewControllerForUserPoolsSignIn:(UIViewController *)signInViewController { 72 | self.signInViewController = signInViewController; 73 | } 74 | 75 | 76 | #pragma mark - AWSIdentityProvider 77 | 78 | - (NSString *)identityProviderName { 79 | return idpName; 80 | } 81 | 82 | - (AWSTask *)token { 83 | AWSCognitoIdentityUserPool *pool = [self getUserPool]; 84 | return [[[pool currentUser] getSession] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { 85 | return [AWSTask taskWithResult:task.result.idToken.tokenString]; 86 | }]; 87 | } 88 | 89 | - (BOOL)isLoggedIn { 90 | AWSCognitoIdentityUserPool *pool = [self getUserPool]; 91 | return [pool.currentUser isSignedIn]; 92 | } 93 | 94 | - (void)reloadSession { 95 | if ([self isLoggedIn]) { 96 | [self completeLogin]; 97 | } 98 | } 99 | 100 | - (void)completeLogin { 101 | [[AWSSignInManager sharedInstance] completeLogin]; 102 | } 103 | 104 | - (void)setInteractiveAuthDelegate:(id)interactiveAuthDelegate { 105 | self.interactiveAuthenticationDelegate = interactiveAuthDelegate; 106 | [self getUserPool].delegate = interactiveAuthDelegate; 107 | } 108 | 109 | - (void)login:(AWSSignInManagerCompletionBlock) completionHandler { 110 | self.completionHandler = completionHandler; 111 | AWSCognitoIdentityUserPool *pool = [self getUserPool]; 112 | [[pool.getUser getSession] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { 113 | [self completeLogin]; 114 | return nil; 115 | }]; 116 | [self.interactiveAuthenticationDelegate handleUserPoolSignInFlowStart]; 117 | } 118 | 119 | - (void)logout { 120 | AWSCognitoIdentityUserPool *pool = [self getUserPool]; 121 | [pool.currentUser signOut]; 122 | } 123 | 124 | - (BOOL)interceptApplication:(UIApplication *)application 125 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 126 | return YES; 127 | } 128 | 129 | - (BOOL)interceptApplication:(UIApplication *)application 130 | openURL:(NSURL *)url 131 | sourceApplication:(NSString *)sourceApplication 132 | annotation:(id)annotation { 133 | 134 | return YES; 135 | } 136 | 137 | @end 138 | -------------------------------------------------------------------------------- /AWSFacebookSignIn/AWSFacebookSignIn.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSFacebookSignIn.h 3 | // AWSFacebookSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSFacebookSignInProvider.h" 12 | #import "AWSFacebookSignInButton.h" 13 | -------------------------------------------------------------------------------- /AWSFacebookSignIn/AWSFacebookSignIn.modulemap: -------------------------------------------------------------------------------- 1 | framework module AWSFacebookSignIn { 2 | umbrella header "AWSFacebookSignIn.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /AWSFacebookSignIn/AWSFacebookSignInButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSFacebookSignInButton.h 3 | // AWSFacebookSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | #import 13 | #import 14 | #import 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | @interface AWSFacebookSignInButton : UIView 19 | 20 | @property (strong, nonatomic) UILabel *textLabel; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /AWSFacebookSignIn/AWSFacebookSignInButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSFacebookSignInButton.m 3 | // AWSFacebookSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSFacebookSignInButton.h" 12 | #import "AWSFacebookSignInProvider.h" 13 | 14 | #define SPACING 10 15 | #define HIGH_HUGGING_PRIORITY 99 16 | #define LOW_HUGGING_PRIORITY 1 17 | // Facebook Blue color to match the logo 18 | #define FB_BLUE_COLOR [UIColor colorWithRed:60.0/255.0 green:92.0/255.0 blue:149.0 /255.0 alpha:1.0] 19 | 20 | typedef void (^AWSSignInManagerCompletionBlock)(id result, AWSIdentityManagerAuthState authState, NSError *error); 21 | 22 | static NSString *FacebookLogoImageKey = @"fb-icon"; 23 | static NSString *ResourceBundle = @"AWSFacebookSignInResources"; 24 | static NSString *BundleExtension = @"bundle"; 25 | 26 | @interface AWSFacebookSignInButton() 27 | 28 | @property (nonatomic, strong) id signInProvider; 29 | @property (nonatomic, strong) UIButton *facebookButton; 30 | @property (nonatomic, strong) UIStackView *facebookStackView; 31 | @property (nonatomic, strong) UIImageView *facebookLogoImageView; 32 | 33 | @end 34 | 35 | @implementation AWSFacebookSignInButton 36 | 37 | @synthesize delegate; 38 | @synthesize buttonStyle; 39 | 40 | - (id)initWithCoder:(NSCoder*)aDecoder { 41 | 42 | if (self = [super initWithCoder:aDecoder]) { 43 | [self commonInit]; 44 | } 45 | return self; 46 | } 47 | 48 | - (id)initWithFrame:(CGRect)frame { 49 | if (self = [super initWithFrame:frame]) { 50 | [self commonInit]; 51 | } 52 | return self; 53 | } 54 | 55 | - (void)commonInit { 56 | _signInProvider = [AWSFacebookSignInProvider sharedInstance]; 57 | [self initFacebookButton]; 58 | [self setUpButtonEffects]; 59 | [self initStackView]; 60 | [self initLogo]; 61 | [self initLabel]; 62 | } 63 | 64 | - (void)dealloc { 65 | @try { 66 | [self removeObserver:self forKeyPath:@"buttonStyle" context:nil]; 67 | } @catch(id exception) { 68 | // ignore exception 69 | } 70 | } 71 | 72 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 73 | // property set 74 | if ([keyPath isEqualToString:@"buttonStyle"]) { 75 | if (self.facebookButton) { 76 | [self.facebookButton setImage:nil forState:UIControlStateNormal]; 77 | } 78 | if (buttonStyle == AWSSignInButtonStyleLarge) { 79 | [self setupLargeFacebookButton]; 80 | } else { 81 | [self setupSmallFacebookButton]; 82 | } 83 | // refresh views 84 | [self.facebookButton setNeedsDisplay]; 85 | [self setNeedsDisplay]; 86 | } 87 | } 88 | 89 | - (void)initFacebookButton { 90 | _facebookButton = [[UIButton alloc] init]; 91 | [self addObserver:self forKeyPath:@"buttonStyle" options:0 context:nil]; 92 | [self.facebookButton addTarget:self 93 | action:@selector(logInWithProvider:) 94 | forControlEvents:UIControlEventTouchUpInside]; 95 | CGRect buttonFrame = _facebookButton.frame; 96 | buttonFrame.size = CGSizeMake(self.frame.size.width, self.frame.size.height); 97 | self.facebookButton.frame = buttonFrame; 98 | self.facebookButton.contentMode = UIViewContentModeCenter; 99 | [self addSubview:self.facebookButton]; 100 | } 101 | 102 | - (void)initLogo { 103 | UIImage *providerImage = [self getImageFromBundle:FacebookLogoImageKey]; 104 | UIImageView *facebookLogoImageView = [[UIImageView alloc] initWithImage:providerImage]; 105 | facebookLogoImageView.contentMode = UIViewContentModeScaleAspectFit; 106 | facebookLogoImageView.exclusiveTouch = NO; 107 | facebookLogoImageView.userInteractionEnabled = NO; 108 | [self.facebookStackView addArrangedSubview:facebookLogoImageView]; 109 | } 110 | 111 | -(void)initStackView { 112 | _facebookStackView = [[UIStackView alloc] initWithFrame:_facebookButton.frame]; 113 | self.facebookStackView.axis = UILayoutConstraintAxisHorizontal; 114 | self.facebookStackView.distribution = UIStackViewDistributionEqualCentering; 115 | self.facebookStackView.contentMode = UIViewContentModeScaleAspectFit; 116 | self.facebookStackView.alignment = UIStackViewAlignmentCenter; 117 | self.facebookStackView.layoutMargins = UIEdgeInsetsMake(SPACING, SPACING, SPACING, SPACING); 118 | [self.facebookStackView setLayoutMarginsRelativeArrangement:YES]; 119 | [self.facebookStackView setSpacing:SPACING]; 120 | self.facebookStackView.exclusiveTouch = NO; 121 | self.facebookStackView.userInteractionEnabled = NO; 122 | [self.facebookButton addSubview:self.facebookStackView]; 123 | } 124 | 125 | - (void)initLabel { 126 | _textLabel = [[UILabel alloc] init]; 127 | self.textLabel.numberOfLines = 1; 128 | self.textLabel.adjustsFontSizeToFitWidth = YES; 129 | self.textLabel.text = @"Continue with Facebook"; 130 | self.textLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:18]; 131 | self.textLabel.textColor = [UIColor whiteColor]; 132 | self.textLabel.exclusiveTouch = NO; 133 | self.textLabel.userInteractionEnabled = NO; 134 | [self.textLabel setContentHuggingPriority:HIGH_HUGGING_PRIORITY forAxis:UILayoutConstraintAxisHorizontal]; 135 | } 136 | 137 | - (void)setUpButtonEffects { 138 | // Facebook Icon Blue Color as background color 139 | UIColor *fbBackGroundColor = FB_BLUE_COLOR; 140 | [self.facebookButton setBackgroundColor: fbBackGroundColor]; 141 | self.facebookButton.layer.cornerRadius = 4.0f; 142 | self.facebookButton.layer.borderWidth = 0.1f; 143 | self.facebookButton.layer.borderColor = [[UIColor grayColor] CGColor]; 144 | self.facebookButton.layer.shadowColor = [[UIColor lightGrayColor] CGColor]; 145 | self.facebookButton.layer.shadowOffset = CGSizeMake(0, 2.0f); 146 | self.facebookButton.layer.shadowOpacity = 0.5f; 147 | self.facebookButton.layer.shadowRadius = 0.0f; 148 | self.facebookButton.layer.masksToBounds = NO; 149 | } 150 | 151 | - (void)setupSmallFacebookButton { 152 | [self.textLabel removeFromSuperview]; 153 | self.facebookStackView.distribution = UIStackViewDistributionEqualCentering; 154 | } 155 | 156 | - (void)setupLargeFacebookButton { 157 | self.facebookStackView.distribution = UIStackViewDistributionFill; 158 | [self.facebookLogoImageView setContentHuggingPriority:LOW_HUGGING_PRIORITY forAxis:UILayoutConstraintAxisHorizontal]; 159 | [self.facebookStackView addArrangedSubview:self.textLabel]; 160 | } 161 | 162 | - (UIImage *)getImageFromBundle:(NSString *)imageName { 163 | NSBundle *currentBundle = [NSBundle bundleForClass:[self class]]; 164 | NSURL *bundleUrl = [currentBundle URLForResource:ResourceBundle withExtension:BundleExtension]; 165 | NSBundle *imageBundle = [NSBundle bundleWithURL:bundleUrl]; 166 | return [UIImage imageNamed:imageName 167 | inBundle:imageBundle 168 | compatibleWithTraitCollection:nil]; 169 | } 170 | 171 | - (void)setSignInProvider:(id)signInProvider { 172 | self.signInProvider = signInProvider; 173 | } 174 | 175 | - (void)logInWithProvider:(id)sender { 176 | 177 | [[AWSSignInManager sharedInstance] loginWithSignInProviderKey:[self.signInProvider identityProviderName] 178 | completionHandler:^(id result, AWSIdentityManagerAuthState authState, NSError *error) { 179 | [self.delegate onLoginWithSignInProvider:self.signInProvider 180 | result:result 181 | authState:authState 182 | error:error]; 183 | }]; 184 | } 185 | 186 | @end 187 | 188 | -------------------------------------------------------------------------------- /AWSFacebookSignIn/AWSFacebookSignInProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSFacebookSignInProvider.h 3 | // AWSFacebookSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | #import 13 | #import 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | /** 18 | * `AWSFacebookSignInProvider` adopts the `AWSSignInProvider` protocol. 19 | * 20 | * It works with the FacebookLoginSDK internally and uses the Facebook App ID specified in the info.plist file. 21 | */ 22 | @interface AWSFacebookSignInProvider : NSObject 23 | 24 | /** 25 | Fetches the singleton instance of AWSFacebookSignInProvider. 26 | 27 | @return the singleton instance of AWSFacebookSignInProvider 28 | */ 29 | + (instancetype)sharedInstance; 30 | 31 | /** 32 | Sets the login behavior of the Facebook SignIn SDK. 33 | Choices are listed in enum FBSDKLoginBehavior. 34 | Default behaviors for iOS: 35 | 9+ SFSafariViewController used. 36 | 8 WebViewController used. 37 | @loginBehavior a FBSDKLoginBehavior enum entry 38 | */ 39 | - (void)setLoginBehavior:(NSUInteger)loginBehavior; 40 | 41 | /** 42 | Sets the permissions requested during login. 43 | Default behavior is no permissions are required. 44 | */ 45 | - (void)setPermissions:(NSArray *)permissions; 46 | 47 | /** 48 | Sets the ViewController used for Facebook SignIn. 49 | Defaults to nil and handled by Facebook SDK. 50 | */ 51 | - (void)setViewControllerForFacebookSignIn:(UIViewController *)signInViewController; 52 | 53 | @end 54 | 55 | NS_ASSUME_NONNULL_END 56 | -------------------------------------------------------------------------------- /AWSFacebookSignIn/AWSFacebookSignInProvider.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSFacebookSignInProvider.m 3 | // AWSFacebookSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | #import 13 | #import 14 | #import "AWSFacebookSignInProvider.h" 15 | 16 | static NSTimeInterval const AWSFacebookSignInProviderTokenRefreshBuffer = 10 * 60; 17 | 18 | typedef void (^AWSSignInManagerCompletionBlock)(id result, AWSIdentityManagerAuthState authState, NSError *error); 19 | 20 | @interface AWSSignInManager() 21 | 22 | - (void)completeLogin; 23 | 24 | @end 25 | 26 | @interface AWSFacebookSignInProvider() 27 | 28 | @property (strong, nonatomic) FBSDKLoginManager *facebookLogin; 29 | 30 | @property (assign, nonatomic) FBSDKLoginBehavior savedLoginBehavior; 31 | @property (strong, nonatomic) NSArray *requestedPermissions; 32 | @property (strong, nonatomic) UIViewController *signInViewController; 33 | @property (atomic, copy) AWSSignInManagerCompletionBlock completionHandler; 34 | @property (strong, nonatomic) AWSTaskCompletionSource *taskCompletionSource; 35 | 36 | @end 37 | 38 | @implementation AWSFacebookSignInProvider 39 | 40 | + (instancetype)sharedInstance { 41 | static AWSFacebookSignInProvider *_sharedInstance = nil; 42 | static dispatch_once_t onceToken; 43 | dispatch_once(&onceToken, ^{ 44 | _sharedInstance = [[AWSFacebookSignInProvider alloc] init]; 45 | }); 46 | 47 | return _sharedInstance; 48 | } 49 | 50 | - (instancetype)init { 51 | 52 | if (self = [super init]) { 53 | _requestedPermissions = nil; 54 | _signInViewController = nil; 55 | if (NSClassFromString(@"SFSafariViewController")) { 56 | _savedLoginBehavior = FBSDKLoginBehaviorNative; 57 | } else { 58 | _savedLoginBehavior = FBSDKLoginBehaviorWeb; 59 | } 60 | return self; 61 | } 62 | return nil; 63 | } 64 | 65 | - (void) createFBSDKLoginManager { 66 | self.facebookLogin = [FBSDKLoginManager new]; 67 | self.facebookLogin.loginBehavior = self.savedLoginBehavior; 68 | } 69 | 70 | #pragma mark - MobileHub user interface 71 | 72 | - (void)setLoginBehavior:(NSUInteger)loginBehavior { 73 | // FBSDKLoginBehavior enum values 0 thru 3 74 | // FBSDK v4.13.1 75 | if (loginBehavior > 3) { 76 | [NSException raise:NSInvalidArgumentException 77 | format:@"%@", @"Failed to set Facebook login behavior with provided login behavior."]; 78 | return; 79 | } 80 | 81 | if (self.facebookLogin) { 82 | self.facebookLogin.loginBehavior = loginBehavior; 83 | } else { 84 | self.savedLoginBehavior = loginBehavior; 85 | } 86 | } 87 | 88 | - (void)setPermissions:(NSArray *)requestedPermissions { 89 | self.requestedPermissions = requestedPermissions; 90 | } 91 | 92 | - (void)setViewControllerForFacebookSignIn:(UIViewController *)signInViewController { 93 | self.signInViewController = signInViewController; 94 | } 95 | 96 | #pragma mark - AWSIdentityProvider 97 | 98 | - (NSString *)identityProviderName { 99 | return AWSIdentityProviderFacebook; 100 | } 101 | 102 | - (AWSTask *)token { 103 | FBSDKAccessToken *token = [FBSDKAccessToken currentAccessToken]; 104 | NSString *tokenString = token.tokenString; 105 | NSDate *idTokenExpirationDate = token.expirationDate; 106 | 107 | if (tokenString 108 | // If the cached token expires within 10 min, tries refreshing a token. 109 | && [idTokenExpirationDate compare:[NSDate dateWithTimeIntervalSinceNow:AWSFacebookSignInProviderTokenRefreshBuffer]] == NSOrderedDescending) { 110 | return [AWSTask taskWithResult:tokenString]; 111 | } 112 | 113 | _taskCompletionSource = [AWSTaskCompletionSource taskCompletionSource]; 114 | [FBSDKLoginManager renewSystemCredentials:^(ACAccountCredentialRenewResult result, NSError *error) { 115 | if (result == ACAccountCredentialRenewResultRenewed) { 116 | FBSDKAccessToken *token = [FBSDKAccessToken currentAccessToken]; 117 | NSString *tokenString = token.tokenString; 118 | _taskCompletionSource.result = tokenString; 119 | } else { 120 | _taskCompletionSource.error = error; 121 | } 122 | }]; 123 | return _taskCompletionSource.task; 124 | } 125 | 126 | #pragma mark - 127 | 128 | - (BOOL)isLoggedIn { 129 | return [FBSDKAccessToken currentAccessToken] != nil; 130 | } 131 | 132 | - (void)reloadSession { 133 | if ([FBSDKAccessToken currentAccessToken]) { 134 | [FBSDKAccessToken refreshCurrentAccessToken:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) { 135 | if (error) { 136 | AWSLogError(@"'refreshCurrentAccessToken' failed: %@", error); 137 | } else { 138 | [self completeLogin]; 139 | } 140 | }]; 141 | } 142 | } 143 | 144 | - (void)completeLogin { 145 | [[AWSSignInManager sharedInstance] completeLogin]; 146 | } 147 | 148 | - (void)login:(AWSSignInManagerCompletionBlock) completionHandler { 149 | self.completionHandler = completionHandler; 150 | 151 | if ([FBSDKAccessToken currentAccessToken]) { 152 | [self completeLogin]; 153 | return; 154 | } 155 | 156 | if (!self.facebookLogin) 157 | [self createFBSDKLoginManager]; 158 | 159 | [self.facebookLogin logInWithReadPermissions:self.requestedPermissions 160 | fromViewController:self.signInViewController 161 | handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) { 162 | 163 | // Determine Auth State 164 | AWSIdentityManagerAuthState authState = [AWSSignInManager sharedInstance].authState; 165 | if (error) { 166 | self.completionHandler(result, authState, error); 167 | } else if (result.isCancelled) { 168 | // Login canceled, allow completionhandler to know about it 169 | NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; 170 | userInfo[@"message"] = @"User Cancelled Login"; 171 | NSError *resultError = [NSError errorWithDomain:FBSDKLoginErrorDomain code:FBSDKLoginUnknownErrorCode userInfo:userInfo]; 172 | self.completionHandler(result, authState, resultError); 173 | } else { 174 | [self completeLogin]; 175 | } 176 | }]; 177 | } 178 | 179 | - (void)logout { 180 | if (!self.facebookLogin) { 181 | [self createFBSDKLoginManager]; 182 | } 183 | [self.facebookLogin logOut]; 184 | } 185 | 186 | - (BOOL)interceptApplication:(UIApplication *)application 187 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 188 | return [[FBSDKApplicationDelegate sharedInstance] application:application 189 | didFinishLaunchingWithOptions:launchOptions]; 190 | } 191 | 192 | - (BOOL)interceptApplication:(UIApplication *)application 193 | openURL:(NSURL *)url 194 | sourceApplication:(NSString *)sourceApplication 195 | annotation:(id)annotation { 196 | if ([[FBSDKApplicationDelegate sharedInstance] application:application 197 | openURL:url 198 | sourceApplication:sourceApplication 199 | annotation:annotation]) { 200 | return YES; 201 | } 202 | 203 | return NO; 204 | } 205 | 206 | @end 207 | -------------------------------------------------------------------------------- /AWSFacebookSignInResources/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /AWSFacebookSignInResources/Images.xcassets/fb-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "facebook-icon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "facebook-icon@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "facebook-icon@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /AWSFacebookSignInResources/Images.xcassets/fb-icon.imageset/facebook-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-mobilehub-helper-ios/b32b8f06d993e469d25dbb64aa6ee3496e46c5d9/AWSFacebookSignInResources/Images.xcassets/fb-icon.imageset/facebook-icon.png -------------------------------------------------------------------------------- /AWSFacebookSignInResources/Images.xcassets/fb-icon.imageset/facebook-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-mobilehub-helper-ios/b32b8f06d993e469d25dbb64aa6ee3496e46c5d9/AWSFacebookSignInResources/Images.xcassets/fb-icon.imageset/facebook-icon@2x.png -------------------------------------------------------------------------------- /AWSFacebookSignInResources/Images.xcassets/fb-icon.imageset/facebook-icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-mobilehub-helper-ios/b32b8f06d993e469d25dbb64aa6ee3496e46c5d9/AWSFacebookSignInResources/Images.xcassets/fb-icon.imageset/facebook-icon@3x.png -------------------------------------------------------------------------------- /AWSFacebookSignInResources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | NSHumanReadableCopyright 22 | Copyright © 2017 Amazon Web Services. All rights reserved. 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AWSGoogleSignIn/AWSGoogleSignIn.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSGoogleSignIn.h 3 | // AWSGoogleSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSGoogleSignInProvider.h" 12 | #import "AWSGoogleSignInButton.h" 13 | -------------------------------------------------------------------------------- /AWSGoogleSignIn/AWSGoogleSignIn.modulemap: -------------------------------------------------------------------------------- 1 | framework module AWSGoogleSignIn { 2 | umbrella header "AWSGoogleSignIn.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /AWSGoogleSignIn/AWSGoogleSignInButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSGoogleSignInButton.h 3 | // AWSGoogleSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | 13 | #import 14 | #import 15 | #import 16 | #import 17 | 18 | NS_ASSUME_NONNULL_BEGIN 19 | 20 | @interface AWSGoogleSignInButton : UIView 21 | 22 | @property (strong, nonatomic) UILabel *textLabel; 23 | 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | 29 | 30 | -------------------------------------------------------------------------------- /AWSGoogleSignIn/AWSGoogleSignInButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSGoogleSignInButton.m 3 | // AWSGoogleSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSGoogleSignInButton.h" 12 | #import "AWSGoogleSignInProvider.h" 13 | 14 | #define SPACING 10 15 | #define HIGH_HUGGING_PRIORITY 99 16 | #define LOW_HUGGING_PRIORITY 1 17 | 18 | typedef void (^AWSSignInManagerCompletionBlock)(id result, AWSIdentityManagerAuthState authState, NSError *error); 19 | 20 | static NSString *GoogleLogoImageKey = @"google-icon"; 21 | static NSString *ResourceBundle = @"AWSGoogleSignInResources"; 22 | static NSString *BundleExtension = @"bundle"; 23 | 24 | @interface AWSGoogleSignInButton() 25 | 26 | @property (nonatomic, strong) id signInProvider; 27 | 28 | @property (nonatomic, strong) UIImageView *signInButton; 29 | @property (nonatomic, strong) UIButton *googleButton; 30 | @property (nonatomic, strong) UIStackView *googleStackView; 31 | @property (nonatomic, strong) UIImageView *googleLogoImageView; 32 | 33 | @end 34 | 35 | @implementation AWSGoogleSignInButton 36 | 37 | @synthesize delegate; 38 | @synthesize buttonStyle; 39 | 40 | - (id)initWithCoder:(NSCoder*)aDecoder { 41 | 42 | if (self = [super initWithCoder:aDecoder]) { 43 | [self commonInit]; 44 | } 45 | return self; 46 | } 47 | 48 | - (id)initWithFrame:(CGRect)frame { 49 | if (self = [super initWithFrame:frame]) { 50 | [self commonInit]; 51 | } 52 | return self; 53 | } 54 | 55 | - (void)commonInit { 56 | _signInProvider = [AWSGoogleSignInProvider sharedInstance]; 57 | [self initGoogleButton]; 58 | [self setUpButtonEffects]; 59 | [self initStackView]; 60 | [self initLogo]; 61 | [self initLabel]; 62 | } 63 | 64 | - (void)dealloc { 65 | @try { 66 | [self removeObserver:self forKeyPath:@"buttonStyle" context:nil]; 67 | } @catch(id exception) { 68 | // ignore exception 69 | } 70 | } 71 | 72 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 73 | // property set 74 | if ([keyPath isEqualToString:@"buttonStyle"]) { 75 | if (self.googleButton) { 76 | [self.googleButton setImage:nil forState:UIControlStateNormal]; 77 | } 78 | if (buttonStyle == AWSSignInButtonStyleLarge) { 79 | [self setupLargeGoogleButton]; 80 | } else { 81 | [self setupSmallGoogleButton]; 82 | } 83 | // refresh views 84 | [self.googleButton setNeedsDisplay]; 85 | [self setNeedsDisplay]; 86 | } 87 | } 88 | 89 | - (void)initGoogleButton { 90 | _googleButton = [[UIButton alloc] init]; 91 | [self addObserver:self forKeyPath:@"buttonStyle" options:0 context:nil]; 92 | [self.googleButton addTarget:self 93 | action:@selector(logInWithProvider:) 94 | forControlEvents:UIControlEventTouchUpInside]; 95 | CGRect buttonFrame = self.googleButton.frame; 96 | buttonFrame.size = CGSizeMake(self.frame.size.width, self.frame.size.height); 97 | self.googleButton.frame = buttonFrame; 98 | NSLog(@"Google Frame: %f %f", self.frame.size.width, self.frame.size.height); 99 | NSLog(@"Google Button: %f %f", self.googleButton.frame.size.width, self.googleButton.frame.size.height); 100 | [self addSubview:self.googleButton]; 101 | } 102 | 103 | - (void)initLogo { 104 | UIImage *providerImage = [self getImageFromBundle:GoogleLogoImageKey]; 105 | UIImageView *logoImageView = [[UIImageView alloc] initWithImage:providerImage]; 106 | logoImageView.contentMode = UIViewContentModeScaleAspectFit; 107 | logoImageView.exclusiveTouch = NO; 108 | logoImageView.userInteractionEnabled = NO; 109 | [self.googleStackView addArrangedSubview:logoImageView]; 110 | } 111 | 112 | -(void)initStackView { 113 | _googleStackView = [[UIStackView alloc] initWithFrame:self.googleButton.frame]; 114 | self.googleStackView.axis = UILayoutConstraintAxisHorizontal; 115 | self.googleStackView.distribution = UIStackViewDistributionEqualSpacing; 116 | self.googleStackView.contentMode = UIViewContentModeScaleAspectFit; 117 | self.googleStackView.alignment = UIStackViewAlignmentCenter; 118 | self.googleStackView.layoutMargins = UIEdgeInsetsMake(SPACING, SPACING, SPACING, SPACING); 119 | [self.googleStackView setLayoutMarginsRelativeArrangement:YES]; 120 | [self.googleStackView setSpacing:SPACING]; 121 | self.googleStackView.exclusiveTouch = NO; 122 | self.googleStackView.userInteractionEnabled = NO; 123 | [self.googleButton addSubview:self.googleStackView]; 124 | } 125 | 126 | - (void)initLabel { 127 | _textLabel = [[UILabel alloc] init]; 128 | self.textLabel.numberOfLines = 1; 129 | self.textLabel.adjustsFontSizeToFitWidth = YES; 130 | self.textLabel.text = @"Sign in with Google"; 131 | self.textLabel.font = [UIFont fontWithName:@"Helvetica-Bold" size:18]; 132 | self.textLabel.textColor = [UIColor darkGrayColor]; 133 | self.textLabel.exclusiveTouch = NO; 134 | self.textLabel.userInteractionEnabled = NO; 135 | [self.textLabel setContentHuggingPriority:HIGH_HUGGING_PRIORITY forAxis:UILayoutConstraintAxisHorizontal]; 136 | } 137 | 138 | - (void)setUpButtonEffects { 139 | self.googleButton.backgroundColor = [UIColor whiteColor]; 140 | self.googleButton.layer.cornerRadius = 4.0f; 141 | self.googleButton.layer.borderWidth = 0.1f; 142 | self.googleButton.layer.borderColor = [[UIColor grayColor] CGColor]; 143 | self.googleButton.layer.shadowColor = [[UIColor lightGrayColor] CGColor]; 144 | self.googleButton.layer.shadowOffset = CGSizeMake(0, 2.0f); 145 | self.googleButton.layer.shadowOpacity = 0.5f; 146 | self.googleButton.layer.shadowRadius = 0.0f; 147 | self.googleButton.layer.masksToBounds = NO; 148 | } 149 | 150 | - (void)setupSmallGoogleButton { 151 | self.googleStackView.distribution = UIStackViewDistributionEqualCentering; 152 | [self.textLabel removeFromSuperview]; 153 | } 154 | 155 | - (void)setupLargeGoogleButton { 156 | self.googleStackView.distribution = UIStackViewDistributionFill; 157 | [self.googleLogoImageView setContentHuggingPriority:LOW_HUGGING_PRIORITY forAxis:UILayoutConstraintAxisHorizontal]; 158 | [self.googleStackView addArrangedSubview:self.textLabel]; 159 | } 160 | 161 | 162 | - (UIImage *)getImageFromBundle:(NSString *)imageName { 163 | NSBundle *currentBundle = [NSBundle bundleForClass:[self class]]; 164 | NSURL *bundleUrl = [currentBundle URLForResource:ResourceBundle withExtension:BundleExtension]; 165 | NSBundle *imageBundle = [NSBundle bundleWithURL:bundleUrl]; 166 | return [UIImage imageNamed:imageName 167 | inBundle:imageBundle 168 | compatibleWithTraitCollection:nil]; 169 | } 170 | 171 | - (void)setSignInProvider:(id)signInProvider { 172 | self.signInProvider = signInProvider; 173 | } 174 | 175 | - (void)logInWithProvider:(id)sender { 176 | 177 | [[AWSSignInManager sharedInstance] loginWithSignInProviderKey:[self.signInProvider identityProviderName] 178 | completionHandler:^(id result, AWSIdentityManagerAuthState authState, NSError *error) { 179 | [self.delegate onLoginWithSignInProvider:self.signInProvider 180 | result:result 181 | authState:authState 182 | error:error]; 183 | }]; 184 | } 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /AWSGoogleSignIn/AWSGoogleSignInProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSGoogleSignInProvider.h 3 | // AWSGoogleSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | #import 11 | #import 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | * `AWSGoogleSignInProvider` adopts the `AWSSignInProvider` protocol. 18 | * 19 | * It works with the Google Sign In SDK internally and requires the Google Client ID provided by Google. 20 | */ 21 | @interface AWSGoogleSignInProvider : NSObject 22 | 23 | /** 24 | Fetches the shared instance for AWSGoogleSignInProvider. 25 | 26 | @return the single instance of AWSGoogleSignInProvider 27 | */ 28 | + (instancetype)sharedInstance; 29 | 30 | /** 31 | Sets the scopes required by the app during login. 32 | Defaults are openid and profile. 33 | */ 34 | - (void)setScopes:(NSArray *)scopes; 35 | 36 | /** 37 | Sets the ViewController used for Google SignIn. 38 | Defaults to rootViewController in keyWindow during signin. 39 | */ 40 | - (void)setViewControllerForGoogleSignIn:(UIViewController *)signInViewController; 41 | 42 | @end 43 | 44 | NS_ASSUME_NONNULL_END 45 | -------------------------------------------------------------------------------- /AWSGoogleSignIn/AWSGoogleSignInProvider.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSGoogleSignInProvider.m 3 | // AWSGoogleSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSGoogleSignInProvider.h" 12 | #import 13 | 14 | #import 15 | 16 | static NSString *const AWSGoogleSignInProviderClientScope = @"profile"; 17 | static NSString *const AWSGoogleSignInProviderOIDCScope = @"openid"; 18 | static NSTimeInterval const AWSGoogleSignInProviderTokenRefreshBuffer = 10 * 60; 19 | static int64_t const AWSGoogleSignInProviderTokenRefreshTimeout = 60 * NSEC_PER_SEC; 20 | 21 | typedef void (^AWSSignInManagerCompletionBlock)(id result, AWSIdentityManagerAuthState authState, NSError *error); 22 | 23 | @interface AWSSignInManager() 24 | 25 | - (void)completeLogin; 26 | 27 | @end 28 | 29 | @interface AWSGoogleSignInProvider() 30 | 31 | @property (atomic, strong) AWSTaskCompletionSource *taskCompletionSource; 32 | @property (nonatomic, strong) dispatch_semaphore_t semaphore; 33 | @property (nonatomic, strong) AWSExecutor *executor; 34 | @property (nonatomic, strong) UIViewController *signInViewController; 35 | @property (atomic, copy) AWSSignInManagerCompletionBlock completionHandler; 36 | @property (nonatomic, strong) GIDSignIn *signIn; 37 | 38 | @end 39 | 40 | @implementation AWSGoogleSignInProvider 41 | 42 | static NSString *const AWSInfoIdentityManager = @"IdentityManager"; 43 | static NSString *const AWSInfoGoogleIdententifier = @"Google"; 44 | static NSString *const AWSInfoGoogleClientId = @"ClientId"; 45 | 46 | + (instancetype)sharedInstance { 47 | AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] defaultServiceInfo:AWSInfoIdentityManager]; 48 | NSString *googleClientID = [[serviceInfo.infoDictionary objectForKey:AWSInfoGoogleIdententifier] objectForKey:AWSInfoGoogleClientId]; 49 | 50 | if (!googleClientID) { 51 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 52 | reason:@"Google Client ID is not set correctly in `Info.plist`. You need to set it in `Info.plist` before using." 53 | userInfo:nil]; 54 | } 55 | 56 | static AWSGoogleSignInProvider *_sharedInstance = nil; 57 | static dispatch_once_t onceToken; 58 | dispatch_once(&onceToken, ^{ 59 | _sharedInstance = [[AWSGoogleSignInProvider alloc] initWithGoogleClientID:googleClientID]; 60 | }); 61 | 62 | return _sharedInstance; 63 | } 64 | 65 | - (instancetype)initWithGoogleClientID:(NSString *)googleClientID { 66 | if (self = [super init]) { 67 | _semaphore = dispatch_semaphore_create(0); 68 | 69 | NSOperationQueue *operationQueue = [NSOperationQueue new]; 70 | _executor = [AWSExecutor executorWithOperationQueue:operationQueue]; 71 | 72 | _signInViewController = nil; 73 | 74 | _signIn = [GIDSignIn sharedInstance]; 75 | _signIn.delegate = self; 76 | _signIn.uiDelegate = self; 77 | _signIn.clientID = googleClientID; 78 | _signIn.scopes = @[AWSGoogleSignInProviderClientScope, AWSGoogleSignInProviderOIDCScope]; 79 | } 80 | 81 | return self; 82 | } 83 | 84 | #pragma mark - MobileHub user interface 85 | 86 | - (void)setScopes:(NSArray *)scopes { 87 | _signIn.scopes = scopes; 88 | } 89 | 90 | - (void)setViewControllerForGoogleSignIn:(UIViewController *)signInViewController { 91 | self.signInViewController = signInViewController; 92 | } 93 | 94 | #pragma mark - AWSIdentityProvider 95 | 96 | - (NSString *)identityProviderName { 97 | return AWSIdentityProviderGoogle; 98 | } 99 | 100 | - (AWSTask *)token { 101 | AWSTask *task = [AWSTask taskWithResult:nil]; 102 | return [task continueWithExecutor:self.executor withBlock:^id _Nullable(AWSTask * _Nonnull task) { 103 | 104 | NSString *idToken = _signIn.currentUser.authentication.idToken; 105 | NSDate *idTokenExpirationDate = _signIn.currentUser.authentication.idTokenExpirationDate; 106 | 107 | if (idToken 108 | // If the cached token expires within 10 min, tries refreshing a token. 109 | && [idTokenExpirationDate compare:[NSDate dateWithTimeIntervalSinceNow:AWSGoogleSignInProviderTokenRefreshBuffer]] == NSOrderedDescending) { 110 | return [AWSTask taskWithResult:idToken]; 111 | } 112 | 113 | if (self.taskCompletionSource) { 114 | // Waits up to 60 seconds for the Google SDK to refresh a token. 115 | if (dispatch_semaphore_wait(self.semaphore, dispatch_time(DISPATCH_TIME_NOW, AWSGoogleSignInProviderTokenRefreshTimeout)) != 0) { 116 | NSError *error = [NSError errorWithDomain:AWSCognitoCredentialsProviderHelperErrorDomain 117 | code:AWSCognitoCredentialsProviderHelperErrorTypeTokenRefreshTimeout 118 | userInfo:nil]; 119 | return [AWSTask taskWithError:error]; 120 | } 121 | } 122 | 123 | idToken = _signIn.currentUser.authentication.idToken; 124 | idTokenExpirationDate = _signIn.currentUser.authentication.idTokenExpirationDate; 125 | 126 | if (idToken 127 | // If the cached token expires within 10 min, tries refreshing a token. 128 | && [idTokenExpirationDate compare:[NSDate dateWithTimeIntervalSinceNow:AWSGoogleSignInProviderTokenRefreshBuffer]] == NSOrderedDescending) { 129 | return [AWSTask taskWithResult:idToken]; 130 | } 131 | 132 | // `self.taskCompletionSource` is used to convert the `GIDSignInDelegate` method to a block based method. 133 | // The `token` string or an error object is returned in a block when the delegate method is called later. 134 | // See the `GIDSignInDelegate` section of this file. 135 | self.taskCompletionSource = [AWSTaskCompletionSource taskCompletionSource]; 136 | dispatch_async(dispatch_get_main_queue(), ^{ 137 | [_signIn signInSilently]; 138 | }); 139 | return self.taskCompletionSource.task; 140 | }]; 141 | } 142 | 143 | #pragma mark - 144 | 145 | - (BOOL)isLoggedIn { 146 | return [_signIn hasAuthInKeychain]; 147 | } 148 | 149 | - (void)reloadSession { 150 | if ([self isLoggedIn]) { 151 | [_signIn signInSilently]; 152 | } 153 | } 154 | 155 | - (void)completeLoginWithToken { 156 | [[AWSSignInManager sharedInstance] completeLogin]; 157 | } 158 | 159 | - (void)login:(AWSSignInManagerCompletionBlock)completionHandler { 160 | self.completionHandler = completionHandler; 161 | [_signIn signIn]; 162 | } 163 | 164 | 165 | - (void)logout { 166 | [_signIn disconnect]; 167 | } 168 | 169 | #pragma mark - GIDSignInDelegate 170 | 171 | - (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user withError:(NSError *)error { 172 | 173 | // Determine Auth State 174 | AWSIdentityManagerAuthState authState = [AWSSignInManager sharedInstance].authState; 175 | // `self.taskCompletionSource` is used to return `user.authentication.idToken` or `error` to the `- token` method. 176 | // See the `AWSIdentityProvider` section of this file. 177 | if (error) { 178 | AWSLogError(@"Error: %@", error); 179 | if (self.taskCompletionSource) { 180 | self.taskCompletionSource.error = error; 181 | self.taskCompletionSource = nil; 182 | } 183 | if (self.completionHandler) { 184 | self.completionHandler(nil, authState, error); 185 | } 186 | } else { 187 | if (self.taskCompletionSource) { 188 | self.taskCompletionSource.result = user.authentication.idToken; 189 | self.taskCompletionSource = nil; 190 | } 191 | [self completeLoginWithToken]; 192 | } 193 | 194 | dispatch_semaphore_signal(self.semaphore); 195 | } 196 | 197 | - (void)signIn:(GIDSignIn *)signIn didDisconnectWithUser:(GIDGoogleUser *)user withError:(NSError *)error { 198 | if (error) { 199 | AWSLogError(@"Error: %@", error); 200 | } 201 | } 202 | 203 | #pragma mark - GIDSignInUIDelegate 204 | 205 | - (void)signInWillDispatch:(GIDSignIn *)signIn error:(NSError *)error { 206 | if (error) { 207 | AWSLogError(@"Error: %@", error); 208 | } 209 | } 210 | 211 | - (void)signIn:(GIDSignIn *)signIn 212 | presentViewController:(UIViewController *)viewController { 213 | [self.signInViewController ?: [UIApplication sharedApplication].keyWindow.rootViewController presentViewController:viewController animated:YES completion:nil]; 214 | } 215 | 216 | - (void)signIn:(GIDSignIn *)signIn 217 | dismissViewController:(UIViewController *)viewController { 218 | [viewController dismissViewControllerAnimated:YES completion:nil]; 219 | } 220 | 221 | #pragma mark - Application delegates 222 | 223 | - (BOOL)interceptApplication:(UIApplication *)application 224 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 225 | return YES; 226 | } 227 | 228 | - (BOOL)interceptApplication:(UIApplication *)application 229 | openURL:(NSURL *)url 230 | sourceApplication:(NSString *)sourceApplication 231 | annotation:(id)annotation { 232 | return [_signIn handleURL:url 233 | sourceApplication:sourceApplication 234 | annotation:annotation]; 235 | } 236 | 237 | - (BOOL)application:(UIApplication *)app 238 | openURL:(NSURL *)url 239 | options:(NSDictionary *)options { 240 | return [_signIn handleURL:url 241 | sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey] 242 | annotation:options[UIApplicationOpenURLOptionsAnnotationKey]]; 243 | } 244 | 245 | - (BOOL)application:(UIApplication *)application 246 | openURL:(NSURL *)url 247 | sourceApplication:(NSString *)sourceApplication 248 | annotation:(id)annotation { 249 | return [_signIn handleURL:url 250 | sourceApplication:sourceApplication 251 | annotation:annotation]; 252 | } 253 | 254 | @end 255 | -------------------------------------------------------------------------------- /AWSGoogleSignInResources/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /AWSGoogleSignInResources/Images.xcassets/google-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "google-icon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "google-icon@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "google-icon@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /AWSGoogleSignInResources/Images.xcassets/google-icon.imageset/google-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-mobilehub-helper-ios/b32b8f06d993e469d25dbb64aa6ee3496e46c5d9/AWSGoogleSignInResources/Images.xcassets/google-icon.imageset/google-icon.png -------------------------------------------------------------------------------- /AWSGoogleSignInResources/Images.xcassets/google-icon.imageset/google-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-mobilehub-helper-ios/b32b8f06d993e469d25dbb64aa6ee3496e46c5d9/AWSGoogleSignInResources/Images.xcassets/google-icon.imageset/google-icon@2x.png -------------------------------------------------------------------------------- /AWSGoogleSignInResources/Images.xcassets/google-icon.imageset/google-icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-mobilehub-helper-ios/b32b8f06d993e469d25dbb64aa6ee3496e46c5d9/AWSGoogleSignInResources/Images.xcassets/google-icon.imageset/google-icon@3x.png -------------------------------------------------------------------------------- /AWSGoogleSignInResources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | NSHumanReadableCopyright 22 | Copyright © 2017 Amazon Web Services. All rights reserved. 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSAuthorizationManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSAuthorizationManager.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import 11 | #import 12 | 13 | extern NSString * _Nonnull const AWSAuthorizationManagerErrorDomain; 14 | 15 | typedef NS_ENUM(NSUInteger, AWSAuthorizationManagerError) { 16 | AWSAuthorizationErrorUserCancelledFlow, 17 | AWSAuthorizationErrorConnectionError, 18 | AWSAuthorizationErrorFailedToRetrieveAccessToken, 19 | AWSAuthorizationErrorMissingRequiredParameter, 20 | }; 21 | 22 | @interface AWSAuthorizationManager : NSObject 23 | 24 | /** 25 | * Singleton used to authorize user during OAuth1.0, 2.0, other flows. 26 | * @return the singleton 27 | */ 28 | + (instancetype _Nonnull)sharedInstance; 29 | 30 | /** 31 | * Utility method that constructs form encoded portion of url 32 | * i.e. @{@"grant": @"code", @"client_id": @"abc123"} -> @"grant=code&client_id=abc123&" 33 | * 34 | * @return the string representation of a form 35 | */ 36 | + (NSString * _Nonnull)constructURIWithParameters:(NSDictionary * _Nonnull)params; 37 | 38 | /** 39 | * Utility method that constructs dictionary from simple form encoded url 40 | * i.e. @"grant=code&client_id=abc123" -> @{@"grant": @"code", @"client_id": @"abc123"} 41 | * 42 | * @return the dictionary representation of a url encoded form 43 | */ 44 | + (NSDictionary * _Nonnull)constructParametersWithURI:(NSString * _Nonnull)formString; 45 | 46 | /** 47 | * Starts the authorization flow. Should be called from main thread. 48 | * 49 | * @param authorizeViewController The view controller that user sees right before they should see a login screen. 50 | * @param completionHandler The code that will follow after receiving successful login. Executes BEFORE login screen is dismissed. 51 | */ 52 | - (void)authorizeWithView:(UIViewController * _Nonnull)authorizeViewController completionHandler:(void (^ _Nullable)(id _Nullable result, NSError * _Nullable error)) completionHandler; 53 | 54 | /** 55 | * This method should be placed in the AppDelegate to listen for the redirect URI. 56 | * 57 | * - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation 58 | * 59 | * @param url The url that the authorization flow gives back. 60 | * @return YES if the url matches an expected response, NO if it is not expected. 61 | */ 62 | - (BOOL)handleURL:(NSURL * _Nullable)url; 63 | 64 | /** 65 | * @return the accessToken used for API calls 66 | */ 67 | - (NSString * _Nullable)getAccessToken; 68 | 69 | /** 70 | * Starts the logout flow. Should be called from main thread. 71 | * 72 | * @param logoutViewController The view controller that user sees right before they should see a logout indication. 73 | * @param completionHandler The code that will follow after receiving successful login. Executes BEFORE login screen is dismissed. 74 | */ 75 | - (void)logout:(UIViewController * _Nonnull)logoutViewController completionHandler:(void (^ _Nullable)(id _Nullable result, NSError * _Nullable error)) completionHandler; 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSAuthorizationManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSAuthorizationManager.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSAuthorizationManager.h" 11 | #import 12 | #import 13 | 14 | NSString *const AWSAuthorizationManagerErrorDomain = @"com.amazonaws.AWSAuthorizationManager"; 15 | 16 | typedef void (^AWSCompletionBlock)(id result, NSError *error); 17 | 18 | @interface AWSAuthorizationManager() 19 | 20 | @property (strong, nonatomic) SFSafariViewController *safariVC; 21 | @property (assign, nonatomic) BOOL dismissOnLoad; 22 | 23 | @property (strong, nonatomic) AWSCompletionBlock loginCompletionHandler; 24 | @property (strong, nonatomic) AWSCompletionBlock logoutCompletionHandler; 25 | @property (strong, nonatomic) AWSCompletionBlock refreshCompletionHandler; 26 | 27 | @property (strong, nonatomic) NSString *accessToken; 28 | 29 | @end 30 | 31 | @implementation AWSAuthorizationManager 32 | 33 | + (instancetype)sharedInstance { 34 | static AWSAuthorizationManager *_sharedInstance = nil; 35 | static dispatch_once_t onceToken; 36 | dispatch_once(&onceToken, ^{ 37 | _sharedInstance = [[AWSAuthorizationManager alloc] init]; 38 | }); 39 | 40 | return _sharedInstance; 41 | } 42 | 43 | + (NSString *)constructURIWithParameters:(NSDictionary *)params { 44 | NSMutableString *uri = [[NSMutableString alloc] init]; 45 | 46 | for (id key in params) { 47 | [uri appendString:[NSString stringWithFormat:@"%@=%@&", key, params[key]]]; 48 | } 49 | 50 | return [uri substringToIndex:[uri length] - 1]; 51 | } 52 | 53 | + (NSDictionary *)constructParametersWithURI:(NSString *)formString { 54 | NSMutableDictionary *queryStringDictionary = [[NSMutableDictionary alloc] init]; 55 | NSArray *urlComponents = [formString componentsSeparatedByString:@"&"]; 56 | 57 | for (NSString *keyValuePair in urlComponents) { 58 | NSRange positionOfEqualSign = [keyValuePair rangeOfString:@"="]; 59 | 60 | if (positionOfEqualSign.location == NSNotFound) { 61 | [queryStringDictionary setObject:@"" forKey:keyValuePair]; 62 | continue; 63 | } 64 | 65 | NSString *key = [[keyValuePair substringWithRange:NSMakeRange(0, positionOfEqualSign.location)] stringByRemovingPercentEncoding]; 66 | NSString *value = [[keyValuePair substringFromIndex:positionOfEqualSign.location + positionOfEqualSign.length] stringByRemovingPercentEncoding]; 67 | 68 | [queryStringDictionary setObject:value forKey:key]; 69 | } 70 | 71 | return queryStringDictionary; 72 | } 73 | 74 | - (instancetype)init { 75 | if (self = [super init]) { 76 | _dismissOnLoad = NO; 77 | _accessToken = nil; 78 | return self; 79 | } 80 | return nil; 81 | } 82 | 83 | - (void)authorizeWithView:(UIViewController *)loginViewController completionHandler:(void (^)(id result, NSError *error)) completionHandler { 84 | AWSLogVerbose(@"authorizeWithView called"); 85 | self.loginCompletionHandler = completionHandler; 86 | 87 | if ([[self getAccessToken] length] > 0) { 88 | self.loginCompletionHandler([self getAccessToken], nil); 89 | return; 90 | } 91 | 92 | self.safariVC = [[SFSafariViewController alloc] initWithURL:[self generateAuthURL] entersReaderIfAvailable:NO]; 93 | self.safariVC.delegate = self; 94 | self.dismissOnLoad = NO; 95 | 96 | [loginViewController presentViewController:self.safariVC animated:NO completion:nil]; 97 | } 98 | 99 | - (void)logout:(UIViewController *)logoutViewController completionHandler:(void (^)(id result, NSError *error)) completionHandler { 100 | AWSLogVerbose(@"logout called"); 101 | self.logoutCompletionHandler = completionHandler; 102 | 103 | NSURL *logoutURL = [self generateLogoutURL]; 104 | 105 | [self clearAccessToken]; 106 | 107 | if (logoutURL) { 108 | self.safariVC = [[SFSafariViewController alloc] initWithURL:logoutURL entersReaderIfAvailable:NO]; 109 | self.safariVC.delegate = self; 110 | self.dismissOnLoad = YES; 111 | [logoutViewController presentViewController:self.safariVC animated:NO completion:nil]; 112 | } else { 113 | self.logoutCompletionHandler(@{@"didSucceed" : @YES}, nil); 114 | self.logoutCompletionHandler = nil; 115 | } 116 | } 117 | 118 | - (BOOL)handleURL:(NSURL *)url { 119 | AWSLogVerbose(@"handleURL called"); 120 | if (![self isAcceptedURL:url]) { 121 | return NO; 122 | } 123 | 124 | self.accessToken = [self findAccessCode:url]; 125 | 126 | if ([self.accessToken length] > 0) { 127 | [self completeLoginWithResult:self.accessToken error:nil]; 128 | return YES; 129 | } else if ([self usesImplicitGrant]) { 130 | [self completeLoginWithResult:nil error:nil]; 131 | } 132 | 133 | return YES; 134 | } 135 | 136 | - (void)completeLoginWithResult:(id)result 137 | error:(NSError *)error { 138 | AWSLogVerbose(@"completeLoginWithResult called"); 139 | NSError *surfacedError = result ? nil : (error ?: [NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 140 | code:AWSAuthorizationErrorFailedToRetrieveAccessToken 141 | userInfo:@{@"message": @"Failed to retrieve access token"}]); 142 | if (surfacedError) { 143 | AWSLogError(@"Error: %@", surfacedError); 144 | } 145 | 146 | if (self.loginCompletionHandler) { 147 | self.loginCompletionHandler(result, surfacedError); 148 | self.loginCompletionHandler = nil; 149 | } 150 | 151 | dispatch_async(dispatch_get_main_queue(), ^{ 152 | if (self.safariVC) { 153 | [self.safariVC dismissViewControllerAnimated:YES completion: nil]; 154 | self.safariVC = nil; 155 | } 156 | }); 157 | } 158 | 159 | - (NSString *)getAccessToken { 160 | return self.accessToken; 161 | } 162 | 163 | - (void)clearAccessToken { 164 | self.accessToken = nil; 165 | } 166 | 167 | #pragma mark - Override Custom Methods 168 | 169 | - (BOOL)usesImplicitGrant { 170 | return NO; 171 | } 172 | 173 | - (NSURL *)generateAuthURL { 174 | [NSException raise:@"Must override this method" format:@"Override this method to generate authorization URL."]; 175 | return [NSURL URLWithString:@"Override this method to generate authorization URL"]; 176 | } 177 | 178 | - (NSString *)findAccessCode:(NSURL *)url { 179 | [NSException raise:@"Must override this method" format:@"Override this method to find access code in URL."]; 180 | return @"Override this method to find access code in URL."; 181 | } 182 | 183 | - (BOOL)isAcceptedURL:(NSURL *)url { 184 | [NSException raise:@"Must override this method" format:@"Override this method to determine if URL is expected."]; 185 | return NO; 186 | } 187 | 188 | - (NSURL *)generateLogoutURL { 189 | [NSException raise:@"Must override this method" format:@"Override this method to generate logout URL."]; 190 | return [NSURL URLWithString:@"Override this method to generate logout URL."]; 191 | } 192 | 193 | #pragma mark - SFSafariViewControllerDelegate 194 | 195 | -(void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully { 196 | // Load finished 197 | if (self.dismissOnLoad) { 198 | self.logoutCompletionHandler(@{@"didSucceed" : @YES}, nil); 199 | self.logoutCompletionHandler = nil; 200 | [controller dismissViewControllerAnimated:true completion: nil]; 201 | } 202 | } 203 | 204 | -(void)safariViewControllerDidFinish:(SFSafariViewController *)controller { 205 | if (self.dismissOnLoad && self.logoutCompletionHandler) { 206 | self.logoutCompletionHandler(@{@"didSucceed" : @NO}, [NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 207 | code:AWSAuthorizationErrorUserCancelledFlow 208 | userInfo:@{@"message": @"User login cookies may not have been cleared."}]); 209 | self.logoutCompletionHandler = nil; 210 | } else if (!self.dismissOnLoad && self.loginCompletionHandler) { 211 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 212 | code:AWSAuthorizationErrorUserCancelledFlow 213 | userInfo:@{@"message": @"User cancelled authorization flow."}]]; 214 | } 215 | } 216 | 217 | @end 218 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSAuthorizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSAuthorizer.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | @protocol AWSAuthorizer 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSHubspotAuthorizationManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSHubspotAuthorizationManager.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSAuthorizationManager.h" 11 | 12 | @interface AWSHubspotAuthorizationManager : AWSAuthorizationManager 13 | 14 | /** 15 | * Singleton used to authorize user during OAuth2.0 16 | * @return the singleton 17 | */ 18 | + (instancetype _Nonnull)sharedInstance; 19 | 20 | /** 21 | * Customize the flow. 22 | * 23 | * @param clientID The client ID provided by Hubspot 24 | * @param portalID The portal ID provided by Hubspot 25 | * @param redirectURI The redirect URI that your app has registered 26 | * i.e. https://mysampleapp.amazonaws.com/hubspot/success 27 | */ 28 | - (void)configureWithClientID:(NSString * _Nonnull)clientID 29 | portalID:(NSString * _Nonnull)portalID 30 | redirectURI:(NSString * _Nonnull)redirectURI; 31 | 32 | /** 33 | * Offline Access offline This application can make API requests on behalf of the user when 34 | * the user is offline (not actively using the app). You will receive 35 | * a refresh token when the user authenticates that you can store to 36 | * gain access to a new, valid access token programtically using the 37 | * refresh token method. 38 | * Contacts Read/Write contacts-rw This application reads your contact information, as well as creates 39 | * new contacts, contact lists, and contact properties. It can also 40 | * modify existing contacts, properties, and contact lists. 41 | * Contacts Read-Only contacts-ro This application can read your contact information, as well as 42 | * information about your contact properties and contact lists. 43 | * Blog Read/Write blog-rw This application can read your blog data, including posts and 44 | * comments, as well as create new blog posts and comments. 45 | * Blog Read-Only blog-ro This application can read your blog data, including posts and comments. 46 | * Events Read/Write events-rw This application can read your marketing events, as well as post 47 | * new ones into your HubSpot account. 48 | * Keywords Read/Write keyword-rw This application can read your keyword data, as well as insert new 49 | * ones into your HubSpot account. 50 | * 51 | * @param scope Specify the amount of access the user would like. 52 | * i.e. @"contacts-rw" 53 | * @"contacts-rw+blog-rw" 54 | */ 55 | - (void)setScope:(NSString * _Nonnull)scope; 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSHubspotAuthorizationManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSHubspotAuthorizationManager.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSHubspotAuthorizationManager.h" 11 | #import 12 | 13 | static NSString *const AWSHubspotAuthorizationManagerAuthorizeURLString = @"https://app.hubspot.com/oauth/authorize"; 14 | static NSString *const AWSHubspotAuthorizationManagerAuthenticateURLString = @"https://app.hubspot.com/auth/authenticate"; 15 | 16 | @interface AWSAuthorizationManager() 17 | 18 | - (void)completeLoginWithResult:(id)result 19 | error:(NSError *)error; 20 | - (void)clearAccessToken; 21 | 22 | @end 23 | 24 | @interface AWSHubspotAuthorizationManager() 25 | 26 | @property (strong, nonatomic) NSString *clientID; 27 | @property (strong, nonatomic) NSString *portalID; 28 | @property (strong, nonatomic) NSString *clientSecret; 29 | @property (strong, nonatomic) NSString *redirectURI; 30 | @property (strong, nonatomic) NSString *scope; 31 | 32 | @property (strong, nonatomic) NSDictionary *valuesFromResponse; 33 | 34 | @end 35 | 36 | @implementation AWSHubspotAuthorizationManager 37 | 38 | + (instancetype)sharedInstance { 39 | static AWSHubspotAuthorizationManager *_sharedInstance = nil; 40 | static dispatch_once_t onceToken; 41 | dispatch_once(&onceToken, ^{ 42 | _sharedInstance = [[AWSHubspotAuthorizationManager alloc] init]; 43 | }); 44 | 45 | return _sharedInstance; 46 | } 47 | 48 | - (instancetype)init { 49 | if (self = [super init]) { 50 | NSDictionary *config = [[[AWSInfo defaultAWSInfo].rootInfoDictionary objectForKey:@"SaaS"] objectForKey:@"HubSpot"]; 51 | [self configureWithClientID:[config objectForKey:@"ClientID"] 52 | portalID:[config objectForKey:@"PortalID"] 53 | redirectURI:[config objectForKey:@"RedirectURI"]]; 54 | 55 | return self; 56 | } 57 | return nil; 58 | } 59 | 60 | - (void)configureWithClientID:(NSString *)clientID 61 | portalID:(NSString *)portalID 62 | redirectURI:(NSString *)redirectURI { 63 | self.clientID = clientID; 64 | self.portalID = portalID; 65 | self.redirectURI = redirectURI; 66 | } 67 | 68 | #pragma mark - Override Custom Methods 69 | 70 | - (BOOL)usesImplicitGrant { 71 | return YES; 72 | } 73 | 74 | - (NSURL *)generateAuthURL { 75 | NSMutableString *missingParams = [NSMutableString new]; 76 | 77 | if ([self.clientID length] == 0) { 78 | [missingParams appendString:@"clientID "]; 79 | } 80 | 81 | if ([self.portalID length] == 0) { 82 | [missingParams appendString:@"portalID "]; 83 | } 84 | 85 | if ([self.redirectURI length] == 0) { 86 | [missingParams appendString:@"redirectURI "]; 87 | } 88 | 89 | if ([self.scope length] == 0) { 90 | [missingParams appendString:@"scope "]; 91 | } 92 | 93 | if ([missingParams length] > 0) { 94 | NSString *message = [NSString stringWithFormat:@"Missing parameter(s): %@", missingParams]; 95 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 96 | code:AWSAuthorizationErrorMissingRequiredParameter 97 | userInfo:@{@"message": message}]]; 98 | } 99 | 100 | NSDictionary *params = @{ 101 | @"client_id" : self.clientID, 102 | @"portalId" : self.portalID, 103 | @"redirect_uri" : [self.redirectURI stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]], 104 | @"scope" : [self.scope stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]] 105 | }; 106 | 107 | NSString *urlString = [NSString stringWithFormat:@"%@?%@", AWSHubspotAuthorizationManagerAuthenticateURLString, [AWSAuthorizationManager constructURIWithParameters:params]]; 108 | NSLog(@"generated %@", urlString); 109 | return [NSURL URLWithString:urlString]; 110 | } 111 | 112 | - (BOOL)isAcceptedURL:(NSURL *)url { 113 | return [[url absoluteString] hasPrefix:self.redirectURI]; 114 | } 115 | 116 | - (NSString *)findAccessCode:(NSURL *)url { 117 | NSLog(@"findAccessCode %@", [url absoluteString]); 118 | NSString *prefix = [NSString stringWithFormat:@"%@?", self.redirectURI]; 119 | NSString *formString = [[url absoluteString] stringByReplacingOccurrencesOfString:prefix withString:@""]; 120 | self.valuesFromResponse = [AWSAuthorizationManager constructParametersWithURI:formString]; 121 | return [self.valuesFromResponse objectForKey:@"access_token"]; 122 | } 123 | 124 | // Keep as reference code, when this flow is actually supported from Hubspot 125 | - (void)getAccessTokenUsingAuthorizationCode:(NSString *)authorizationCode { 126 | NSDictionary *params = @{@"grant_type" : @"authorization_code", 127 | @"code" : authorizationCode, 128 | @"client_id" : self.clientID, 129 | @"redirect_uri" : self.redirectURI, 130 | }; 131 | 132 | NSString *post = [AWSAuthorizationManager constructURIWithParameters:params]; 133 | 134 | NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 135 | NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]]; 136 | 137 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 138 | [request setURL:[NSURL URLWithString:@"https://app.hubspot.com/oauth/v1/token"]]; 139 | [request setHTTPMethod:@"POST"]; 140 | [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; 141 | [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; 142 | [request setHTTPBody:postData]; 143 | 144 | __weak AWSHubspotAuthorizationManager *weakSelf = self; 145 | 146 | NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 147 | if (error) { 148 | [weakSelf completeLoginWithResult:nil error:error]; 149 | return; 150 | } 151 | 152 | weakSelf.valuesFromResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 153 | [weakSelf completeLoginWithResult:[self.valuesFromResponse objectForKey:@"access_token"] error:nil]; 154 | }]; 155 | [task resume]; 156 | } 157 | 158 | - (NSURL *)generateLogoutURL { 159 | return nil; 160 | } 161 | 162 | - (void)clearAccessToken { 163 | [super clearAccessToken]; 164 | self.valuesFromResponse = nil; 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSMSDynamicsAuthorizationManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSMSDynamicsAuthorizationManager.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSAuthorizationManager.h" 11 | 12 | @interface AWSMSDynamicsAuthorizationManager : AWSAuthorizationManager 13 | 14 | /** 15 | * Singleton used to authorize user during OAuth2.0 16 | * @return the singleton 17 | */ 18 | + (instancetype _Nonnull)sharedInstance; 19 | 20 | /** 21 | * Customize the flow. 22 | * 23 | * @param clientID The client ID provided by Microsoft Dynamics 24 | * @param redirectURI The redirect URI you provided Microsoft Dynamics 25 | * i.e. https://mysampleapp.amazonaws.com/msdynamics/success 26 | * @param resource The URL of the resource you will access 27 | */ 28 | - (void)configureWithClientID:(NSString * _Nonnull)clientID 29 | redirectURI:(NSString * _Nonnull)redirectURI 30 | resource:(NSString * _Nonnull)resource; 31 | /** 32 | * @param apiVersion The version of Microsoft Dynamics API you are using. 33 | * The default value is "v8.0" 34 | */ 35 | - (void)setAPIVersion:(NSString * _Nonnull)apiVersion; 36 | 37 | /** 38 | * @return The token type. Available after user authorizes app. 39 | * i.e. Bearer 40 | */ 41 | - (NSString * _Nullable)getTokenType; 42 | 43 | /** 44 | * @return The resource you will access in Microsoft Dynamics 45 | * with the API version attached to the end 46 | * i.e. https://emhawsapps.crm.dynamics.com 47 | */ 48 | - (NSString * _Nullable)getResourceURL; 49 | 50 | /** 51 | * @return the accessToken used for API calls 52 | */ 53 | - (NSString * _Nullable)getAccessToken; 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSMSDynamicsAuthorizationManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSMSDynamicsAuthorizationManager.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSMSDynamicsAuthorizationManager.h" 11 | #import 12 | 13 | static NSString *const AWSMSDynamicsAuthorizationManagerAuthorizeURLString = @"https://login.microsoftonline.com/common/oauth2/authorize"; 14 | static NSString *const AWSMSDynamicsAuthorizationManagerTokenURLString = @"https://login.microsoftonline.com/common/oauth2/token"; 15 | static NSString *const AWSMSDynamicsAuthorizationManagerLogoutURLString = @"https://login.microsoftonline.com/common/oauth2/logout"; 16 | 17 | static NSString *const AWSMSDynamicsAuthorizationManagerCodeKey = @"code"; 18 | static NSString *const AWSMSDynamicsAuthorizationManagerAccessTokenKey = @"access_token"; 19 | static NSString *const AWSMSDynamicsAuthorizationManagerTokenTypeKey = @"token_type"; 20 | 21 | typedef void (^AWSCompletionBlock)(id result, NSError *error); 22 | 23 | @interface AWSAuthorizationManager() 24 | 25 | - (void)completeLoginWithResult:(id)result 26 | error:(NSError *)error; 27 | - (void)clearAccessToken; 28 | 29 | @end 30 | 31 | @interface AWSMSDynamicsAuthorizationManager() 32 | 33 | @property (strong, nonatomic) NSString *authorizeURLString; 34 | @property (strong, nonatomic) NSString *clientID; 35 | @property (strong, nonatomic) NSString *redirectURI; 36 | @property (strong, nonatomic) NSString *resource; 37 | @property (strong, nonatomic, setter=setAPIVersion:) NSString *apiVersion; 38 | 39 | @property (strong, nonatomic) NSDictionary *valuesFromResponse; 40 | 41 | @end 42 | 43 | @implementation AWSMSDynamicsAuthorizationManager 44 | 45 | + (instancetype)sharedInstance { 46 | static AWSMSDynamicsAuthorizationManager *_sharedInstance = nil; 47 | static dispatch_once_t onceToken; 48 | dispatch_once(&onceToken, ^{ 49 | _sharedInstance = [[AWSMSDynamicsAuthorizationManager alloc] init]; 50 | }); 51 | 52 | return _sharedInstance; 53 | } 54 | 55 | - (instancetype)init { 56 | if (self = [super init]) { 57 | NSDictionary *config = [[[AWSInfo defaultAWSInfo].rootInfoDictionary objectForKey:@"SaaS"] objectForKey:@"Dynamics"]; 58 | _clientID = [config objectForKey:@"ClientID"]; 59 | _redirectURI = [config objectForKey:@"RedirectURI"]; 60 | _resource = [config objectForKey:@"ResourceURL"]; 61 | _apiVersion = @"v8.0"; 62 | 63 | return self; 64 | } 65 | return nil; 66 | } 67 | 68 | - (void)configureWithClientID:(NSString *)clientID 69 | redirectURI:(NSString *)redirectURI 70 | resource:(NSString *)resource { 71 | self.clientID = clientID; 72 | self.redirectURI = redirectURI; 73 | self.resource = resource; 74 | } 75 | 76 | - (NSString *)getTokenType { 77 | return [self.valuesFromResponse objectForKey:AWSMSDynamicsAuthorizationManagerTokenTypeKey]; 78 | } 79 | 80 | - (NSString *)getAccessToken { 81 | return [self.valuesFromResponse objectForKey:AWSMSDynamicsAuthorizationManagerAccessTokenKey]; 82 | } 83 | 84 | - (NSString *)getResourceURL { 85 | return [NSString stringWithFormat:@"%@/api/data/%@", self.resource, self.apiVersion]; 86 | } 87 | 88 | #pragma mark - Override Custom Methods 89 | 90 | - (BOOL)usesImplicitGrant { 91 | return NO; 92 | } 93 | 94 | - (NSURL *)generateAuthURL { 95 | NSMutableString *missingParams = [NSMutableString new]; 96 | 97 | if ([self.clientID length] == 0) { 98 | [missingParams appendString:@"clientID "]; 99 | } 100 | 101 | if ([self.redirectURI length] == 0) { 102 | [missingParams appendString:@"redirectURI "]; 103 | } 104 | 105 | if ([self.resource length] == 0) { 106 | [missingParams appendString:@"resourceURL "]; 107 | } 108 | 109 | if ([missingParams length] > 0) { 110 | NSString *message = [NSString stringWithFormat:@"Missing parameter(s): %@", missingParams]; 111 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 112 | code:AWSAuthorizationErrorMissingRequiredParameter 113 | userInfo:@{@"message": message}]]; 114 | } 115 | 116 | NSDictionary *params = @{@"client_id" : self.clientID, 117 | @"response_type" : @"code", 118 | @"response_mode" : @"query", 119 | @"resource" : [self.resource stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]], 120 | @"redirect_uri" : [self.redirectURI stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]], 121 | }; 122 | 123 | NSString *urlString = [NSString stringWithFormat:@"%@?%@", AWSMSDynamicsAuthorizationManagerAuthorizeURLString, [AWSAuthorizationManager constructURIWithParameters:params]]; 124 | return [NSURL URLWithString:urlString]; 125 | } 126 | 127 | - (NSString *)findAccessCode:(NSURL *)url { 128 | NSString *urlHeadRemoved = [[url absoluteString] stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"%@?", self.redirectURI] withString:@""]; 129 | NSDictionary *returnedValues = [AWSAuthorizationManager constructParametersWithURI:urlHeadRemoved]; 130 | [self getAccessTokenUsingAuthorizationCode:[returnedValues objectForKey:AWSMSDynamicsAuthorizationManagerCodeKey]]; 131 | return nil; 132 | } 133 | 134 | - (NSString *)getAccessTokenUsingAuthorizationCode:(NSString *)authorizationCode { 135 | NSDictionary *params = @{@"grant_type" : @"authorization_code", 136 | @"code" : authorizationCode, 137 | @"client_id" : self.clientID, 138 | @"redirect_uri" : self.redirectURI, 139 | }; 140 | 141 | NSString *post = [AWSAuthorizationManager constructURIWithParameters:params]; 142 | 143 | NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 144 | NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]]; 145 | 146 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 147 | [request setURL:[NSURL URLWithString:AWSMSDynamicsAuthorizationManagerTokenURLString]]; 148 | [request setHTTPMethod:@"POST"]; 149 | [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; 150 | [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; 151 | [request setHTTPBody:postData]; 152 | 153 | __weak AWSMSDynamicsAuthorizationManager *weakSelf = self; 154 | 155 | NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 156 | if (error) { 157 | [weakSelf completeLoginWithResult:nil error:error]; 158 | return; 159 | } 160 | 161 | weakSelf.valuesFromResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 162 | [weakSelf completeLoginWithResult:[self.valuesFromResponse objectForKey:AWSMSDynamicsAuthorizationManagerAccessTokenKey] error:nil]; 163 | }]; 164 | [task resume]; 165 | 166 | return nil; 167 | } 168 | 169 | - (BOOL)isAcceptedURL:(NSURL *)url { 170 | return [[url absoluteString] hasPrefix:self.redirectURI]; 171 | } 172 | 173 | - (NSURL *)generateLogoutURL { 174 | return [NSURL URLWithString:AWSMSDynamicsAuthorizationManagerLogoutURLString]; 175 | } 176 | 177 | - (void)clearAccessToken { 178 | [super clearAccessToken]; 179 | self.valuesFromResponse = nil; 180 | } 181 | 182 | @end 183 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSMarketoAuthorizationManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSMarketoAuthorizationManager.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSAuthorizationManager.h" 11 | 12 | @interface AWSMarketoAuthorizationManager : AWSAuthorizationManager 13 | 14 | /** 15 | * Singleton used to authorize user for Marketo 16 | * @return the singleton 17 | */ 18 | + (instancetype _Nonnull)sharedInstance; 19 | 20 | /** 21 | * Customize the flow. 22 | * 23 | * @param identityURI Client ID provided by Salesforce. 24 | * @param restApiURI Should be you're bundle ID or universal URL 25 | * i.e. com.amazonaws.mysampleapp://salesforce/success 26 | * https://mysampleapp.amazonaws.com/success 27 | */ 28 | - (void)configureWithIdentityURI:(NSString * _Nonnull)identityURI 29 | restApiURI:(NSString * _Nonnull)restApiURI; 30 | 31 | /** 32 | * @param clientID Specify the Client ID provided by Marketo. 33 | * i.e. @"abc123...-abc123...-..." 34 | */ 35 | - (void)setClientID:(NSString * _Nonnull)clientID; 36 | 37 | /** 38 | * @param clientSecret Specify the Client Secret provided by Marketo. 39 | * i.e. @"aBc123..." 40 | */ 41 | - (void)setClientSecret:(NSString * _Nonnull)clientSecret; 42 | 43 | /** 44 | * @return The access token used for API calls 45 | */ 46 | - (NSString * _Nullable)getAccessToken; 47 | 48 | /** 49 | * @return The identity URI used during authorization and API calls 50 | */ 51 | - (NSString * _Nullable)getIdentityURI; 52 | 53 | /** 54 | * @return The REST API URI used during authorization and API calls 55 | */ 56 | - (NSString * _Nullable)getRestApiURI; 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSMarketoAuthorizationManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSMarketoAuthorizationManager.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSMarketoAuthorizationManager.h" 11 | #import 12 | 13 | static NSString *const AWSMarketoAuthorizationManagerAccessTokenKey = @"access_token"; 14 | static NSString *const AWSMarketoAuthorizationManagerTokenTypeKey = @"token_type"; 15 | 16 | typedef void (^AWSCompletionBlock)(id result, NSError *error); 17 | 18 | @interface AWSAuthorizationManager() 19 | 20 | @property (strong, nonatomic) AWSCompletionBlock loginCompletionHandler; 21 | @property (strong, nonatomic) AWSCompletionBlock logoutCompletionHandler; 22 | @property (strong, nonatomic) AWSCompletionBlock refreshCompletionHandler; 23 | 24 | @property (strong, nonatomic) NSString *accessToken; 25 | 26 | - (void)completeLoginWithResult:(id)result 27 | error:(NSError *)error; 28 | 29 | - (void)clearAccessToken; 30 | 31 | @end 32 | 33 | @interface AWSMarketoAuthorizationManager() 34 | 35 | @property (strong, nonatomic, getter=getIdentityURI) NSString *identityURI; 36 | @property (strong, nonatomic, getter=getRestApiURI) NSString *restApiURI; 37 | @property (strong, nonatomic, setter=setClientID:) NSString *clientID; 38 | @property (strong, nonatomic, setter=setClientSecret:) NSString *clientSecret; 39 | 40 | @property (strong, nonatomic) NSDictionary *valuesFromResponse; 41 | 42 | @end 43 | 44 | @implementation AWSMarketoAuthorizationManager 45 | 46 | + (instancetype)sharedInstance { 47 | static AWSMarketoAuthorizationManager *_sharedInstance = nil; 48 | static dispatch_once_t onceToken; 49 | dispatch_once(&onceToken, ^{ 50 | _sharedInstance = [[AWSMarketoAuthorizationManager alloc] init]; 51 | }); 52 | 53 | return _sharedInstance; 54 | } 55 | 56 | - (instancetype)init { 57 | if (self = [super init]) { 58 | NSDictionary *config = [[[AWSInfo defaultAWSInfo].rootInfoDictionary objectForKey:@"SaaS"] objectForKey:@"Marketo"]; 59 | [self configureWithIdentityURI:[config objectForKey:@"IdentityURI"] 60 | restApiURI:[config objectForKey:@"RestAPIURI"]]; 61 | 62 | return self; 63 | } 64 | return nil; 65 | } 66 | 67 | - (void)configureWithIdentityURI:(NSString *)identityURI 68 | restApiURI:(NSString *)restApiURI { 69 | self.identityURI = identityURI; 70 | self.restApiURI = restApiURI; 71 | } 72 | 73 | #pragma mark - Override Custom Methods 74 | 75 | - (BOOL)usesImplicitGrant { 76 | return YES; 77 | } 78 | 79 | - (NSString *)getAccessToken { 80 | return [self.valuesFromResponse objectForKey:AWSMarketoAuthorizationManagerAccessTokenKey]; 81 | } 82 | 83 | - (NSString *)getTokenType { 84 | return [self.valuesFromResponse objectForKey:AWSMarketoAuthorizationManagerTokenTypeKey]; 85 | } 86 | 87 | - (void)authorizeWithView:(UIViewController *)authorizeViewController 88 | completionHandler:(void (^)(id _Nullable, NSError * _Nullable))completionHandler { 89 | self.loginCompletionHandler = completionHandler; 90 | 91 | if ([[self getTokenType] length] > 0 && [[self getAccessToken] length] > 0) { 92 | [self completeLoginWithResult:[self getAccessToken] error:nil]; 93 | } 94 | 95 | NSMutableString *missingParams = [NSMutableString new]; 96 | 97 | if ([self.identityURI length] == 0) { 98 | [missingParams appendString:@"identityURI "]; 99 | } 100 | 101 | if ([self.restApiURI length] == 0) { 102 | [missingParams appendString:@"restApiURI "]; 103 | } 104 | 105 | if ([self.clientID length] == 0) { 106 | [missingParams appendString:@"clientID "]; 107 | } 108 | 109 | if ([self.clientSecret length] == 0) { 110 | [missingParams appendString:@"clientSecret "]; 111 | } 112 | 113 | if ([missingParams length] > 0) { 114 | NSString *message = [NSString stringWithFormat:@"Missing parameter(s): %@", missingParams]; 115 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 116 | code:AWSAuthorizationErrorMissingRequiredParameter 117 | userInfo:@{@"message": message}]]; 118 | } 119 | 120 | NSString *urlString = [NSString stringWithFormat:@"%@/oauth/token?grant_type=client_credentials&client_id=%@&client_secret=%@", self.identityURI, self.clientID, self.clientSecret]; 121 | NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]]; 122 | 123 | __weak AWSMarketoAuthorizationManager *weakSelf = self; 124 | 125 | [NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { 126 | if (connectionError) { 127 | AWSLogVerbose(@"Error: %@", connectionError.description); 128 | [weakSelf completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 129 | code:AWSAuthorizationErrorConnectionError 130 | userInfo:@{@"connectionError": connectionError}]]; 131 | return; 132 | } 133 | 134 | NSError *parseError; 135 | weakSelf.valuesFromResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError]; 136 | NSString *accessToken = [weakSelf.valuesFromResponse objectForKey:AWSMarketoAuthorizationManagerAccessTokenKey]; 137 | if (accessToken) { 138 | [weakSelf completeLoginWithResult:accessToken error:nil]; 139 | } else { 140 | [weakSelf completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 141 | code:AWSAuthorizationErrorFailedToRetrieveAccessToken 142 | userInfo:@{@"parseError": parseError}]]; 143 | } 144 | 145 | if (data) { 146 | NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 147 | AWSLogVerbose(@"Received response from Marketo: %@", responseString); 148 | } 149 | }]; 150 | } 151 | 152 | - (NSURL *)generateLogoutURL { 153 | return nil; 154 | } 155 | 156 | - (void)clearAccessToken { 157 | [super clearAccessToken]; 158 | 159 | self.valuesFromResponse = nil; 160 | } 161 | 162 | @end 163 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSMobileHubAuthorizers.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSMobileHubAuthorizers.h 3 | // AWSMobileHubAuthorizers 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSAuthorizationManager.h" 12 | #import "AWSAuthorizer.h" 13 | #import "AWSHubspotAuthorizationManager.h" 14 | #import "AWSMarketoAuthorizationManager.h" 15 | #import "AWSMSDynamicsAuthorizationManager.h" 16 | #import "AWSQuickbooksAuthorizationManager.h" 17 | #import "AWSSalesforceAuthorizationManager.h" 18 | #import "AWSZendeskAuthorizationManager.h" 19 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSMobileHubAuthorizers.modulemap: -------------------------------------------------------------------------------- 1 | framework module AWSMobileHubAuthorizers { 2 | umbrella header "AWSMobileHubAuthorizers.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSQuickbooksAuthorizationManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSQuickbooksAuthorizationManager.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSAuthorizationManager.h" 11 | 12 | @interface AWSQuickbooksAuthorizationManager : AWSAuthorizationManager 13 | 14 | /** 15 | * Singleton used to authorize user during OAuth1.0 16 | * @return the singleton 17 | */ 18 | + (instancetype _Nonnull)sharedInstance; 19 | 20 | /** 21 | * Customize the flow. 22 | * 23 | * @param key The API key provided by Quickbooks 24 | * @param redirectURI The redirect URI you provided Zendesk 25 | * i.e. https://mysampleapp.amazonaws.com/zendesk/success 26 | */ 27 | - (void)configureWithAPIKey:(NSString * _Nonnull)key 28 | redirectURI:(NSString * _Nonnull)redirectURI; 29 | 30 | /** 31 | * The secret must be set before attempting to authorize. 32 | * It is recommended that this secret be securely passed to this point. 33 | * 34 | * @param secret The API secret provided by Quickbooks 35 | * i.e. @"abc123" 36 | */ 37 | - (void)setAPISecret:(NSString * _Nonnull)secret; 38 | 39 | /** 40 | * @return The API secret used to authorize 41 | */ 42 | - (NSString * _Nullable)getAPIKey; 43 | 44 | /** 45 | * @return The API secret used to authorize 46 | */ 47 | - (NSString * _Nullable)getAPISecret; 48 | 49 | /** 50 | * @return The access token, available after authorization 51 | */ 52 | - (NSString * _Nullable)getAccessToken; 53 | 54 | /** 55 | * @return The token secret, available after authorization 56 | */ 57 | - (NSString * _Nullable)getAccessTokenSecret; 58 | 59 | /** 60 | * @return The realm ID, available after authorization 61 | */ 62 | - (NSString * _Nullable)getRealmID; 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSQuickbooksAuthorizationManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSQuickbooksAuthorizationManager.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSQuickbooksAuthorizationManager.h" 11 | #import 12 | 13 | #import 14 | #import 15 | 16 | static NSString *const AWSQuickbooksAuthorizationManagerRequestTokenURLString = @"https://oauth.intuit.com/oauth/v1/get_request_token"; 17 | static NSString *const AWSQuickbooksAuthorizationManagerAccessTokenURLString = @"https://oauth.intuit.com/oauth/v1/get_access_token"; 18 | static NSString *const AWSQuickbooksAuthorizationManagerAuthorizationURLString = @"https://appcenter.intuit.com/Connect/Begin"; 19 | 20 | @interface AWSAuthorizationManager() 21 | 22 | - (void)completeLoginWithResult:(id)result 23 | error:(NSError *)error; 24 | - (void)clearAccessToken; 25 | 26 | @end 27 | 28 | @interface AWSQuickbooksAuthorizationManager() 29 | 30 | typedef void (^AWSCompletionBlock)(id result, NSError *error); 31 | 32 | - (void)completeLoginWithResult:(id)result error:(NSError *)error; 33 | 34 | @property (strong, nonatomic) SFSafariViewController *safariVC; 35 | @property (assign, nonatomic) BOOL dismissOnLoad; 36 | 37 | @property (strong, nonatomic) AWSCompletionBlock loginCompletionHandler; 38 | @property (strong, nonatomic) AWSCompletionBlock logoutCompletionHandler; 39 | @property (strong, nonatomic) AWSCompletionBlock refreshCompletionHandler; 40 | 41 | @property (strong, nonatomic) NSString *redirectURI; 42 | @property (strong, nonatomic, getter=getAPIKey) NSString *key; 43 | @property (strong, nonatomic, getter=getAPISecret, setter=setAPISecret:) NSString *secret; 44 | @property (strong, nonatomic, getter=getAccessToken) NSString *token; 45 | @property (strong, nonatomic, getter=getAccessTokenSecret) NSString *tokenSecret; 46 | @property (strong, nonatomic, getter=getRealmID) NSString *realmID; 47 | @property (strong, nonatomic) NSString *intermediateTokenSecret; 48 | 49 | @end 50 | 51 | @implementation AWSQuickbooksAuthorizationManager 52 | 53 | + (instancetype)sharedInstance { 54 | static AWSQuickbooksAuthorizationManager *_sharedInstance = nil; 55 | static dispatch_once_t onceToken; 56 | dispatch_once(&onceToken, ^{ 57 | _sharedInstance = [AWSQuickbooksAuthorizationManager new]; 58 | }); 59 | 60 | return _sharedInstance; 61 | } 62 | 63 | - (instancetype)init { 64 | if (self = [super init]) { 65 | NSDictionary *config = [[[AWSInfo defaultAWSInfo].rootInfoDictionary objectForKey:@"SaaS"] objectForKey:@"QuickBooks"]; 66 | [self configureWithAPIKey:[config objectForKey:@"APIKey"] 67 | redirectURI:[config objectForKey:@"RedirectURI"]]; 68 | return self; 69 | } 70 | return nil; 71 | } 72 | 73 | #pragma mark - External API 74 | 75 | - (void)configureWithAPIKey:(NSString *)key 76 | redirectURI:(NSString *)redirectURI { 77 | self.key = key; 78 | self.redirectURI = redirectURI; 79 | } 80 | 81 | - (void)authorizeWithView:(UIViewController * _Nonnull)authorizeViewController 82 | completionHandler:(void (^_Nullable)(id _Nullable, NSError * _Nullable))completionHandler { 83 | self.loginCompletionHandler = completionHandler; 84 | 85 | if ([self.key length] > 0 && [self.secret length] > 0 86 | && [self.token length] > 0 && [self.tokenSecret length] > 0 && [self.realmID length] > 0) { 87 | [self completeLoginWithResult:@{@"api_key": self.key, 88 | @"api_secret": self.secret, 89 | @"access_token": self.token, 90 | @"access_token_secret": self.tokenSecret, 91 | @"realm_id": self.realmID} 92 | error:nil]; 93 | } 94 | 95 | NSMutableString *missingParams = [NSMutableString new]; 96 | 97 | if ([self.key length] == 0) { 98 | [missingParams appendString:@"apiKey "]; 99 | } 100 | 101 | if ([self.secret length] == 0) { 102 | [missingParams appendString:@"apiSecret "]; 103 | } 104 | 105 | if ([self.redirectURI length] == 0) { 106 | [missingParams appendString:@"redirectURI "]; 107 | } 108 | 109 | if ([missingParams length] > 0) { 110 | NSString *message = [NSString stringWithFormat:@"Missing parameter(s): %@", missingParams]; 111 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 112 | code:AWSAuthorizationErrorMissingRequiredParameter 113 | userInfo:@{@"message": message}]]; 114 | } 115 | 116 | [self generateOAuthRequestToken:^(NSError *error, NSDictionary *responseParams) { 117 | if (error) { 118 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 119 | code:AWSAuthorizationErrorConnectionError 120 | userInfo:@{@"error": error}]]; 121 | } 122 | AWSLogVerbose(@"%@", responseParams); 123 | 124 | self.intermediateTokenSecret = responseParams[@"oauth_token_secret"]; 125 | NSString *oauth_token = responseParams[@"oauth_token"]; 126 | 127 | if (self.intermediateTokenSecret && oauth_token) { 128 | NSString *authenticationUrl = [NSString stringWithFormat:@"%@?oauth_token=%@", AWSQuickbooksAuthorizationManagerAuthorizationURLString, oauth_token]; 129 | 130 | self.safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:authenticationUrl] 131 | entersReaderIfAvailable:NO]; 132 | self.safariVC.delegate = self; 133 | self.dismissOnLoad = NO; 134 | [authorizeViewController presentViewController:self.safariVC animated:YES completion:nil]; 135 | } else { 136 | [self completeLoginWithResult:nil error:nil]; 137 | } 138 | }]; 139 | } 140 | 141 | #pragma mark - Internal use 142 | 143 | - (void)generateOAuthRequestToken:(void (^)(NSError *error, NSDictionary *responseParams))completion { 144 | NSMutableString *formString = [NSMutableString new]; 145 | [formString appendFormat:@""]; 146 | [formString appendFormat:@"oauth_callback=%@", [self escape:self.redirectURI]]; 147 | [formString appendFormat:@"&oauth_consumer_key=%@", self.key]; 148 | [formString appendFormat:@"&oauth_nonce=%u", arc4random_uniform(UINT32_MAX)]; 149 | [formString appendFormat:@"&oauth_signature_method=%@", @"HMAC-SHA1"]; 150 | [formString appendFormat:@"&oauth_timestamp=%d", (int) [[NSDate date] timeIntervalSince1970]]; 151 | [formString appendFormat:@"&oauth_version=%@", @"1.0"]; 152 | 153 | NSString *message = [NSString stringWithFormat:@"GET&%@&%@", [self escape:AWSQuickbooksAuthorizationManagerRequestTokenURLString], [self escape:formString]]; 154 | NSString *secret = [NSString stringWithFormat:@"%@&", self.secret]; 155 | NSString *signature = [self sha1HMacWithData:[message dataUsingEncoding:NSUTF8StringEncoding] 156 | withKey:[secret dataUsingEncoding:NSUTF8StringEncoding]]; 157 | 158 | [formString appendFormat:@"&oauth_signature=%@", [self escape:signature]]; 159 | 160 | NSString *urlString = [NSString stringWithFormat:@"%@?%@", AWSQuickbooksAuthorizationManagerRequestTokenURLString, formString]; 161 | 162 | NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]]; 163 | 164 | [NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { 165 | if(connectionError) { 166 | completion(connectionError, nil); 167 | return; 168 | } 169 | AWSLogVerbose(@"Completed Quickbooks first leg."); 170 | NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 171 | completion(nil, [AWSAuthorizationManager constructParametersWithURI:responseString]); 172 | }]; 173 | } 174 | 175 | - (NSString *)sha1HMacWithData:(NSData *)data withKey:(NSData *)key { 176 | CCHmacContext context; 177 | 178 | CCHmacInit(&context, kCCHmacAlgSHA1, [key bytes], [key length]); 179 | CCHmacUpdate(&context, [data bytes], [data length]); 180 | 181 | unsigned char digestRaw[CC_SHA1_DIGEST_LENGTH]; 182 | NSInteger digestLength = CC_SHA1_DIGEST_LENGTH; 183 | 184 | CCHmacFinal(&context, digestRaw); 185 | 186 | return [[NSData dataWithBytes:digestRaw length:digestLength] base64EncodedStringWithOptions:kNilOptions]; 187 | } 188 | 189 | - (NSString *)escape:(NSString *)string { 190 | string = [string stringByReplacingOccurrencesOfString:@"%" withString:@"%25"]; 191 | string = [string stringByReplacingOccurrencesOfString:@"&" withString:@"%26"]; 192 | string = [string stringByReplacingOccurrencesOfString:@"=" withString:@"%3D"]; 193 | string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"]; 194 | string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"%2F"]; 195 | string = [string stringByReplacingOccurrencesOfString:@":" withString:@"%3A"]; 196 | return string; 197 | } 198 | 199 | - (BOOL)handleURL:(NSURL *)url { 200 | if (![self isAcceptedURL:url]) { 201 | return NO; 202 | } 203 | AWSLogVerbose(@"Completed Quickbooks second leg."); 204 | NSDictionary *params = [AWSAuthorizationManager constructParametersWithURI:[url query]]; 205 | self.realmID = params[@"realmId"]; 206 | 207 | if ([self.realmID length] == 0) { 208 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 209 | code:AWSAuthorizationErrorFailedToRetrieveAccessToken 210 | userInfo:nil]]; 211 | } 212 | 213 | NSMutableString *formString = [NSMutableString new]; 214 | [formString appendFormat:@"oauth_consumer_key=%@", self.key]; 215 | [formString appendFormat:@"&oauth_nonce=%u", arc4random_uniform(UINT32_MAX)]; 216 | [formString appendFormat:@"&oauth_signature_method=%@", @"HMAC-SHA1"]; 217 | [formString appendFormat:@"&oauth_timestamp=%d", (int) [[NSDate date] timeIntervalSince1970]]; 218 | [formString appendFormat:@"&oauth_token=%@", params[@"oauth_token"]]; 219 | [formString appendFormat:@"&oauth_verifier=%@", params[@"oauth_verifier"]]; 220 | [formString appendFormat:@"&oauth_version=%@", @"1.0"]; 221 | 222 | NSString *message = [NSString stringWithFormat:@"GET&%@&%@", 223 | [self escape:AWSQuickbooksAuthorizationManagerAccessTokenURLString], [self escape:formString]]; 224 | NSString *secret = [NSString stringWithFormat:@"%@&%@", self.secret, self.intermediateTokenSecret]; 225 | self.intermediateTokenSecret = nil; 226 | NSString *signature = [self sha1HMacWithData:[message dataUsingEncoding:NSUTF8StringEncoding] 227 | withKey:[secret dataUsingEncoding:NSUTF8StringEncoding]]; 228 | 229 | [formString appendFormat:@"&oauth_signature=%@",[self escape:signature]]; 230 | NSString *urlString = [NSString stringWithFormat:@"%@?%@", AWSQuickbooksAuthorizationManagerAccessTokenURLString, formString]; 231 | NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:urlString]]; 232 | 233 | [NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { 234 | if (connectionError) { 235 | AWSLogVerbose(@"Error: %@", connectionError.description); 236 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 237 | code:AWSAuthorizationErrorConnectionError 238 | userInfo:@{@"connectionError": connectionError}]]; 239 | return; 240 | } 241 | AWSLogVerbose(@"Completed Quickbooks third leg."); 242 | NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 243 | NSDictionary *oauthTokens = [AWSAuthorizationManager constructParametersWithURI:responseString]; 244 | self.token = oauthTokens[@"oauth_token"]; 245 | self.tokenSecret = oauthTokens[@"oauth_token_secret"]; 246 | 247 | if ([self.token length] == 0 || [self.tokenSecret length] == 0) { 248 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 249 | code:AWSAuthorizationErrorFailedToRetrieveAccessToken 250 | userInfo:@{@"message": responseString}]]; 251 | } 252 | [self completeLoginWithResult:@{@"api_key": self.key, 253 | @"api_secret": self.secret, 254 | @"access_token": self.token, 255 | @"access_token_secret": self.tokenSecret, 256 | @"realm_id": self.realmID} 257 | error:nil]; 258 | }]; 259 | 260 | return YES; 261 | } 262 | 263 | - (BOOL)isAcceptedURL:(NSURL *)url { 264 | return [[url absoluteString] hasPrefix:self.redirectURI]; 265 | } 266 | 267 | - (void)completeLoginWithResult:(id)result 268 | error:(NSError *)error { 269 | AWSLogVerbose(@"completeLoginWithResult called"); 270 | 271 | NSError *surfacedError = result ? nil : (error ?: [NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 272 | code:AWSAuthorizationErrorFailedToRetrieveAccessToken 273 | userInfo:nil]); 274 | if (surfacedError) { 275 | AWSLogError(@"Error: %@", surfacedError); 276 | } 277 | 278 | if (self.loginCompletionHandler) { 279 | self.loginCompletionHandler(result, surfacedError); 280 | self.loginCompletionHandler = nil; 281 | } 282 | 283 | dispatch_async(dispatch_get_main_queue(), ^{ 284 | if (self.safariVC) { 285 | [self.safariVC dismissViewControllerAnimated:YES completion: nil]; 286 | self.safariVC = nil; 287 | } 288 | }); 289 | } 290 | 291 | - (NSURL *)generateLogoutURL { 292 | return nil; 293 | } 294 | 295 | - (void)clearAccessToken { 296 | [super clearAccessToken]; 297 | self.token = nil; 298 | self.tokenSecret = nil; 299 | self.secret = nil; 300 | self.realmID = nil; 301 | } 302 | 303 | #pragma mark - SFSafariViewControllerDelegate 304 | 305 | -(void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully { 306 | // Load finished 307 | if (self.dismissOnLoad) { 308 | if (self.logoutCompletionHandler) { 309 | self.logoutCompletionHandler(@{@"didSucceed" : @YES}, nil); 310 | self.logoutCompletionHandler = nil; 311 | } 312 | [controller dismissViewControllerAnimated:true completion: nil]; 313 | } 314 | } 315 | 316 | -(void)safariViewControllerDidFinish:(SFSafariViewController *)controller { 317 | if (self.dismissOnLoad && self.logoutCompletionHandler) { 318 | self.logoutCompletionHandler(@{@"didSucceed" : @NO}, [NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 319 | code:AWSAuthorizationErrorUserCancelledFlow 320 | userInfo:@{@"message": @"User login cookies may not have been cleared."}]); 321 | self.logoutCompletionHandler = nil; 322 | } else if (!self.dismissOnLoad && self.loginCompletionHandler) { 323 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 324 | code:AWSAuthorizationErrorUserCancelledFlow 325 | userInfo:@{@"message": @"User cancelled authorization flow."}]]; 326 | } 327 | } 328 | 329 | @end 330 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSSalesforceAuthorizationManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSalesforceAuthorizationManager.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSAuthorizationManager.h" 11 | 12 | @interface AWSSalesforceAuthorizationManager : AWSAuthorizationManager 13 | 14 | /** 15 | * Singleton used to authorize user during OAuth2.0 16 | * @return the singleton 17 | */ 18 | + (instancetype _Nonnull)sharedInstance; 19 | 20 | /** 21 | * Customize the flow. 22 | * 23 | * @param clientID Client ID provided by Salesforce. 24 | * @param redirectURI Should be you're bundle ID or universal URL 25 | * i.e. com.amazonaws.mysampleapp://salesforce/success 26 | * https://mysampleapp.amazonaws.com/success 27 | */ 28 | - (void)configureWithClientID:(NSString * _Nonnull)clientID redirectURI:(NSString * _Nonnull)redirectURI; 29 | 30 | /** 31 | * @return The token type. Available after user authorizes app. 32 | * i.e. Bearer 33 | */ 34 | - (NSString * _Nullable)getTokenType; 35 | 36 | /** 37 | * @return The instance Salesforce has assigned you. Available after user authorizes app. 38 | * i.e. https://na15.salesforce.com/ 39 | */ 40 | - (NSString * _Nullable)getInstanceURL; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSSalesforceAuthorizationManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSalesforceAuthorizationManager.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSSalesforceAuthorizationManager.h" 11 | #import 12 | 13 | typedef void (^AWSCompletionBlock)(id result, NSError *error); 14 | 15 | static NSString *const AWSSalesforceAuthorizationManagerAuthorizeURLString = @"https://login.salesforce.com/services/oauth2/authorize"; 16 | static NSString *const AWSSalesforceAuthorizationManagerTokenURLString = @"https://login.salesforce.com/services/oauth2/token"; 17 | static NSString *const AWSSalesforceAuthorizationManagerLogoutURLPostfix = @"/secur/logout.jsp"; 18 | 19 | static NSString *const AWSSalesforceAuthorizationManagerInstanceURLKey = @"instance_url"; 20 | static NSString *const AWSSalesforceAuthorizationManagerTokenTypeKey = @"token_type"; 21 | static NSString *const AWSSalesforceAuthorizationManagerAccessTokenKey = @"access_token"; 22 | 23 | @interface AWSAuthorizationManager() 24 | 25 | - (void)completeLoginWithResult:(id)result 26 | error:(NSError *)error; 27 | - (void)clearAccessToken; 28 | 29 | @end 30 | 31 | @interface AWSSalesforceAuthorizationManager() 32 | 33 | @property (strong, nonatomic) NSString *clientID; 34 | @property (strong, nonatomic) NSString *redirectURI; 35 | 36 | @property (strong, nonatomic) NSDictionary *valuesFromResponse; 37 | 38 | @end 39 | 40 | @implementation AWSSalesforceAuthorizationManager 41 | 42 | + (instancetype)sharedInstance { 43 | static AWSSalesforceAuthorizationManager *_sharedInstance = nil; 44 | static dispatch_once_t onceToken; 45 | dispatch_once(&onceToken, ^{ 46 | _sharedInstance = [[AWSSalesforceAuthorizationManager alloc] init]; 47 | }); 48 | 49 | return _sharedInstance; 50 | } 51 | 52 | - (instancetype)init { 53 | if (self = [super init]) { 54 | NSDictionary *config = [[[AWSInfo defaultAWSInfo].rootInfoDictionary objectForKey:@"SaaS"] objectForKey:@"Salesforce"]; 55 | _clientID = [config objectForKey:@"ClientID"]; 56 | _redirectURI = [config objectForKey:@"RedirectURI"]; 57 | 58 | return self; 59 | } 60 | return nil; 61 | } 62 | 63 | - (void)configureWithClientID:(NSString *)clientID 64 | redirectURI:(NSString *)redirectURI { 65 | self.clientID = clientID; 66 | self.redirectURI = redirectURI; 67 | } 68 | 69 | - (NSString *)getInstanceURL { 70 | return self.valuesFromResponse[AWSSalesforceAuthorizationManagerInstanceURLKey]; 71 | } 72 | 73 | - (NSString *)getTokenType { 74 | return self.valuesFromResponse[AWSSalesforceAuthorizationManagerTokenTypeKey]; 75 | } 76 | 77 | #pragma mark - Override Custom Methods 78 | 79 | - (BOOL)usesImplicitGrant { 80 | return YES; 81 | } 82 | 83 | - (NSURL *)generateAuthURL { 84 | NSMutableString *missingParams = [NSMutableString new]; 85 | 86 | if ([self.clientID length] == 0) { 87 | [missingParams appendString:@"clientID "]; 88 | } 89 | 90 | if ([self.redirectURI length] == 0) { 91 | [missingParams appendString:@"redirectURI "]; 92 | } 93 | 94 | if ([missingParams length] > 0) { 95 | NSString *message = [NSString stringWithFormat:@"Missing parameter(s): %@", missingParams]; 96 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 97 | code:AWSAuthorizationErrorMissingRequiredParameter 98 | userInfo:@{@"message": message}]]; 99 | } 100 | 101 | NSDictionary *params = @{@"client_id" : self.clientID, 102 | @"response_type" : @"token", 103 | @"redirect_uri" : [self.redirectURI stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]], 104 | }; 105 | 106 | NSString *urlString = [NSString stringWithFormat:@"%@?%@", AWSSalesforceAuthorizationManagerAuthorizeURLString, [AWSAuthorizationManager constructURIWithParameters:params]]; 107 | 108 | return [NSURL URLWithString:urlString]; 109 | } 110 | 111 | - (NSString *)findAccessCode:(NSURL *)url { 112 | NSString *urlHeadRemoved = [[url absoluteString] stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"%@#", self.redirectURI] withString:@""]; 113 | self.valuesFromResponse = [AWSAuthorizationManager constructParametersWithURI:urlHeadRemoved]; 114 | 115 | return [self.valuesFromResponse objectForKey:AWSSalesforceAuthorizationManagerAccessTokenKey]; 116 | } 117 | 118 | - (NSString *)getAccessTokenUsingAuthorizationCode:(NSString *)authorizationCode 119 | loginCompletionHandler:(AWSCompletionBlock)loginCompletionHandler { 120 | NSDictionary *params = @{@"grant_type" : @"authorization_code", 121 | @"code" : authorizationCode, 122 | @"client_id" : self.clientID, 123 | @"redirect_uri" : self.redirectURI, 124 | }; 125 | 126 | NSString *post = [AWSAuthorizationManager constructURIWithParameters:params]; 127 | 128 | NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 129 | NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]]; 130 | 131 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; 132 | [request setURL:[NSURL URLWithString:AWSSalesforceAuthorizationManagerTokenURLString]]; 133 | [request setHTTPMethod:@"POST"]; 134 | [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; 135 | [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; 136 | [request setHTTPBody:postData]; 137 | 138 | __weak AWSSalesforceAuthorizationManager *weakSelf = self; 139 | 140 | NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 141 | if (error) { 142 | [weakSelf completeLoginWithResult:nil error:error]; 143 | return; 144 | } 145 | 146 | NSError *parseError; 147 | weakSelf.valuesFromResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError]; 148 | 149 | if ([[weakSelf.valuesFromResponse objectForKey:AWSSalesforceAuthorizationManagerAccessTokenKey] length] == 0) { 150 | [weakSelf completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 151 | code:AWSAuthorizationErrorFailedToRetrieveAccessToken 152 | userInfo:@{@"response": weakSelf.valuesFromResponse, 153 | @"parseError": parseError}]]; 154 | } 155 | 156 | [weakSelf completeLoginWithResult:[weakSelf.valuesFromResponse objectForKey:AWSSalesforceAuthorizationManagerAccessTokenKey] error:parseError]; 157 | }]; 158 | [task resume]; 159 | 160 | return nil; 161 | } 162 | 163 | - (BOOL)isAcceptedURL:(NSURL *)url { 164 | return [[url absoluteString] hasPrefix:self.redirectURI]; 165 | } 166 | 167 | - (NSURL *)generateLogoutURL { 168 | NSString *logoutURLString = [NSString stringWithFormat:@"%@%@", [self getInstanceURL], AWSSalesforceAuthorizationManagerLogoutURLPostfix]; 169 | AWSLogVerbose(@"Logout: %@", logoutURLString); 170 | return [NSURL URLWithString:logoutURLString]; 171 | } 172 | 173 | - (void)clearAccessToken { 174 | [super clearAccessToken]; 175 | self.valuesFromResponse = nil; 176 | } 177 | 178 | @end 179 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSZendeskAuthorizationManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSZendeskAuthorizationManager.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSAuthorizationManager.h" 11 | 12 | @interface AWSZendeskAuthorizationManager : AWSAuthorizationManager 13 | 14 | /** 15 | * Singleton used to authorize user during OAuth2.0 16 | * @return the singleton 17 | */ 18 | + (instancetype _Nonnull)sharedInstance; 19 | 20 | /** 21 | * Customize the flow. This relies on the redirectURI being an Universal link. 22 | * 23 | * @param clientID The client ID that you signed up for in Zendesk 24 | * @param redirectURI The redirect URI you provided Zendesk 25 | * i.e. https://mysampleapp.amazonaws.com/zendesk/success 26 | * @param subdomain The subdomain that you signed up for in Zendesk 27 | */ 28 | - (void)configureWithClientID:(NSString * _Nonnull)clientID 29 | redirectURI:(NSString * _Nonnull)redirectURI 30 | subdomain:(NSString * _Nonnull)subdomain; 31 | 32 | /** 33 | * If you are unable to setup Universal links at this moment, then for development purposes 34 | * you may consider use a HTTPS endpoint that you control to redirect to a custom app scheme url. 35 | * 36 | * Example: 37 | * Endpoint HTML content at https://awsmobilehub.s3-us-west-2.amazonaws.com/zendesk 38 | * 39 | * 40 | * 41 | * 42 | * customSchemeRedirectURI = @"com.amazon.mysampleapp://zendesk/oauth2"; 43 | * httpsEndpoint = @"https://awsmobilehub.s3-us-west-2.amazonaws.com/zendesk"; 44 | * 45 | * @param clientID The client ID that you signed up for in Zendesk 46 | * @param customSchemeRedirectURI The redirectURI that has the custom app scheme 47 | * @param httpsEndpoint The HTTPS endpoint that needs to be registered with Zendesk. 48 | * This endpoint must redirect the page to the customSchemeRedirectURI 49 | * provided here. 50 | * @param subdomain The subdomain that you signed up for in Zendesk 51 | */ 52 | - (void)configureWithClientID:(NSString * _Nonnull)clientID 53 | setCustomSchemeRedirectURI:(NSString * _Nonnull)customSchemeRedirectURI 54 | httpsEndpoint:(NSString * _Nonnull)httpsEndpoint 55 | subdomain:(NSString * _Nonnull)subdomain; 56 | 57 | /** 58 | * 59 | * Available scopes: 60 | * tickets 61 | * users 62 | * auditlogs (read only) 63 | * organizations 64 | * hc 65 | * apps 66 | * triggers 67 | * automations 68 | * targets 69 | * 70 | * @param scope Specify the amount of access the user would like. 71 | * i.e. @"read" 72 | * @"read tickets:write" 73 | * @"tickets:read tickets:write" 74 | */ 75 | - (void)setScope:(NSString * _Nonnull)scope; 76 | 77 | /** 78 | * @return The token type. Available after user authorizes app. 79 | * i.e. Bearer 80 | */ 81 | - (NSString * _Nullable)getTokenType; 82 | 83 | /** 84 | * @return The subdomain that you signed up for in Zendesk. 85 | * i.e. aws 86 | */ 87 | - (NSString * _Nullable)getSubdomain; 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /AWSMobileHubAuthorizers/AWSZendeskAuthorizationManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSZendeskAuthorizationManager.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSZendeskAuthorizationManager.h" 11 | #import 12 | 13 | static NSString *const AWSZendeskAuthorizationManagerAuthorizeURLFormatString = @"https://%@.zendesk.com/oauth/authorizations/new"; 14 | static NSString *const AWSZendeskAuthorizationManagerLogoutURLFormatString = @"https://%@.zendesk.com/access/logout"; 15 | 16 | static NSString *const AWSZendeskAuthorizationManagerTokenTypeKey = @"token_type"; 17 | static NSString *const AWSZendeskAuthorizationManagerAccessTokenKey = @"access_token"; 18 | 19 | @interface AWSAuthorizationManager() 20 | 21 | - (void)completeLoginWithResult:(id)result 22 | error:(NSError *)error; 23 | - (void)clearAccessToken; 24 | 25 | @end 26 | 27 | @interface AWSZendeskAuthorizationManager() 28 | 29 | @property (strong, nonatomic) NSString *authorizeURLString; 30 | @property (strong, nonatomic) NSString *logoutURLString; 31 | @property (strong, nonatomic) NSString *clientID; 32 | @property (strong, nonatomic, getter=getSubdomain) NSString *subdomain; 33 | @property (strong, nonatomic) NSString *redirectURI; 34 | @property (strong, nonatomic) NSString *customSchemeRedirect; 35 | @property (strong, nonatomic, setter=setScope:) NSString *scope; 36 | 37 | @property (strong, nonatomic) NSDictionary *valuesFromResponse; 38 | 39 | @end 40 | 41 | @implementation AWSZendeskAuthorizationManager 42 | 43 | + (instancetype)sharedInstance { 44 | static AWSZendeskAuthorizationManager *_sharedInstance = nil; 45 | static dispatch_once_t onceToken; 46 | dispatch_once(&onceToken, ^{ 47 | _sharedInstance = [[AWSZendeskAuthorizationManager alloc] init]; 48 | }); 49 | 50 | return _sharedInstance; 51 | } 52 | 53 | - (instancetype)init { 54 | if (self = [super init]) { 55 | NSDictionary *config = [[[AWSInfo defaultAWSInfo].rootInfoDictionary objectForKey:@"SaaS"] objectForKey:@"Zendesk"]; 56 | _authorizeURLString = [NSString stringWithFormat:AWSZendeskAuthorizationManagerAuthorizeURLFormatString, [config objectForKey:@"Subdomain"]]; 57 | [self configureWithClientID:[config objectForKey:@"ClientID"] 58 | redirectURI:[config objectForKey:@"RedirectURI"] 59 | subdomain:[config objectForKey:@"Subdomain"]]; 60 | 61 | return self; 62 | } 63 | return nil; 64 | } 65 | 66 | - (void)configureWithClientID:(NSString *)clientID 67 | redirectURI:(NSString *)redirectURI 68 | subdomain:(NSString *)subdomain { 69 | self.clientID = clientID; 70 | self.redirectURI = redirectURI; 71 | self.authorizeURLString = [NSString stringWithFormat:AWSZendeskAuthorizationManagerAuthorizeURLFormatString, subdomain]; 72 | self.logoutURLString = [NSString stringWithFormat:AWSZendeskAuthorizationManagerLogoutURLFormatString, subdomain]; 73 | self.subdomain = subdomain; 74 | self.customSchemeRedirect = nil; 75 | } 76 | 77 | - (void)configureWithClientID:(NSString * _Nonnull)clientID 78 | setCustomSchemeRedirectURI:(NSString * _Nonnull)customSchemeRedirectURI 79 | httpsEndpoint:(NSString * _Nonnull)httpsEndpoint 80 | subdomain:(NSString * _Nonnull)subdomain { 81 | self.clientID = clientID; 82 | self.redirectURI = httpsEndpoint; 83 | self.customSchemeRedirect = customSchemeRedirectURI; 84 | self.authorizeURLString = [NSString stringWithFormat:AWSZendeskAuthorizationManagerAuthorizeURLFormatString, subdomain]; 85 | self.logoutURLString = [NSString stringWithFormat:AWSZendeskAuthorizationManagerLogoutURLFormatString, subdomain]; 86 | self.subdomain = subdomain; 87 | } 88 | 89 | - (NSString *)getTokenType { 90 | return [self.valuesFromResponse objectForKey:AWSZendeskAuthorizationManagerTokenTypeKey]; 91 | } 92 | 93 | #pragma mark - Override Custom Methods 94 | 95 | - (BOOL)usesImplicitGrant { 96 | return YES; 97 | } 98 | 99 | - (NSURL *)generateAuthURL { 100 | NSMutableString *missingParams = [NSMutableString new]; 101 | 102 | if ([self.clientID length] == 0) { 103 | [missingParams appendString:@"clientID "]; 104 | } 105 | 106 | if ([self.redirectURI length] == 0) { 107 | [missingParams appendString:@"redirectURI "]; 108 | } 109 | 110 | if ([self.subdomain length] == 0) { 111 | [missingParams appendString:@"subdomain "]; 112 | } 113 | 114 | if ([self.scope length] == 0) { 115 | [missingParams appendString:@"scope "]; 116 | } 117 | 118 | if ([missingParams length] > 0) { 119 | NSString *message = [NSString stringWithFormat:@"Missing parameter(s): %@", missingParams]; 120 | [self completeLoginWithResult:nil error:[NSError errorWithDomain:AWSAuthorizationManagerErrorDomain 121 | code:AWSAuthorizationErrorMissingRequiredParameter 122 | userInfo:@{@"message": message}]]; 123 | } 124 | 125 | NSDictionary *params = @{ 126 | @"response_type" : @"token", 127 | @"client_id" : self.clientID, 128 | @"redirect_uri" : [self.redirectURI stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]], 129 | @"scope" : [self.scope stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]] 130 | }; 131 | 132 | NSString *urlString = [NSString stringWithFormat:@"%@?%@", self.authorizeURLString, [AWSAuthorizationManager constructURIWithParameters:params]]; 133 | return [NSURL URLWithString:urlString]; 134 | } 135 | 136 | - (BOOL)isAcceptedURL:(NSURL *)url { 137 | if (self.customSchemeRedirect) { 138 | return [[url absoluteString] hasPrefix:self.customSchemeRedirect]; 139 | } else if (self.redirectURI) { 140 | return [[url absoluteString] hasPrefix:self.redirectURI]; 141 | } 142 | return NO; 143 | } 144 | 145 | - (NSString *)findAccessCode:(NSURL *)url { 146 | NSString *formString = [url absoluteString]; 147 | 148 | if (self.customSchemeRedirect) { 149 | formString = [formString stringByReplacingOccurrencesOfString:self.customSchemeRedirect withString:@""]; 150 | } 151 | 152 | if (self.redirectURI) { 153 | formString = [formString stringByReplacingOccurrencesOfString:self.redirectURI withString:@""]; 154 | } 155 | 156 | if ([formString length] > 2) { 157 | formString = [formString substringFromIndex:1]; 158 | } 159 | 160 | self.valuesFromResponse = [AWSAuthorizationManager constructParametersWithURI:formString]; 161 | return [self.valuesFromResponse objectForKey:AWSZendeskAuthorizationManagerAccessTokenKey]; 162 | } 163 | 164 | - (NSURL *)generateLogoutURL { 165 | return [NSURL URLWithString:self.logoutURLString]; 166 | } 167 | 168 | - (void)clearAccessToken { 169 | [super clearAccessToken]; 170 | self.valuesFromResponse = nil; 171 | } 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /AWSMobileHubHelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AWSMobileHubHelper.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/AWSMobileHubHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSMobileHubHelper.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSContentManager.h" 11 | #import "AWSCloudLogic.h" 12 | #import "AWSIdentityManager.h" 13 | #import "AWSPushManager.h" 14 | #import "AWSUserFileManager.h" 15 | #import "AWSIdentityProfile.h" 16 | #import "AWSSignInManager.h" 17 | #import "AWSSignInButtonView.h" 18 | #import "AWSIdentityProfileManager.h" 19 | #import "AWSSignInButtonView.h" 20 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/AWSMobileHubHelper.modulemap: -------------------------------------------------------------------------------- 1 | framework module AWSMobileHubHelper { 2 | umbrella header "AWSMobileHubHelper.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSIdentityManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSIdentityManager.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | #import 10 | #import 11 | #import 12 | #import "AWSSignInProvider.h" 13 | #import "AWSSignInProviderApplicationIntercept.h" 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | @interface AWSIdentityManager : NSObject 18 | 19 | /** 20 | * User Info acquired from third party identity provider, such as Facebook or Google. 21 | * @return userInfo object of the underlying signInProvider 22 | */ 23 | @property (nonatomic, readonly) id _Nullable identityProfile; 24 | 25 | /** 26 | * Amazon Cognito User Identity ID. This uniquely identifies the user, regardless of 27 | * whether or not the user is signed-in, if User Sign-in is enabled in the project. 28 | * @return unique user identifier 29 | */ 30 | @property (nonatomic, readonly, nullable) NSString *identityId; 31 | 32 | /** 33 | * Amazon Cognito Credentials Provider. This is the credential provider used by the Identity Manager. 34 | * 35 | * @return the cognito credentials provider 36 | */ 37 | @property (nonatomic, readonly, strong) AWSCognitoCredentialsProvider *credentialsProvider; 38 | 39 | /** 40 | Returns the Identity Manager singleton instance configured using the information provided in `Info.plist` file. 41 | 42 | *Swift* 43 | 44 | let identityManager = AWSIdentityManager.default() 45 | 46 | *Objective-C* 47 | 48 | AWSIdentityManager *identityManager = [AWSIdentityManager defaultIdentityManager]; 49 | */ 50 | + (instancetype)defaultIdentityManager; 51 | 52 | 53 | @end 54 | 55 | NS_ASSUME_NONNULL_END 56 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSIdentityManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSIdentityManager.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import "AWSIdentityManager.h" 11 | #import "AWSSignInProvider.h" 12 | #import "AWSSignInManager.h" 13 | #import "AWSIdentityProfileManager.h" 14 | 15 | @interface AWSIdentityManager() 16 | 17 | @property (nonatomic, readwrite, strong) AWSCognitoCredentialsProvider *credentialsProvider; 18 | 19 | @end 20 | 21 | @interface AWSSignInManager() 22 | 23 | @property (nonatomic, strong) id currentSignInProvider; 24 | @property (nonatomic, strong) id potentialSignInProvider; 25 | 26 | @end 27 | 28 | @interface AWSIdentityProfileManager() 29 | 30 | -(id)getIdentityProfileForProviderKey:(NSString *)key; 31 | 32 | @end 33 | 34 | @implementation AWSIdentityManager 35 | 36 | static NSString *const AWSInfoIdentityManager = @"IdentityManager"; 37 | static NSString *const AWSInfoRoot = @"AWS"; 38 | static NSString *const AWSInfoMobileHub = @"MobileHub"; 39 | static NSString *const AWSInfoProjectClientId = @"ProjectClientId"; 40 | 41 | + (instancetype)defaultIdentityManager { 42 | static AWSIdentityManager *_defaultIdentityManager = nil; 43 | static dispatch_once_t onceToken; 44 | dispatch_once(&onceToken, ^{ 45 | AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] defaultServiceInfo:AWSInfoIdentityManager]; 46 | if (!serviceInfo) { 47 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 48 | reason:@"The service configuration is `nil`. You need to configure `Info.plist` before using this method." 49 | userInfo:nil]; 50 | } 51 | _defaultIdentityManager = [[AWSIdentityManager alloc] initWithCredentialProvider:serviceInfo]; 52 | }); 53 | 54 | return _defaultIdentityManager; 55 | } 56 | 57 | - (instancetype)initWithCredentialProvider:(AWSServiceInfo *)serviceInfo { 58 | if (self = [super init]) { 59 | 60 | self.credentialsProvider = serviceInfo.cognitoCredentialsProvider; 61 | [self.credentialsProvider setIdentityProviderManagerOnce:self]; 62 | 63 | // Set up the user agent string to indicate usage of the Mobile Hub Helper Framework. 64 | NSString *projectTemplateId = [[[AWSInfo defaultAWSInfo].rootInfoDictionary objectForKey:AWSInfoMobileHub] objectForKey:AWSInfoProjectClientId]; 65 | if (!projectTemplateId) { 66 | projectTemplateId = @"MobileHub HelperFramework"; 67 | } 68 | [AWSServiceConfiguration addGlobalUserAgentProductToken:projectTemplateId]; 69 | } 70 | return self; 71 | } 72 | 73 | #pragma mark - AWSIdentityProviderManager 74 | 75 | - (AWSTask *> *)logins { 76 | if (![AWSSignInManager sharedInstance].currentSignInProvider) { 77 | return [AWSTask taskWithResult:nil]; 78 | } 79 | return [[[AWSSignInManager sharedInstance].currentSignInProvider token] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) { 80 | NSString *token = task.result; 81 | return [AWSTask taskWithResult:@{[AWSSignInManager sharedInstance].currentSignInProvider.identityProviderName : token}]; 82 | }]; 83 | } 84 | 85 | #pragma mark - 86 | 87 | - (NSString *)identityId { 88 | return self.credentialsProvider.identityId; 89 | } 90 | 91 | - (id)identityProfile { 92 | 93 | if ([AWSSignInManager sharedInstance].currentSignInProvider) { 94 | NSString *signInProviderKey = [AWSSignInManager sharedInstance].currentSignInProvider.identityProviderName; 95 | return [[AWSIdentityProfileManager sharedInstance] getIdentityProfileForProviderKey:signInProviderKey]; 96 | } 97 | 98 | return nil; 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSIdentityProfile.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSIdentityProfile.h 3 | // AWSMobileHubHelper 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | /* 14 | This protocol defines a list of methods and properties required to be implemented by a Identity Profile provider. 15 | */ 16 | @protocol AWSIdentityProfile 17 | 18 | /* 19 | The shared instance for the profile provider. 20 | */ 21 | +(id)sharedInstance; 22 | 23 | /** 24 | The URL for profile image of a user. 25 | */ 26 | @property (nonatomic, readonly, nullable) NSURL *imageURL; 27 | 28 | /** 29 | The User Name of a user. 30 | */ 31 | @property (nonatomic, readonly, nullable) NSString *userName; 32 | 33 | /** 34 | Fetches custom stored profile attribute using specified key. 35 | */ 36 | -(_Nullable id)getProfileAttributeForKey:( NSString *)key; 37 | 38 | /** 39 | Stores custom values using specified key. 40 | */ 41 | -(void)setProfileAttribute:(id)value 42 | forKey:(NSString *)key; 43 | 44 | /** 45 | Fetches the entire identity profile attributes map. 46 | */ 47 | -(NSDictionary *)getProfileAttributesMap; 48 | 49 | /** 50 | Clears the current profile information. 51 | */ 52 | -(void)clearProfile; 53 | 54 | /** 55 | Loads the profile information for current signed-in user. 56 | */ 57 | -(void)loadProfile; 58 | 59 | @end 60 | 61 | NS_ASSUME_NONNULL_END 62 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSIdentityProfileManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSIdentityProfileManager.h 3 | // AWSMobileHubHelper 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | #import "AWSIdentityProfile.h" 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | @interface AWSIdentityProfileManager : NSObject 17 | 18 | /* 19 | The shared instance of AWSIdentityProfileManager. 20 | */ 21 | +(instancetype)sharedInstance; 22 | 23 | /* 24 | Registers the specified identity profile instance with a sign in provider. 25 | 26 | @param identityProfile The instance of identity profile implementing `AWSIdentityProfile` protocol. 27 | @param key The sign in provider key registered AWSSignInManager 28 | */ 29 | -(void)registerIdentityProfile:(id)identityProfile 30 | forProviderKey:(NSString *)key; 31 | 32 | /* 33 | Loads the profile details for identity profile instance. 34 | */ 35 | -(void)loadProfileForProviderKey:(NSString *)key; 36 | 37 | /* 38 | Clears the profile information if loaded for idenity profile instance. 39 | */ 40 | -(void)clearProfileForProviderKey:(NSString *)key; 41 | 42 | @end 43 | 44 | NS_ASSUME_NONNULL_END 45 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSIdentityProfileManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSIdentityProfileManager.m 3 | // AWSMobileHubHelper 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSIdentityProfileManager.h" 12 | 13 | @implementation AWSIdentityProfileManager 14 | 15 | static NSMutableDictionary> *identityProfileDict = nil; 16 | 17 | +(instancetype)sharedInstance { 18 | static AWSIdentityProfileManager *_sharedIdentityProfileManager = nil; 19 | static dispatch_once_t onceToken; 20 | dispatch_once(&onceToken, ^{ 21 | _sharedIdentityProfileManager = [[AWSIdentityProfileManager alloc] init]; 22 | identityProfileDict = [[NSMutableDictionary alloc] init]; 23 | }); 24 | 25 | return _sharedIdentityProfileManager; 26 | } 27 | 28 | -(void)registerIdentityProfile:(id)identityProfile 29 | forProviderKey:(NSString *)key { 30 | [identityProfileDict setObject:identityProfile 31 | forKey:key]; 32 | 33 | } 34 | 35 | -(id)getIdentityProfileForProviderKey:(NSString *)key { 36 | return [identityProfileDict objectForKey:key]; 37 | } 38 | 39 | -(void)clearProfileForProviderKey:(NSString *)key { 40 | [[self getIdentityProfileForProviderKey:key] clearProfile]; 41 | } 42 | 43 | -(void)loadProfileForProviderKey:(NSString *)key { 44 | [[self getIdentityProfileForProviderKey:key] loadProfile]; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSSignInButtonView.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSignInButtonView.h 3 | // AWSMobileHubHelper 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | #import "AWSSignInProvider.h" 13 | #import "AWSSignInManager.h" 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | typedef NS_ENUM(NSInteger, AWSSignInButtonStyle) { 18 | AWSSignInButtonStyleSmall, 19 | AWSSignInButtonStyleLarge 20 | }; 21 | 22 | @protocol AWSSignInButtonView 23 | 24 | @property (nonatomic, weak) id delegate; 25 | 26 | @property (nonatomic) AWSSignInButtonStyle buttonStyle; 27 | 28 | - (void)setSignInProvider:(id)signInProvider; 29 | 30 | @end 31 | 32 | NS_ASSUME_NONNULL_END 33 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSSignInManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSignInManager.h 3 | // AWSMobileHubHelper 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | #import "AWSSignInProvider.h" 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | * This protocol defines the method to be implemented to receive a call back when a user attempts 18 | * login with a registered sign-in provider. 19 | */ 20 | @protocol AWSSignInDelegate 21 | 22 | /** 23 | This method gets a call back to the assigned delegate when a user attempts login with a registered sign-in provider. 24 | 25 | @param signInProvider The instance of sign in provider implementing `AWSSignInProvider` protocol. 26 | @param result The result of login attempt. If error, set to `nil`. 27 | @param authState The auth state of the user after sign-in attempt. 28 | @param error The error if sign-in attempt failed. 29 | **/ 30 | - (void)onLoginWithSignInProvider:(id)signInProvider 31 | result:(id _Nullable)result 32 | authState:(AWSIdentityManagerAuthState)authState 33 | error:(NSError * _Nullable)error NS_SWIFT_NAME(onLogin(signInProvider:result:authState:error:)); 34 | 35 | @end 36 | 37 | @interface AWSSignInManager : NSObject 38 | 39 | /** 40 | * Indicates whether the user is signed-in or not. 41 | * @return true if user is signed-in 42 | */ 43 | @property (nonatomic, readonly, getter=isLoggedIn) BOOL loggedIn; 44 | 45 | /** 46 | * The delegate class to be called when a user attempts to login with a registered sign in provider. 47 | */ 48 | @property (nonatomic, weak) id delegate; 49 | 50 | /* 51 | * Fetches the shared instance of `AWSSignInManager`. 52 | */ 53 | +(instancetype)sharedInstance; 54 | 55 | /* 56 | Fetches the current auth state for a user 57 | */ 58 | -(AWSIdentityManagerAuthState)authState; 59 | 60 | /** 61 | Registers the shared instance of sign in provider implementing `AWSSignInProvider`. 62 | 63 | @param signInProvider The shared instance of sign in provider implementing `AWSSignInProvider` protocol. 64 | **/ 65 | -(void)registerAWSSignInProvider:(id)signInProvider NS_SWIFT_NAME(register(signInProvider:)); 66 | 67 | /** 68 | * Signs the user out of whatever third party identity provider they used to sign in. 69 | * @param completionHandler used to callback application with async operation results 70 | */ 71 | - (void)logoutWithCompletionHandler:(void (^)(id _Nullable result, AWSIdentityManagerAuthState authState, NSError * _Nullable error))completionHandler; 72 | 73 | /** 74 | * Signs the user in with an identity provider. Note that even if User Sign-in is not 75 | * enabled in the project, the user is still signed-in with the Guest type provider. 76 | * @param signInProviderKey the identifier key of sign in provider 77 | * @param completionHandler used to callback application with async operation results 78 | */ 79 | - (void)loginWithSignInProviderKey:(NSString *)signInProviderKey 80 | completionHandler:(void (^)(id _Nullable result, AWSIdentityManagerAuthState authState, NSError * _Nullable error))completionHandler NS_SWIFT_NAME(login(signInProviderKey:completionHandler:)); 81 | 82 | /** 83 | * Attempts to resume session with the previous sign-in provider. 84 | * @param completionHandler used to callback application with async operation results 85 | */ 86 | - (void)resumeSessionWithCompletionHandler:(void (^)(id _Nullable result, AWSIdentityManagerAuthState authState, NSError * _Nullable error))completionHandler; 87 | 88 | /** 89 | * Passes parameters used to launch the application to the current identity provider. For some 90 | * third party providers, this completes the User Sign-in call flow, which used a browser to 91 | * get information from the user, directly. The current sign-in provider will be set to nil if 92 | * the sign-in provider is not registered using `registerAWSSignInProvider:forKey` method of 93 | * `AWSSignInProviderFactory` class. 94 | * @param application application 95 | * @param launchOptions options used to launch the application 96 | * @return true if this call handled the operation 97 | */ 98 | - (BOOL)interceptApplication:(UIApplication *)application 99 | didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions; 100 | 101 | /** 102 | * Passes parameters used to launch the application to the current identity provider. For some 103 | * third party providers, this completes the User Sign-in call flow, which used a browser to 104 | * get information from the user, directly. 105 | * @param application application 106 | * @param url url used to open the application 107 | * @param sourceApplication source application 108 | * @param annotation annotation 109 | * @return true if this call handled the operation 110 | */ 111 | - (BOOL)interceptApplication:(UIApplication *)application 112 | openURL:(NSURL *)url 113 | sourceApplication:(nullable NSString *)sourceApplication 114 | annotation:(id)annotation; 115 | 116 | @end 117 | 118 | NS_ASSUME_NONNULL_END 119 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSSignInManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSignInManager.m 3 | // AWSMobileHubHelper 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSSignInManager.h" 12 | #import "AWSIdentityManager.h" 13 | #import "AWSSignInProviderApplicationIntercept.h" 14 | #import "AWSIdentityProfileManager.h" 15 | 16 | typedef void (^AWSSignInManagerCompletionBlock)(id result, AWSIdentityManagerAuthState authState, NSError *error); 17 | 18 | @interface AWSSignInManager() 19 | 20 | @property (atomic, copy) AWSSignInManagerCompletionBlock completionHandler; 21 | 22 | @property (nonatomic, strong) id currentSignInProvider; 23 | @property (nonatomic, strong) id potentialSignInProvider; 24 | 25 | -(id)signInProviderForKey:(NSString *)key; 26 | 27 | @end 28 | 29 | @implementation AWSSignInManager 30 | 31 | static NSMutableDictionary> *signInProviderInfo = nil; 32 | static AWSIdentityManager *identityManager; 33 | 34 | +(instancetype)sharedInstance { 35 | static AWSSignInManager *_sharedSignInManager = nil; 36 | static dispatch_once_t onceToken; 37 | dispatch_once(&onceToken, ^{ 38 | _sharedSignInManager = [[AWSSignInManager alloc] init]; 39 | signInProviderInfo = [[NSMutableDictionary alloc] init]; 40 | identityManager = [AWSIdentityManager defaultIdentityManager]; 41 | }); 42 | 43 | return _sharedSignInManager; 44 | } 45 | 46 | -(AWSIdentityManagerAuthState)authState { 47 | if (identityManager.identityId && self.currentSignInProvider) { 48 | return AWSIdentityManagerAuthStateAuthenticated; 49 | } else if (identityManager.identityId) { 50 | return AWSIdentityManagerAuthStateUnauthenticated; 51 | } 52 | return AWSIdentityManagerAuthStateUnknown; 53 | } 54 | 55 | -(void)registerAWSSignInProvider:(id)signInProvider { 56 | [signInProviderInfo setValue:signInProvider 57 | forKey:signInProvider.identityProviderName]; 58 | 59 | } 60 | 61 | -(id)signInProviderForKey:(NSString *)key { 62 | return [signInProviderInfo objectForKey:key]; 63 | } 64 | 65 | -(NSArray*)getRegisterdSignInProviders { 66 | return [signInProviderInfo allKeys]; 67 | } 68 | 69 | - (BOOL)isLoggedIn { 70 | return self.currentSignInProvider.isLoggedIn || self.potentialSignInProvider.isLoggedIn; 71 | } 72 | 73 | 74 | - (void)wipeAll { 75 | [identityManager.credentialsProvider clearKeychain]; 76 | } 77 | 78 | - (void)logoutWithCompletionHandler:(void (^)(id result, AWSIdentityManagerAuthState authState, NSError *error))completionHandler { 79 | if ([self.currentSignInProvider isLoggedIn]) { 80 | [self.currentSignInProvider logout]; 81 | [[AWSIdentityProfileManager sharedInstance] clearProfileForProviderKey:self.currentSignInProvider.identityProviderName]; 82 | } 83 | 84 | [self wipeAll]; 85 | 86 | self.currentSignInProvider = nil; 87 | 88 | [[identityManager.credentialsProvider getIdentityId] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { 89 | dispatch_async(dispatch_get_main_queue(), ^{ 90 | if (task.result) { 91 | completionHandler(task.result, AWSIdentityManagerAuthStateUnauthenticated, task.error); 92 | } else { 93 | completionHandler(task.result, AWSIdentityManagerAuthStateUnknown, task.error); 94 | } 95 | }); 96 | return nil; 97 | }]; 98 | } 99 | 100 | - (void)loginWithSignInProviderKey:(NSString *)signInProviderKey 101 | completionHandler:(void (^)(id result, AWSIdentityManagerAuthState authState, NSError *error))completionHandler { 102 | 103 | if ([self signInProviderForKey:signInProviderKey]) { 104 | self.potentialSignInProvider = [self signInProviderForKey:signInProviderKey]; 105 | } else { 106 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 107 | reason:@"The sign in provider is not registered as an available sign in provider. Please register using `registerAWSSignInProvider:`." 108 | userInfo:nil]; 109 | } 110 | 111 | self.completionHandler = completionHandler; 112 | [self.potentialSignInProvider login:completionHandler]; 113 | } 114 | 115 | - (void)resumeSessionWithCompletionHandler:(void (^)(id result, AWSIdentityManagerAuthState authState, NSError *error))completionHandler { 116 | 117 | self.completionHandler = completionHandler; 118 | 119 | for(NSString *key in [self getRegisterdSignInProviders]) { 120 | if ([[self signInProviderForKey:key] isLoggedIn]) { 121 | self.potentialSignInProvider = [self signInProviderForKey:key]; 122 | } 123 | } 124 | 125 | [self.potentialSignInProvider reloadSession]; 126 | 127 | if (self.potentialSignInProvider == nil) { 128 | [self completeLogin]; 129 | } 130 | } 131 | 132 | - (void)completeLogin { 133 | // Force a refresh of credentials to see if we need to merge unauth credentials. 134 | [identityManager.credentialsProvider invalidateCachedTemporaryCredentials]; 135 | 136 | if (self.potentialSignInProvider) { 137 | self.currentSignInProvider = self.potentialSignInProvider; 138 | self.potentialSignInProvider = nil; 139 | [[AWSIdentityProfileManager sharedInstance] loadProfileForProviderKey:self.currentSignInProvider.identityProviderName]; 140 | } 141 | 142 | [[identityManager.credentialsProvider credentials] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { 143 | dispatch_async(dispatch_get_main_queue(), ^{ 144 | // Retrieve and report the authorization state to the handler. 145 | AWSIdentityManagerAuthState authState = [AWSSignInManager sharedInstance].authState; 146 | self.completionHandler(task.result, authState, task.error); 147 | }); 148 | return nil; 149 | }]; 150 | } 151 | 152 | - (BOOL)interceptApplication:(UIApplication *)application 153 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 154 | for(NSString *key in [self getRegisterdSignInProviders]) { 155 | id signInProvider = [self signInProviderForKey:key]; 156 | if ([signInProvider conformsToProtocol:@protocol(AWSSignInProviderApplicationIntercept)]) { 157 | [(id)signInProvider interceptApplication:application 158 | didFinishLaunchingWithOptions:launchOptions]; 159 | } 160 | } 161 | 162 | return YES; 163 | } 164 | 165 | - (BOOL)interceptApplication:(UIApplication *)application 166 | openURL:(NSURL *)url 167 | sourceApplication:(NSString *)sourceApplication 168 | annotation:(id)annotation { 169 | if (self.potentialSignInProvider) { 170 | if ([self.potentialSignInProvider conformsToProtocol:@protocol(AWSSignInProviderApplicationIntercept)]) { 171 | id provider = (id)self.potentialSignInProvider; 172 | return [provider interceptApplication:application 173 | openURL:url 174 | sourceApplication:sourceApplication 175 | annotation:annotation]; 176 | } 177 | } 178 | 179 | return YES; 180 | } 181 | 182 | @end 183 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSSignInProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSignInProvider.h 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import 11 | #import 12 | #import "AWSIdentityProfile.h" 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | @class AWSIdentityManager; 17 | 18 | typedef NS_ENUM(NSInteger, AWSIdentityManagerAuthState) { 19 | AWSIdentityManagerAuthStateAuthenticated, 20 | AWSIdentityManagerAuthStateUnauthenticated, 21 | AWSIdentityManagerAuthStateUnknown, 22 | }; 23 | 24 | /** 25 | * `AWSSignInProvider` protocol defines a list of methods and properties which a Sign-In Provider should implement. 26 | * 27 | * The AWSSignInProvider is implemented by difference Sign-In Providers like FacbookSignInProvider, GoogleSignInProvider, etc. 28 | * 29 | */ 30 | @protocol AWSSignInProvider 31 | 32 | /** 33 | Determines if a user is logged in. 34 | */ 35 | @property (nonatomic, readonly, getter=isLoggedIn) BOOL loggedIn; 36 | 37 | /** 38 | The login handler method for the Sign-In Provider. 39 | The completionHandler will bubble back errors to the developers. 40 | */ 41 | - (void)login:(void (^)(id _Nullable result, AWSIdentityManagerAuthState authState, NSError * _Nullable error))completionHandler; 42 | 43 | /** 44 | The logout handler method for the Sign-In Provider. 45 | */ 46 | - (void)logout; 47 | 48 | /** 49 | The handler method for managing the session reload for the Sign-In Provider. 50 | The completionHandler will bubble back errors to the developers. 51 | */ 52 | - (void)reloadSession; 53 | 54 | @end 55 | 56 | NS_ASSUME_NONNULL_END 57 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/Authentication/AWSSignInProviderApplicationIntercept.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSignInProviderApplicationIntercept.h 3 | // AWSMobileHubHelper 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @protocol AWSSignInProviderApplicationIntercept 16 | 17 | /** 18 | * Passes parameters used to launch the application to the current identity provider. For some 19 | * third party providers, this completes the User Sign-in call flow, which used a browser to 20 | * get information from the user, directly. The current sign-in provider will be set to nil if 21 | * the sign-in provider is not registered using `registerAWSSignInProvider:forKey` method of 22 | * `AWSSignInProviderFactory` class. 23 | * @param application application 24 | * @param launchOptions options used to launch the application 25 | * @return true if this call handled the operation 26 | */ 27 | - (BOOL)interceptApplication:(UIApplication *)application 28 | didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions; 29 | 30 | /** 31 | * Passes parameters used to launch the application to the current identity provider. For some 32 | * third party providers, this completes the User Sign-in call flow, which used a browser to 33 | * get information from the user, directly. 34 | * @param application application 35 | * @param url url used to open the application 36 | * @param sourceApplication source application 37 | * @param annotation annotation 38 | * @return true if this call handled the operation 39 | */ 40 | - (BOOL)interceptApplication:(UIApplication *)application 41 | openURL:(NSURL *)url 42 | sourceApplication:(nullable NSString *)sourceApplication 43 | annotation:(id)annotation; 44 | 45 | @end 46 | 47 | NS_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/CloudLogic/AWSCloudLogic.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSCloudLogic.h 3 | // 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | /** 16 | * Cloud logic helper singleton class that provides convenient interface to invoke 17 | * AWS Lambda functions and handle the results asynchronously. 18 | * Requires the AWSLambda framework of AWSiOSSDK. 19 | */ 20 | @interface AWSCloudLogic : NSObject 21 | 22 | /** 23 | Returns the default Cloud Logic singleton instance configured using the information provided in `Info.plist` file. 24 | 25 | *Swift* 26 | 27 | let cloudLogic = AWSCloudLogic.default() 28 | 29 | *Objective-C* 30 | 31 | AWSCloudLogic *cloudLogic = [AWSCloudLogic defaultCloudLogic]; 32 | 33 | */ 34 | + (instancetype)defaultCloudLogic; 35 | 36 | /** 37 | Creates a helper client for `AWSCloud` for specified configuration with mentioned key. 38 | Use this method only if you require a helper client with specific configuration. 39 | 40 | For example, set the configuration in `- application:didFinishLaunchingWithOptions:` 41 | 42 | *Swift* 43 | 44 | let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") 45 | let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialProvider) 46 | 47 | AWSCloudLogic.register(with: configuration, forKey: "USWest2CloudLogic") 48 | 49 | *Objective-C* 50 | 51 | AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 52 | identityPoolId:@"YourIdentityPoolId"]; 53 | AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSWest2 54 | credentialsProvider:credentialsProvider]; 55 | [AWSCloudLogic registerCloudLogicWithConfiguration:configuration 56 | forKey:@"USWest2CloudLogic"]; 57 | 58 | Then call the following to get the helper client: 59 | 60 | *Swift* 61 | 62 | let cloudLogic = AWSCloudLogic(forKey: "USWest2CloudLogic") 63 | 64 | *Objective-C* 65 | 66 | AWSCloudLogic *cloudLogic = [AWSCloudLogic cloudLogicForKey:@"USWest2CloudLogic"]; 67 | 68 | @warning After calling this method, do not modify the configuration object. It may cause unspecified behaviors. 69 | 70 | @param serviceConfiguration AWSServiceConfiguration object for the cloud logic. 71 | @param key A string to identify the helper client. 72 | */ 73 | + (void)registerCloudLogicWithConfiguration:(AWSServiceConfiguration *)serviceConfiguration 74 | forKey:(NSString *)key; 75 | 76 | /** 77 | Retrieves the helper client associated with the key. You need to call `+ registercloudLogicWithConfiguration:` before invoking this method. If `+ registercloudLogicWithConfiguration:` has not been called in advance or the key does not exist, this method returns `nil`. 78 | 79 | *Swift* 80 | 81 | let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "YourIdentityPoolId") 82 | let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialProvider) 83 | 84 | AWSCloudLogic.registercloudLogicWithConfiguration(configuration, forKey: "USWest2cloudLogic") 85 | 86 | *Objective-C* 87 | 88 | AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 89 | identityPoolId:@"YourIdentityPoolId"]; 90 | AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSWest2 91 | credentialsProvider:credentialsProvider]; 92 | [AWSCloudLogic registercloudLogicWithConfiguration:configuration 93 | forKey:@"USWest2cloudLogic"]; 94 | 95 | Then call the following to get the helper client: 96 | 97 | *Swift* 98 | 99 | let CloudLogic = AWSCloudLogic(forKey: "USWest2cloudLogic") 100 | 101 | *Objective-C* 102 | 103 | AWSCloudLogic *CloudLogic = [AWSCloudLogic CloudLogicForKey:@"USWest2cloudLogic"]; 104 | 105 | @param key A string to identify the helper client. 106 | @return An instance of AWSCloudLogic for specified key. 107 | */ 108 | + (instancetype)CloudLogicForKey:(NSString *)key; 109 | 110 | /** 111 | Removes the helper client associated with the key and release it. 112 | 113 | *Swift* 114 | 115 | AWSCloudLogic.remove(forKey: "USWest2CloudLogic") 116 | 117 | *Objective-C* 118 | 119 | [AWSCloudLogic removeCloudLogicForKey:@"USWest2CloudLogic"]; 120 | 121 | @warning Before calling this method, make sure no method is running on this client. 122 | 123 | @param key A string to identify the helper client. 124 | */ 125 | + (void)removeCloudLogicForKey:(NSString *)key; 126 | 127 | /** 128 | Invokes the specified AWS Lambda function and passes the results and possible error back to the application asynchronously. 129 | 130 | @param name AWS Lambda function name, e.g., hello-world 131 | @param parameters The object from which to generate JSON request data. Can be `nil`. 132 | @param completionBlock handler for results from the function 133 | */ 134 | - (void)invokeFunction:(NSString *)name 135 | withParameters:(nullable id)parameters 136 | completionBlock:(void (^)(id _Nullable result, NSError * _Nullable error))completionBlock; 137 | 138 | @end 139 | 140 | NS_ASSUME_NONNULL_END 141 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/CloudLogic/AWSCloudLogic.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSCloudLogic.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | 10 | #import 11 | #import "AWSCloudLogic.h" 12 | #import 13 | 14 | @interface AWSCloudLogic () 15 | 16 | @property AWSLambdaInvoker *invoker; 17 | 18 | @end 19 | 20 | @interface AWSLambdaInvoker() 21 | 22 | - (instancetype)initWithConfiguration:(AWSServiceConfiguration *)configuration; 23 | 24 | @end 25 | 26 | @implementation AWSCloudLogic 27 | 28 | static NSString *const AWSInfoClougLogic = @"CloudLogic"; 29 | static AWSSynchronizedMutableDictionary *_serviceClients = nil; 30 | 31 | + (instancetype)defaultCloudLogic { 32 | AWSServiceConfiguration *serviceConfiguration = nil; 33 | AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] defaultServiceInfo:AWSInfoClougLogic]; 34 | if (serviceInfo) { 35 | serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region 36 | credentialsProvider:serviceInfo.cognitoCredentialsProvider]; 37 | } 38 | 39 | if (!serviceConfiguration) { 40 | serviceConfiguration = [AWSServiceManager defaultServiceManager].defaultServiceConfiguration; 41 | } 42 | 43 | static AWSCloudLogic *_defaultCloudLogic = nil; 44 | static dispatch_once_t onceToken; 45 | dispatch_once(&onceToken, ^{ 46 | _defaultCloudLogic = [[AWSCloudLogic alloc] initWithConfiguration:serviceConfiguration 47 | key:@"default"]; 48 | }); 49 | 50 | return _defaultCloudLogic; 51 | } 52 | 53 | - (instancetype)initWithConfiguration:(AWSServiceConfiguration *)configuration 54 | key:(NSString *)key { 55 | if (self = [super init]) { 56 | _invoker = [[AWSLambdaInvoker alloc] initWithConfiguration:configuration]; 57 | } 58 | return self; 59 | } 60 | 61 | 62 | + (void)registerCloudLogicWithConfiguration:(AWSServiceConfiguration *)serviceConfiguration 63 | forKey:(NSString *)key { 64 | if ([key isEqualToString:AWSInfoDefault]) { 65 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 66 | reason:@"The key used for registering this instance is a reserved key. Please use some other key to register the instance." 67 | userInfo:nil]; 68 | } 69 | static dispatch_once_t onceToken; 70 | dispatch_once(&onceToken, ^{ 71 | _serviceClients = [AWSSynchronizedMutableDictionary new]; 72 | }); 73 | 74 | [_serviceClients setObject:[[AWSCloudLogic alloc] initWithConfiguration:serviceConfiguration 75 | key:key] 76 | forKey:key]; 77 | 78 | } 79 | 80 | + (instancetype)CloudLogicForKey:(NSString *)key { 81 | @synchronized(self) { 82 | AWSCloudLogic *serviceClient = [_serviceClients objectForKey:key]; 83 | if (serviceClient) { 84 | return serviceClient; 85 | } 86 | 87 | AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] serviceInfo:AWSInfoClougLogic 88 | forKey:key]; 89 | if (serviceInfo) { 90 | AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region 91 | credentialsProvider:serviceInfo.cognitoCredentialsProvider]; 92 | [AWSCloudLogic registerCloudLogicWithConfiguration:serviceConfiguration 93 | forKey:key]; 94 | } 95 | 96 | return [_serviceClients objectForKey:key]; 97 | } 98 | } 99 | 100 | + (void)removeCloudLogicForKey:(NSString *)key { 101 | [_serviceClients removeObjectForKey:key]; 102 | } 103 | 104 | - (void)invokeFunction:(NSString *)name 105 | withParameters:(id)parameters 106 | completionBlock:(void (^)(id result, NSError *error))completionBlock { 107 | AWSLogDebug(@"invokeFunction: Function Name: %@", name); 108 | [_invoker invokeFunction:name 109 | JSONObject:parameters 110 | completionHandler:^(id _Nullable response, NSError * _Nullable error) { 111 | if (completionBlock) { 112 | completionBlock(response, error); 113 | } 114 | }]; 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /AWSMobileHubHelper/UserFiles/AWSUserFileManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSUserFileManager.m 3 | // 4 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 5 | // 6 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 7 | // copy, distribute and modify it. 8 | // 9 | #import "AWSUserFileManager.h" 10 | 11 | @protocol AWSUserFileProvider 12 | 13 | @required 14 | 15 | - (void)PUTURLForKey:(NSString *)key 16 | completionHandler:(void(^)(NSURL *URL, NSError *error))completionHandler; 17 | 18 | - (void)DELETEURLForKey:(NSString *)key 19 | completionHandler:(void (^)(NSURL *, NSError *))completionHandler; 20 | 21 | @end 22 | 23 | typedef NS_ENUM(NSInteger, AWSContentManagerType){ 24 | AWSContentManagerTypeS3, 25 | AWSContentManagerTypeCloudFront, 26 | }; 27 | 28 | @interface AWSContentManager() 29 | 30 | @property (nonatomic, strong) id contentProvider; 31 | @property (nonatomic, strong) NSURLSession *URLSession; 32 | @property (nonatomic, strong) NSMutableDictionary *runningTasks; 33 | 34 | @property (nonatomic, strong) NSMutableArray *uploadingContents; 35 | 36 | - (instancetype)initWithType:(AWSContentManagerType)type 37 | bucket:(NSString *)bucket 38 | cloudFrontURL:(NSString *)cloudFrontURL 39 | serviceConfiguration:(AWSServiceConfiguration *)serviceConfiguration 40 | identifier:(NSString *)identifier; 41 | 42 | @end 43 | 44 | @interface AWSContent() 45 | 46 | @property (nonatomic, strong) AWSContentManager *manager; 47 | @property (nonatomic, assign) AWSContentStatusType status; 48 | @property (nonatomic, strong) NSString *key; 49 | @property (nonatomic, assign) BOOL pinOnCompletion; 50 | 51 | @property (nonatomic, strong) NSData *uploadData; 52 | @property (nonatomic, copy) void(^uploadProgressBlock)(AWSLocalContent *content, NSProgress *progress); 53 | @property (nonatomic, copy) void(^uploadCompletionHandler)(AWSLocalContent *content, NSError *error); 54 | 55 | - (instancetype)initWithManager:(AWSContentManager *)manager; 56 | 57 | @end 58 | 59 | @interface AWSLocalContent() 60 | 61 | - (instancetype)initWithData:(NSData *)data 62 | key:(NSString *)key; 63 | 64 | - (instancetype)initWithManager:(AWSContentManager *)manager 65 | data:(NSData *)data 66 | key:(NSString *)key; 67 | 68 | @end 69 | 70 | @implementation AWSUserFileManager 71 | 72 | @dynamic uploadingContents; 73 | 74 | static NSString *const AWSInfoUserFileManager = @"UserFileManager"; 75 | static NSString *const AWSUserFileManagerBucketName = @"S3Bucket"; 76 | static AWSSynchronizedMutableDictionary *_serviceClients = nil; 77 | 78 | #pragma mark - Initializers 79 | 80 | + (instancetype)defaultUserFileManager { 81 | static AWSUserFileManager *_defaultUserFileManager = nil; 82 | static dispatch_once_t onceToken; 83 | dispatch_once(&onceToken, ^{ 84 | AWSServiceConfiguration *serviceConfiguration = nil; 85 | AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] defaultServiceInfo:AWSInfoUserFileManager]; 86 | 87 | if (serviceInfo) { 88 | serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region 89 | credentialsProvider:serviceInfo.cognitoCredentialsProvider]; 90 | } 91 | 92 | if (!serviceConfiguration) { 93 | serviceConfiguration = [AWSServiceManager defaultServiceManager].defaultServiceConfiguration; 94 | } 95 | 96 | NSString *bucketName = [serviceInfo.infoDictionary objectForKey:AWSUserFileManagerBucketName]; 97 | if (bucketName) { 98 | _defaultUserFileManager = [[AWSUserFileManager alloc] initWithType:AWSContentManagerTypeS3 99 | bucket:bucketName 100 | cloudFrontURL:nil 101 | serviceConfiguration:serviceConfiguration 102 | identifier:AWSInfoDefault]; 103 | } else { 104 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 105 | reason:@"The Push Manager specific configuration is set incorrectly in the `Info.plist` file. You need to configure `Info.plist` before using this method." 106 | userInfo:nil]; 107 | } 108 | }); 109 | 110 | return _defaultUserFileManager; 111 | } 112 | 113 | + (void)registerUserFileManagerWithConfiguration:(AWSUserFileManagerConfiguration *)userFileManagerConfiguration 114 | forKey:(NSString *)key { 115 | if ([key isEqualToString:AWSInfoDefault]) { 116 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 117 | reason:@"The key used for registering this instance is a reserved key. Please use some other key to register the instance." 118 | userInfo:nil]; 119 | } 120 | static dispatch_once_t onceToken; 121 | dispatch_once(&onceToken, ^{ 122 | _serviceClients = [AWSSynchronizedMutableDictionary new]; 123 | }); 124 | 125 | [_serviceClients setObject:[[AWSUserFileManager alloc] initWithType:AWSContentManagerTypeS3 126 | bucket:userFileManagerConfiguration.bucketName 127 | cloudFrontURL:nil 128 | serviceConfiguration:userFileManagerConfiguration.serviceConfiguration 129 | identifier:key] 130 | forKey:key]; 131 | } 132 | 133 | + (instancetype)UserFileManagerForKey:(NSString *)key { 134 | @synchronized(self) { 135 | AWSUserFileManager *serviceClient = [_serviceClients objectForKey:key]; 136 | if (serviceClient) { 137 | return serviceClient; 138 | } 139 | 140 | AWSServiceInfo *serviceInfo = [[AWSInfo defaultAWSInfo] serviceInfo:AWSInfoUserFileManager 141 | forKey:key]; 142 | if (serviceInfo) { 143 | AWSServiceConfiguration *serviceConfiguration = [[AWSServiceConfiguration alloc] initWithRegion:serviceInfo.region 144 | credentialsProvider:serviceInfo.cognitoCredentialsProvider]; 145 | NSString *bucketName = [serviceInfo.infoDictionary objectForKey:AWSUserFileManagerBucketName]; 146 | 147 | if (bucketName) { 148 | AWSUserFileManagerConfiguration *userFileManagerConfiguration = [[AWSUserFileManagerConfiguration alloc]initWithBucketName:bucketName 149 | serviceConfiguration:serviceConfiguration]; 150 | 151 | [AWSUserFileManager registerUserFileManagerWithConfiguration:userFileManagerConfiguration forKey:key]; 152 | } else { 153 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 154 | reason:@"The User File Manager specific configuration is set incorrectly in the `Info.plist` file. You need to configure `Info.plist` before using this method." 155 | userInfo:nil]; 156 | } 157 | } 158 | 159 | return [_serviceClients objectForKey:key]; 160 | } 161 | } 162 | 163 | + (void)removeUserFileManagerForKey:(NSString *)key { 164 | [_serviceClients removeObjectForKey:key]; 165 | } 166 | 167 | - (AWSLocalContent *)localContentWithData:(NSData *)data 168 | key:(NSString *)key { 169 | AWSLocalContent *localContent = [[AWSLocalContent alloc] initWithManager:self 170 | data:data 171 | key:key]; 172 | return localContent; 173 | } 174 | 175 | @end 176 | 177 | @implementation AWSUserFileManagerConfiguration 178 | 179 | @synthesize serviceConfiguration = _serviceConfiguration; 180 | 181 | - (instancetype)initWithBucketName:(NSString *)bucketName 182 | serviceConfiguration:(AWSServiceConfiguration *)serviceConfiguration { 183 | if (self = [super init]) { 184 | _bucketName = bucketName; 185 | _serviceConfiguration = serviceConfiguration; 186 | } 187 | return self; 188 | } 189 | 190 | - (instancetype)initWithBucketName:(NSString *)bucketName { 191 | return [[AWSUserFileManagerConfiguration alloc] initWithBucketName:bucketName 192 | serviceConfiguration:nil]; 193 | } 194 | 195 | - (AWSServiceConfiguration *)serviceConfiguration { 196 | if (!_serviceConfiguration) { 197 | return AWSServiceManager.defaultServiceManager.defaultServiceConfiguration; 198 | } 199 | 200 | return _serviceConfiguration; 201 | } 202 | 203 | @end 204 | -------------------------------------------------------------------------------- /AWSSamlSignIn/AWSSAMLSignInProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSAMLSignInProvider.h 3 | // AWSSamlSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | NS_ASSUME_NONNULL_BEGIN 15 | 16 | /** 17 | * Any class over-riding the `AWSSAMLSignInProvider` class for implemeting `SAML` as a sign-in provider, 18 | * should also adopt the `AWSSAMLSignInProviderInstance` protocol. 19 | */ 20 | @protocol AWSSAMLSignInProviderInstance 21 | 22 | /** 23 | * The shared instance of the class implementing `SAML` as a sign-in provider. 24 | * 25 | * @return the shared instance of the class implementing `SAML` as a sign-in provider. 26 | */ 27 | + (id)sharedInstance; 28 | 29 | @end 30 | 31 | @interface AWSSAMLSignInProvider : NSObject 32 | 33 | #pragma mark - Initializer 34 | 35 | /* 36 | The only initializer for AWSSAMLSignInProvider. This initializer has to be used by the class over-riding AWSSAMLSignInProvider. 37 | @param uniqueIdentifier The unique identifier string for the SAML Sign In Provider 38 | @param identityProviderName The identifier provider name for SAML provider (the Identity Provider ARN for SAML) 39 | @return instance of AWSSAMLSignInProvider 40 | */ 41 | - (instancetype)initWithIdentifier:(NSString *)uniqueIdentifier 42 | identityProviderName:(NSString *)identityProviderName; 43 | 44 | #pragma mark - Mandatory Override Methods 45 | 46 | // The user is expected to over the methods in this pragma mark 47 | 48 | /** 49 | * This method will be called when `loginWithSignInProvider` is invoked from `AWSIdentityManager`. 50 | * Developer is expected to call `setResult` on `taskCompletionSource` with the SAML login token on a successful login, 51 | * or `setError` when the login is cancelled or encounters an error. 52 | * 53 | * The token internally is stored in the keychain store, and a flag is set in `NSUserDefaults` indicating the user is logged in using this `SAML` sign-in provider. 54 | * 55 | * ** Objective-C *** 56 | * - (void)handleLoginWithTaskCompletionSource:(AWSTaskCompletionSource *)taskCompletionSource { 57 | * // handle login logic 58 | * if(loginSuccessful) { 59 | * [taskCompletionSource setResult:@"SuccessfullyGeneratedToken"]; 60 | * } else { 61 | * [taskCompletionSource setError:error]; 62 | * } 63 | * } 64 | * 65 | * ** Swift ** 66 | * func handleLogicWithTaskCompletionSource(taskCompletionSource: AWSTaskCompletionSource) { 67 | * if(loginSuccessful) { 68 | * taskCompletionSource.setResult("SuccessfullyGeneratedToken") 69 | * } else { 70 | * taskCompletionSource.setError(error) 71 | * } 72 | * } 73 | * 74 | * @param taskCompletionSource the `AWSTaskCompletionSource` object which is used to call `setResult` or `setError` 75 | */ 76 | - (void)handleLoginWithTaskCompletionSource:(AWSTaskCompletionSource *)taskCompletionSource; 77 | 78 | /** 79 | * This method is called whenver the cognito credentials are refreshed or when app is loaded from background state / closed state. 80 | * The previous saved token can be fetched using `fetchStoredToken`, and if it is valid the same can be returned without refreshing. 81 | * 82 | * @return an instance of `AWSTask`. `task.result` should contain the valid token in case of successful token fetch, or `task.error` should be set 83 | */ 84 | - (AWSTask*)fetchLatestToken; 85 | 86 | #pragma mark - Optional Override Methods 87 | 88 | /** 89 | * Passes parameters used to launch the application to the current identity provider. 90 | * It can be used to complete the user sign-in call flow, which uses a browser to 91 | * get information from the user, directly. The current sign-in provider will be set to nil if 92 | * the sign-in provider is not registered using `registerAWSSignInProvider:forKey` method of 93 | * `AWSSignInProviderFactory` class. 94 | * 95 | * @param application application 96 | * @param launchOptions options used to launch the application 97 | * @return true if this call handled the operation 98 | */ 99 | - (BOOL)interceptApplication:(UIApplication *)application 100 | didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions; 101 | 102 | /** 103 | * Passes parameters used to launch the application to the current identity provider. 104 | * It can be used to complete the user sign-in call flow, which uses a browser to 105 | * get information from the user, directly. The developer should store a reference to 106 | * the `taskCompletionSource` instance provided by the `handleLoginWithTaskCompletionSouce` 107 | * method to set the result with successfully retrieved token. 108 | * 109 | * @param application application 110 | * @param url url used to open the application 111 | * @param sourceApplication source application 112 | * @param annotation annotation 113 | * @return true if this call handled the operation 114 | */ 115 | - (BOOL)interceptApplication:(UIApplication *)application 116 | openURL:(NSURL *)url 117 | sourceApplication:(nullable NSString *)sourceApplication 118 | annotation:(id)annotation; 119 | 120 | #pragma mark - Instance Methods 121 | 122 | /** 123 | * Can be used to store a reference of teh view controller from which `loginWithSignInProvider` is invoked by `AWSIdentityManager` 124 | * 125 | * @param signInViewController the signInViewController object whose reference needs to be stored 126 | */ 127 | - (void)setViewControllerForSignIn:(UIViewController *)signInViewController; 128 | 129 | /** 130 | * This method returns the view controller whose reference was stored using `setViewControllerForSignIn` 131 | * 132 | * @return the stored view controller if set, else `nil` 133 | */ 134 | - (UIViewController *)getViewControllerForSignIn; 135 | 136 | /** 137 | * Returns the token stored in keychain as-is (without refreshing) 138 | * 139 | * @return the token if available in keychain, else `nil` 140 | */ 141 | - (NSString *)fetchStoredToken; 142 | 143 | /** 144 | * Determines if the user is logged in based on the token available in keychain and if the login flag is set internally. 145 | * 146 | * @return `YES` if the user is logged in using `SAML` sign-in provider instance 147 | */ 148 | - (BOOL)isLoggedIn; 149 | 150 | @end 151 | 152 | NS_ASSUME_NONNULL_END 153 | -------------------------------------------------------------------------------- /AWSSamlSignIn/AWSSAMLSignInProvider.m: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSAMLSignInProvider.m 3 | // AWSSamlSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSSAMLSignInProvider.h" 12 | #import "AWSSignInManager.h" 13 | #import 14 | 15 | static NSString *const AWSSAMLSignInProviderUserNameKeySuffix = @"SAML.userName"; 16 | static NSString *const AWSSAMLSignInProviderImageURLKeySuffix = @"SAML.imageURL"; 17 | static NSString *const AWSSAMLSignInProviderTokenSuffix = @"SAML.loginToken"; 18 | 19 | typedef void (^AWSSignInManagerCompletionBlock)(id result, AWSIdentityManagerAuthState authState, NSError *error); 20 | 21 | @interface AWSSignInManager() 22 | 23 | - (void)completeLogin; 24 | 25 | @end 26 | 27 | @interface AWSSAMLSignInProvider() 28 | 29 | @property (strong, nonatomic) NSString *uniqueIdentfier; 30 | @property (strong, nonatomic) NSString *samlIdentityProviderName; 31 | @property (nonatomic, strong) AWSUICKeyChainStore *keychain; 32 | @property (strong, nonatomic) NSString *userName; 33 | @property (strong, nonatomic) NSURL *imageURL; 34 | @property (atomic, copy) AWSSignInManagerCompletionBlock completionHandler; 35 | @property (nonatomic, strong) UIViewController *signInViewController; 36 | 37 | @end 38 | 39 | @implementation AWSSAMLSignInProvider 40 | 41 | - (instancetype)init { 42 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 43 | reason:@"`- init` is not a valid initializer. This class is to be used as an abstract base class for SAML sign in provider." 44 | userInfo:nil]; 45 | return nil; 46 | } 47 | 48 | - (instancetype)initWithIdentifier:(NSString *)uniqueIdentifier 49 | identityProviderName:(NSString *)identityProviderName { 50 | if (self = [super init]) { 51 | if (!uniqueIdentifier || [uniqueIdentifier length] == 0) { 52 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 53 | reason:@"The value of `uniqueIdentifier` cannot be `nil` or empty string." 54 | userInfo:nil]; 55 | } 56 | _uniqueIdentfier = uniqueIdentifier; 57 | _samlIdentityProviderName = identityProviderName; 58 | _keychain = [AWSUICKeyChainStore keyChainStoreWithService:[NSString stringWithFormat:@"SAML.%@", _uniqueIdentfier]]; 59 | _signInViewController = nil; 60 | } 61 | 62 | return self; 63 | } 64 | 65 | #pragma mark - AWSIdentityProvider 66 | 67 | - (NSString *)identityProviderName { 68 | return self.samlIdentityProviderName; 69 | } 70 | 71 | - (AWSTask *)token { 72 | return [self fetchLatestToken]; 73 | } 74 | 75 | #pragma mark - Instance Methods 76 | 77 | - (BOOL)isLoggedIn { 78 | return [self fetchStoredToken]; 79 | } 80 | 81 | - (void)reloadSession { 82 | if ([self isLoggedIn]) { 83 | [[self fetchLatestToken] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { 84 | if (task.result) { 85 | [self completeLogin]; 86 | } else if (task.error) { 87 | AWSLogError(@"Could not reload the session. Refreshed token missing."); 88 | } 89 | return nil; 90 | }]; 91 | } 92 | } 93 | 94 | - (void)completeLogin { 95 | [[AWSSignInManager sharedInstance] completeLogin]; 96 | } 97 | 98 | - (void)saveToken:(NSString *)token { 99 | self.keychain[[self stringWithUniqueIdentifierPrefix:AWSSAMLSignInProviderTokenSuffix]] = token; 100 | } 101 | 102 | - (void)deleteToken { 103 | [self.keychain removeItemForKey:[self stringWithUniqueIdentifierPrefix:AWSSAMLSignInProviderTokenSuffix]]; 104 | } 105 | 106 | - (NSString *)fetchStoredToken { 107 | return self.keychain[[self stringWithUniqueIdentifierPrefix:AWSSAMLSignInProviderTokenSuffix]]; 108 | } 109 | 110 | - (void)login:(AWSSignInManagerCompletionBlock)completionHandler { 111 | self.completionHandler = completionHandler; 112 | AWSTaskCompletionSource *taskCompletionSource = [AWSTaskCompletionSource taskCompletionSource]; 113 | 114 | [self handleLoginWithTaskCompletionSource:taskCompletionSource]; 115 | [taskCompletionSource.task continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) { 116 | AWSIdentityManagerAuthState authState = [AWSSignInManager sharedInstance].authState; 117 | if(task.error){ 118 | self.completionHandler(nil, authState, task.error); 119 | } else { 120 | [self completeLoginWithToken:task.result]; 121 | } 122 | return nil; 123 | }]; 124 | } 125 | 126 | - (void)completeLoginWithToken:(NSString *)token { 127 | [self saveToken:token]; 128 | [self completeLogin]; 129 | } 130 | 131 | - (void)cancelLoginWithError:(NSError *)error { 132 | AWSIdentityManagerAuthState authState = [AWSSignInManager sharedInstance].authState; 133 | self.completionHandler(nil, authState, error); 134 | } 135 | 136 | - (void)logout { 137 | [self deleteToken]; 138 | } 139 | 140 | - (void)setViewControllerForSignIn:(UIViewController *)signInViewController { 141 | self.signInViewController = signInViewController; 142 | } 143 | 144 | - (UIViewController *)getViewControllerForSignIn { 145 | return self.signInViewController; 146 | } 147 | 148 | #pragma mark - Mandatory Override Methods 149 | 150 | - (void)handleLoginWithTaskCompletionSource:(AWSTaskCompletionSource *)taskCompletionSource { 151 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 152 | reason:@"`-handleLoginWithTaskCompletionSource` cannot be called for the base `AWSSAMLSignInProvider` class. This method has to be over-ridden in the class extending AWSSAMLSignInProvider." 153 | userInfo:nil]; 154 | } 155 | 156 | - (AWSTask*)fetchLatestToken { 157 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 158 | reason:@"`-fetchLatestToken` cannot be called for the base `AWSSAMLSignInProvider` class. This method has to be over-ridden in the class extending AWSSAMLSignInProvider." 159 | userInfo:nil]; 160 | return nil; 161 | } 162 | 163 | #pragma mark - Optional Override Methods 164 | 165 | - (BOOL)interceptApplication:(UIApplication *)application 166 | openURL:(NSURL *)url 167 | sourceApplication:(nullable NSString *)sourceApplication 168 | annotation:(id)annotation { 169 | return YES; 170 | } 171 | 172 | - (BOOL)interceptApplication:(UIApplication *)application 173 | didFinishLaunchingWithOptions:(nullable NSDictionary *)launchOptions { 174 | return YES; 175 | } 176 | 177 | #pragma mark - Helper Method 178 | 179 | - (NSString *)stringWithUniqueIdentifierPrefix:(NSString *)suffix { 180 | return [self.uniqueIdentfier stringByAppendingString: [NSString stringWithFormat:@".%@", suffix]]; 181 | } 182 | 183 | @end 184 | -------------------------------------------------------------------------------- /AWSSamlSignIn/AWSSamlSignIn.h: -------------------------------------------------------------------------------- 1 | // 2 | // AWSSamlSignIn.h 3 | // AWSSamlSignIn 4 | // 5 | // Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved. 6 | // 7 | // Code generated by AWS Mobile Hub. Amazon gives unlimited permission to 8 | // copy, distribute and modify it. 9 | // 10 | 11 | #import "AWSSAMLSignInProvider.h" 12 | -------------------------------------------------------------------------------- /AWSSamlSignIn/AWSSamlSignIn.modulemap: -------------------------------------------------------------------------------- 1 | framework module AWSSamlSignIn { 2 | umbrella header "AWSSamlSignIn.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | platform :ios, '9.0' 4 | 5 | target 'AWSMobileHubHelper' do 6 | pod 'AWSSNS', '~>2.5.0' 7 | pod 'AWSS3', '~>2.5.0' 8 | pod 'AWSLambda', '~>2.5.0' 9 | end 10 | 11 | target 'AWSFacebookSignIn' do 12 | pod 'FBSDKLoginKit', '~> 4.13.1' 13 | pod 'FBSDKCoreKit', '~> 4.13.1' 14 | pod 'AWSCore', '~>2.5.0' 15 | end 16 | 17 | target 'AWSGoogleSignIn' do 18 | pod 'AWSCore', '~>2.5.0' 19 | pod 'GoogleSignIn', '~> 4.0.0' 20 | end 21 | 22 | target 'AWSSamlSignIn' do 23 | pod 'AWSCore', '~>2.5.0' 24 | end 25 | 26 | target 'AWSCognitoUserPoolsSignIn' do 27 | pod 'AWSCognitoIdentityProvider', '~>2.5.0' 28 | end 29 | 30 | target 'AWSMobileHubAuthorizers' do 31 | pod 'AWSCore', '~>2.5.0' 32 | end 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Mobile Hub Helper for iOS 2 | 3 | The AWS Mobile Hub simplifies the process of building, testing, and monitoring mobile applications that make use of one or more AWS services. It helps you skip the heavy lifting of integrating and configuring services by letting you add and configure features to your apps, including user authentication, data storage, backend logic, push notifications, content delivery, and analytics—all from a single, integrated console. 4 | 5 | This helper code is the source for the AWSMobileHubHelper.framework file which is included with every Objective C and Swift application download from AWS Mobile Hub. 6 | 7 | * [API Docs](https://docs.aws.amazon.com/awsmobilehubhelper/apireference/latest/index.html) 8 | * [Forums](https://forums.aws.amazon.com/forum.jspa?forumID=88) 9 | * [Issues](https://github.com/aws/aws-sdk-ios/issues) 10 | 11 | ## Distribution 12 | 13 | You can download the framework along with the sample app from the mobile hub [console](https://console.aws.amazon.com/mobilehub) under the build section. The framework is currently distributed as a static library. 14 | 15 | ## Building framework from source 16 | 17 | You can build the framework from source using the [Script](Scripts/GenerateHelperFramework.sh). The API reference documentation can be generated using the [Script](Scripts/GenerateHelperFrameworkDocs.sh). 18 | 19 | ## Integrating the framework into XCode 20 | 21 | If you have downloaded the AWSMobileHubHelper from the mobile hub [console](https://console.aws.amazon.com/mobilehub), follow the steps 1-4, otherwise jump to Step 5. 22 | 23 | 1. Locate the custom SDK and source code you downloaded. 24 | 2. Drag and drop the `AmazonAws` folder into the `Navigator` pane in XCode. 25 | 3. When prompted, choose **Copy items if needed** and then choose **Create groups**. 26 | 4. Choose **Finish**. 27 | 5. Open the target for your project. 28 | 6. Select General. 29 | 7. Expand **Linked Frameworks and Libraries** and choose the **+** symbol to select frameworks. 30 | 8. Add `AWSMobileHubHelper.framework`. 31 | 9. Optionally add other frameworks that need to be statically linked under the **Linked Frameworks and Libraries** section. 32 | 33 | ## Submitting Pull Requests 34 | 35 | At this time we are accepting pull requests only for Bug fixes (one bug fix per requests). For new features please submit feedback on the [mobile hub console](https://console.aws.amazon.com/mobilehub/home) (link for feedback on the bottom left corner). Please make sure that your pull requests comply with the license. 36 | -------------------------------------------------------------------------------- /Scripts/GenerateAllFrameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -x "Scripts/GenerateHelperFramework.sh" ]; then 4 | # clean up build folder 5 | rm -rf builtFramework 6 | echo "Cleaning Completed" 7 | # start building all frameworks 8 | Scripts/GenerateHelperFramework.sh AWSMobileHubHelper 9 | Scripts/GenerateHelperFramework.sh AWSFacebookSignIn 10 | Scripts/GenerateHelperFramework.sh AWSGoogleSignIn 11 | Scripts/GenerateHelperFramework.sh AWSSamlSignIn 12 | Scripts/GenerateHelperFramework.sh AWSCognitoUserPoolsSignIn 13 | Scripts/GenerateHelperFramework.sh AWSMobileHubAuthorizers 14 | fi 15 | -------------------------------------------------------------------------------- /Scripts/GenerateHelperFramework.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -u 3 | 4 | # Helper function to exit on nonzero code 5 | function exitOnFailureCode() { 6 | if [ $1 -ne 0 ] 7 | then 8 | echo "Error occurred, abort" 9 | exit $1 10 | fi 11 | } 12 | 13 | ############################################# 14 | ############################################# 15 | 16 | if [ $# -eq 0 ] 17 | then 18 | echo "No argument supplied, need to specified the name of the project. e.g. GenerateHelperFramework.sh AWSFacebookSignIn" 19 | exit 1 20 | fi 21 | 22 | project_name=$1 23 | project_path=. 24 | 25 | # Define these to suit your nefarious purposes 26 | CURR_DIR=$(PWD) 27 | FRAMEWORK_NAME="${project_name}" 28 | FRAMEWORK_VERSION=1.0.0 29 | 30 | # Where we'll put the build framework. 31 | # The script presumes we're in the project root 32 | # directory. Xcode builds in "build" by default 33 | FRAMEWORK_BUILD_PATH="builtFramework/framework" 34 | 35 | 36 | # Clean any existing framework that might be there 37 | # already 38 | echo "Framework: Cleaning framework..." 39 | if [ -d "$FRAMEWORK_BUILD_PATH" ] 40 | then 41 | rm -rf "$FRAMEWORK_BUILD_PATH/$FRAMEWORK_NAME.framework" 42 | fi 43 | 44 | # Build .a files 45 | xcodebuild ARCHS="armv7 armv7s arm64 i386 x86_64" \ 46 | ONLY_ACTIVE_ARCH=NO \ 47 | OTHER_CFLAGS="-fembed-bitcode" \ 48 | -configuration Debug \ 49 | -workspace "${project_path}/AWSMobileHubHelper.xcworkspace" \ 50 | -scheme "${project_name}" \ 51 | -sdk iphonesimulator \ 52 | SYMROOT=$(PWD)/builtFramework \ 53 | clean build 54 | 55 | exitOnFailureCode $? 56 | 57 | xcodebuild ARCHS="armv7 armv7s arm64 i386 x86_64" \ 58 | ONLY_ACTIVE_ARCH=NO \ 59 | OTHER_CFLAGS="-fembed-bitcode" \ 60 | -configuration Release \ 61 | -workspace "${project_path}/AWSMobileHubHelper.xcworkspace" \ 62 | -scheme "${project_name}" \ 63 | -sdk iphoneos \ 64 | SYMROOT=$(PWD)/builtFramework \ 65 | clean build 66 | 67 | exitOnFailureCode $? 68 | 69 | # This is the full name of the framework we'll 70 | # build 71 | FRAMEWORK_DIR=$FRAMEWORK_BUILD_PATH/$FRAMEWORK_NAME.framework 72 | 73 | # clean up old framework directory if exists 74 | rm -rf $FRAMEWORK_DIR 75 | 76 | # Build the canonical Framework bundle directory 77 | # structure 78 | echo "Framework: Setting up directories..." 79 | mkdir -p $FRAMEWORK_DIR 80 | mkdir -p $FRAMEWORK_DIR/Modules 81 | mkdir -p $FRAMEWORK_DIR/Headers 82 | 83 | # The trick for creating a fully usable library is 84 | # to use lipo to glue the different library 85 | # versions together into one file. When an 86 | # application is linked to this library, the 87 | # linker will extract the appropriate platform 88 | # version and use that. 89 | # The library file is given the same name as the 90 | # framework with no .a extension. 91 | echo "Framework: Creating library..." 92 | lipo -create \ 93 | "builtFramework/Debug-iphonesimulator/lib${project_name}.a" \ 94 | "builtFramework/Release-iphoneos/lib${project_name}.a" \ 95 | -o "$FRAMEWORK_DIR/$FRAMEWORK_NAME" 96 | 97 | exitOnFailureCode $? 98 | 99 | # Now copy the final assets over: your library 100 | # header files and service definition json files 101 | echo "Framework: Copying public headers into current version..." 102 | #those headers are declared in xcode's building phase: Headers 103 | cp -a builtFramework/Release-iphoneos/include/${project_name}/*.h $FRAMEWORK_DIR/Headers/ 104 | exitOnFailureCode $? 105 | 106 | echo "Framework: Copying the module map into current version..." 107 | #those headers are declared in xcode's building phase: Headers 108 | cp -a builtFramework/Release-iphoneos/include/${project_name}/${project_name}.modulemap $FRAMEWORK_DIR/Modules/module.modulemap 109 | exitOnFailureCode $? 110 | -------------------------------------------------------------------------------- /Scripts/GenerateHelperFrameworkDocs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | # remove everything generated by this script 5 | function cleanup 6 | { 7 | rm -rf helperdocs 8 | rm -rf HelperDocumentation 9 | } 10 | 11 | 12 | VERSION="1.0.0" 13 | if [ -n $1 ] && [ "$1" == "clean" ]; 14 | then 15 | cleanup 16 | exit 0 17 | else 18 | cd "$SOURCE_ROOT" 19 | 20 | if [ -d docs ]; 21 | then 22 | cleanup 23 | fi 24 | 25 | rm -rf docs_tmp 26 | mkdir -p docs 27 | mkdir -p docs_tmp 28 | 29 | 30 | cp -r AWSMobileHubHelper ./docs_tmp/AWSMobileHubHelper 31 | cp -r AWSFacebookSignIn ./docs_tmp/AWSFacebookSignIn 32 | cp -r AWSGoogleSignIn ./docs_tmp/AWSGoogleSignIn 33 | cp -r AWSSamlSignIn ./docs_tmp/AWSSamlSignIn 34 | cp -r AWSCognitoUserPoolsSignIn ./docs_tmp/AWSCognitoUserPoolsSignIn 35 | cp -r AWSMobileHubAuthorizers ./docs_tmp/AWSMobileHubAuthorizers 36 | 37 | cd docs_tmp 38 | 39 | rm -rf AWSMobileHubHelper/Facebook 40 | rm -rf AWSMobileHubHelper/Google 41 | 42 | # generate documenation 43 | appledoc --verbose 0 \ 44 | --output ../docs \ 45 | --exit-threshold 2 \ 46 | --no-repeat-first-par \ 47 | --explicit-crossref \ 48 | --docset-install-path ../docs \ 49 | --docset-bundle-filename com.amazon.aws.ios.mobilehub.helper.docset \ 50 | --company-id aws.amazon.com \ 51 | --project-name "AWS iOS Mobile Hub Helper Library v${VERSION}" \ 52 | --project-version "${VERSION}" \ 53 | --project-company "Amazon Web Services, Inc." \ 54 | --create-html \ 55 | --finalize-docset \ 56 | --keep-intermediate-files \ 57 | --index-desc ../aws-ios-mobile-hub-helper.markdown \ 58 | ./ 59 | 60 | # get command execution result 61 | result=$? 62 | 63 | if [ $result != 0 ]; 64 | then 65 | echo "Building the AWS Mobile Hub Helper documentation FAILED!" 66 | cleanup; 67 | exit 1; 68 | fi 69 | 70 | cd .. 71 | 72 | # pack html doc into a zip file 73 | (cd docs/html; zip -q -r --symlinks ../aws-ios-mobilehub-helper-docs.zip .) 74 | 75 | 76 | rm -rf Documentation 77 | mkdir Documentation 78 | mv docs/html Documentation 79 | mv docs/com.amazon.aws.ios.mobilehub.helper.docset Documentation 80 | mv docs/aws-ios-mobilehub-helper-docs.zip Documentation 81 | rm -rf docs 82 | rm -rf docs_tmp 83 | 84 | exit 0 85 | fi 86 | -------------------------------------------------------------------------------- /aws-ios-mobile-hub-helper.markdown: -------------------------------------------------------------------------------- 1 | The AWS iOS Mobile Hub Helper provides a helper library written on top of AWS iOS SDK for developers to build connected applications for iPad, iPhone, or iPod touch devices using Amazon Web Services. It provides multiple utilities which are descibed in this API Reference. It also includes code snippets describing how to use the functions available in framework. 2 | 3 | It is recommended that you configure your project through AWS Mobile Hub for appropriate configuration and settings for using the below utilities. --------------------------------------------------------------------------------