|
18 | 18 | #import "UICKeyChainStore.h"
|
19 | 19 | #import "AWSLogging.h"
|
20 | 20 |
|
21 |
| -NSString *const AWSCognitoIdentityIdChangedNotification = @"com.amazonaws.services.cognitoidentity.AWSCognitoIdentityIdChangedNotification"; |
22 |
| -NSString *const AWSCognitoNotificationPreviousId = @"PREVID"; |
23 |
| -NSString *const AWSCognitoNotificationNewId = @"NEWID"; |
24 | 21 | NSString *const AWSCognitoCredentialsProviderErrorDomain = @"com.amazonaws.AWSCognitoCredentialsProviderErrorDomain";
|
25 | 22 |
|
26 | 23 | @interface AWSStaticCredentialsProvider()
|
@@ -180,12 +177,8 @@ - (NSDate *)expiration {
|
180 | 177 |
|
181 | 178 | @interface AWSCognitoCredentialsProvider()
|
182 | 179 |
|
183 |
| -@property (nonatomic, strong) NSString *openIdToken; |
184 |
| -@property (nonatomic, strong) NSString *accountId; |
185 |
| -@property (nonatomic, strong) NSString *identityPoolId; |
186 | 180 | @property (nonatomic, strong) NSString *authRoleArn;
|
187 | 181 | @property (nonatomic, strong) NSString *unAuthRoleArn;
|
188 |
| -@property (nonatomic, strong) AWSCognitoIdentity *cib; |
189 | 182 | @property (nonatomic, strong) AWSSTS *sts;
|
190 | 183 | @property (nonatomic, strong) UICKeyChainStore *keychain;
|
191 | 184 |
|
@@ -241,98 +234,93 @@ + (instancetype)credentialsWithRegionType:(AWSRegionType)regionType
|
241 | 234 | return credentials;
|
242 | 235 | }
|
243 | 236 |
|
| 237 | ++ (instancetype)credentialsWithRegionType:(AWSRegionType)regionType |
| 238 | + identityProvider:(id<AWSCognitoIdentityProvider>)identityProvider |
| 239 | + unauthRoleArn:(NSString *)unauthRoleArn |
| 240 | + authRoleArn:(NSString *)authRoleArn { |
| 241 | + |
| 242 | + AWSCognitoCredentialsProvider *credentials = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:regionType |
| 243 | + identityProvider:identityProvider |
| 244 | + unauthRoleArn:unauthRoleArn |
| 245 | + authRoleArn:authRoleArn]; |
| 246 | + return credentials; |
| 247 | +} |
| 248 | + |
| 249 | + |
244 | 250 | - (instancetype)initWithRegionType:(AWSRegionType)regionType
|
245 | 251 | identityId:(NSString *)identityId
|
246 | 252 | accountId:(NSString *)accountId
|
247 | 253 | identityPoolId:(NSString *)identityPoolId
|
248 | 254 | unauthRoleArn:(NSString *)unauthRoleArn
|
249 | 255 | authRoleArn:(NSString *)authRoleArn
|
250 | 256 | logins:(NSDictionary *)logins {
|
| 257 | + |
| 258 | + // check for a stored identity if one isn't explicitly set |
| 259 | + if (!identityId) { |
| 260 | + UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:[NSString stringWithFormat:@"%@.%@.%@", [NSBundle mainBundle].bundleIdentifier, [AWSCognitoCredentialsProvider class], identityPoolId]]; |
| 261 | + identityId = keychain[@"identityId"]; |
| 262 | + } |
| 263 | + |
| 264 | + AWSBasicCognitoIdentityProvider *identityProvider = [[AWSBasicCognitoIdentityProvider alloc] |
| 265 | + initWithRegionType:regionType |
| 266 | + identityId:identityId |
| 267 | + accountId:accountId |
| 268 | + identityPoolId:identityPoolId |
| 269 | + logins:logins]; |
| 270 | + |
| 271 | + |
| 272 | + AWSCognitoCredentialsProvider *credentials = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:regionType |
| 273 | + identityProvider:identityProvider |
| 274 | + unauthRoleArn:unauthRoleArn |
| 275 | + authRoleArn:authRoleArn]; |
| 276 | + |
| 277 | + return credentials; |
| 278 | +} |
| 279 | + |
| 280 | +- (instancetype)initWithRegionType:(AWSRegionType)regionType |
| 281 | + identityProvider:(id<AWSCognitoIdentityProvider>) identityProvider |
| 282 | + unauthRoleArn:(NSString *)unauthRoleArn |
| 283 | + authRoleArn:(NSString *)authRoleArn { |
251 | 284 | if (self = [super init]) {
|
252 |
| - _accountId = accountId; |
253 |
| - _identityPoolId = identityPoolId; |
254 | 285 | _unAuthRoleArn = unauthRoleArn;
|
255 | 286 | _authRoleArn = authRoleArn;
|
256 |
| - _logins = [self updateKeysForLogins:logins]; |
257 |
| - |
| 287 | + _identityProvider = identityProvider; |
| 288 | + |
258 | 289 | // initialize keychain - name spaced by app bundle and identity pool id
|
259 |
| - _keychain = [UICKeyChainStore keyChainStoreWithService:[NSString stringWithFormat:@"%@.%@.%@", [NSBundle mainBundle].bundleIdentifier, [AWSCognitoCredentialsProvider class], identityPoolId]]; |
260 |
| - if (identityId) { |
261 |
| - _keychain[@"identityId"] = identityId; |
| 290 | + _keychain = [UICKeyChainStore keyChainStoreWithService:[NSString stringWithFormat:@"%@.%@.%@", [NSBundle mainBundle].bundleIdentifier, [AWSCognitoCredentialsProvider class], identityProvider.identityPoolId]]; |
| 291 | + if (identityProvider.identityId) { |
| 292 | + _keychain[@"identityId"] = identityProvider.identityId; |
262 | 293 | [_keychain synchronize];
|
263 | 294 | }
|
264 |
| - |
| 295 | + |
265 | 296 | AWSAnonymousCredentialsProvider *credentialsProvider = [AWSAnonymousCredentialsProvider new];
|
266 | 297 | AWSServiceConfiguration *configuration = [AWSServiceConfiguration configurationWithRegion:regionType
|
267 | 298 | credentialsProvider:credentialsProvider];
|
268 |
| - |
269 |
| - _cib = [[AWSCognitoIdentity new] initWithConfiguration:configuration]; |
| 299 | + |
270 | 300 | _sts = [[AWSSTS new] initWithConfiguration:configuration];
|
271 | 301 | }
|
272 |
| - |
| 302 | + |
273 | 303 | return self;
|
274 | 304 | }
|
275 | 305 |
|
276 | 306 | - (BFTask *)refresh {
|
277 | 307 | dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
|
278 | 308 |
|
279 |
| - return [[[[[[BFTask taskWithResult:nil] continueWithSuccessBlock:^id(BFTask *task) { |
| 309 | + return [[[[BFTask taskWithResult:nil] continueWithSuccessBlock:^id(BFTask *task) { |
280 | 310 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
281 |
| - return [self getIdentityId]; |
282 |
| - }] continueWithSuccessBlock:^id(BFTask *task) { |
283 |
| - AWSCognitoIdentityGetOpenIdTokenInput *getTokenInput = [AWSCognitoIdentityGetOpenIdTokenInput new]; |
284 |
| - getTokenInput.identityId = self.identityId; |
285 |
| - getTokenInput.logins = self.logins; |
286 |
| - |
287 |
| - return [[self.cib getOpenIdToken:getTokenInput] continueWithBlock:^id(BFTask *task) { |
288 |
| - // When an invalid identityId is cached in the keychain for auth, |
289 |
| - // we will refresh the identityId and try to get OpenID token again. |
290 |
| - if (task.error) { |
291 |
| - // if it's unauth, just fail out |
292 |
| - if (!self.logins) { |
293 |
| - return task; |
294 |
| - } |
295 |
| - |
296 |
| - AWSLogError(@"GetOpenIdToken failed. Error is [%@]", task.error); |
297 |
| - AWSLogVerbose(@"Calling GetId"); |
298 |
| - // if it's auth, reset id and refetch |
299 |
| - [self clearKeychain]; |
300 |
| - return [[self getIdentityId] continueWithSuccessBlock:^id(BFTask *task) { |
301 |
| - AWSLogVerbose(@"Retrying GetOpenIdToken"); |
302 |
| - |
303 |
| - // retry get token |
304 |
| - AWSCognitoIdentityGetOpenIdTokenInput *tokenRetry = [AWSCognitoIdentityGetOpenIdTokenInput new]; |
305 |
| - tokenRetry.identityId = self.identityId; |
306 |
| - tokenRetry.logins = self.logins; |
307 |
| - |
308 |
| - return [self.cib getOpenIdToken:tokenRetry]; |
309 |
| - }]; |
310 |
| - } |
311 |
| - return task; |
312 |
| - }]; |
313 |
| - }] continueWithSuccessBlock:^id(BFTask *task) { |
314 |
| - AWSCognitoIdentityGetOpenIdTokenResponse *getTokenResponse = task.result; |
315 |
| - self.openIdToken = getTokenResponse.token; |
316 |
| - NSString *identityIdFromToken = getTokenResponse.identityId; |
317 |
| - |
318 |
| - if (![self.identityId isEqualToString:identityIdFromToken]) { |
319 |
| - [self postIdentityIdChangedNotification:identityIdFromToken]; |
320 |
| - self.keychain[@"identityId"] = identityIdFromToken; |
321 |
| - [self.keychain synchronize]; |
322 |
| - } |
323 |
| - |
324 |
| - return nil; |
| 311 | + return [self.identityProvider refresh]; |
325 | 312 | }] continueWithSuccessBlock:^id(BFTask *task) {
|
326 |
| - NSString *roleArn = nil; |
327 |
| - if ([self.logins count] > 0) { |
| 313 | + self.keychain[@"identityId"] = self.identityProvider.identityId; |
| 314 | + [self.keychain synchronize]; |
| 315 | + |
| 316 | + NSString *roleArn = self.unAuthRoleArn; |
| 317 | + if ([self.identityProvider isAuthenticated]) { |
328 | 318 | roleArn = self.authRoleArn;
|
329 |
| - } else { |
330 |
| - roleArn = self.unAuthRoleArn; |
331 | 319 | }
|
332 | 320 |
|
333 | 321 | AWSSTSAssumeRoleWithWebIdentityRequest *webIdentityRequest = [AWSSTSAssumeRoleWithWebIdentityRequest new];
|
334 | 322 | webIdentityRequest.roleArn = roleArn;
|
335 |
| - webIdentityRequest.webIdentityToken = self.openIdToken; |
| 323 | + webIdentityRequest.webIdentityToken = self.identityProvider.token; |
336 | 324 | webIdentityRequest.roleSessionName = @"iOS-Provider";
|
337 | 325 | return [[self.sts assumeRoleWithWebIdentity:webIdentityRequest] continueWithBlock:^id(BFTask *task) {
|
338 | 326 | if (task.result) {
|
@@ -363,43 +351,22 @@ - (BFTask *)refresh {
|
363 | 351 | }
|
364 | 352 |
|
365 | 353 | - (BFTask *)getIdentityId {
|
366 |
| - if (self.identityId) { |
367 |
| - return [BFTask taskWithResult:nil]; |
368 |
| - } else { |
369 |
| - return [[BFTask taskWithResult:nil] continueWithBlock:^id(BFTask *task) { |
370 |
| - dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); |
371 |
| - dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); |
372 |
| - |
373 |
| - if (!self.identityId) { |
374 |
| - AWSCognitoIdentityGetIdInput *getIdInput = [AWSCognitoIdentityGetIdInput new]; |
375 |
| - getIdInput.accountId = self.accountId; |
376 |
| - getIdInput.identityPoolId = self.identityPoolId; |
377 |
| - getIdInput.logins = self.logins; |
378 |
| - |
379 |
| - return [[self.cib getId:getIdInput] continueWithBlock:^id(BFTask *task) { |
380 |
| - if (task.error) { |
381 |
| - AWSLogError(@"GetId failed. Error is [%@]", task.error); |
382 |
| - } else { |
383 |
| - AWSCognitoIdentityGetIdResponse *getIdResponse = task.result; |
384 |
| - [self postIdentityIdChangedNotification:getIdResponse.identityId]; |
385 |
| - self.keychain[@"identityId"] = getIdResponse.identityId; |
386 |
| - [self.keychain synchronize]; |
387 |
| - } |
388 |
| - |
389 |
| - dispatch_semaphore_signal(semaphore); |
390 |
| - return nil; |
391 |
| - }]; |
392 |
| - } else { |
393 |
| - dispatch_semaphore_signal(semaphore); |
394 |
| - } |
395 |
| - |
396 |
| - return nil; |
397 |
| - }]; |
398 |
| - } |
| 354 | + dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); |
| 355 | + |
| 356 | + return [[[BFTask taskWithResult:nil] continueWithSuccessBlock:^id(BFTask *task) { |
| 357 | + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); |
| 358 | + return [self.identityProvider getIdentityId]; |
| 359 | + }] continueWithBlock:^id(BFTask *task) { |
| 360 | + self.keychain[@"identityId"] = self.identityProvider.identityId; |
| 361 | + [self.keychain synchronize]; |
| 362 | + dispatch_semaphore_signal(semaphore); |
| 363 | + return nil; |
| 364 | + }]; |
399 | 365 | }
|
400 | 366 |
|
401 | 367 | - (void)clearKeychain {
|
402 | 368 | @synchronized(self) {
|
| 369 | + [self.identityProvider clear]; |
403 | 370 | [self.keychain removeItemForKey:@"identityId"];
|
404 | 371 | [self clearCredentials];
|
405 | 372 | }
|
@@ -451,54 +418,18 @@ - (NSDate *)expiration {
|
451 | 418 | }
|
452 | 419 |
|
453 | 420 | - (void)setLogins:(NSDictionary *)logins {
|
454 |
| - _logins = [self updateKeysForLogins:logins]; |
| 421 | + self.identityProvider.logins = logins; |
455 | 422 | // invalidate the credentials, so next time we
|
456 | 423 | // are forced to get a new token (and perhaps merge)
|
457 | 424 | [self clearCredentials];
|
458 | 425 | }
|
459 | 426 |
|
460 |
| -- (NSDictionary *)updateKeysForLogins:(NSDictionary *)logins { |
461 |
| - if (logins == nil) { |
462 |
| - return nil; |
463 |
| - } |
464 |
| - |
465 |
| - NSMutableDictionary *mutableLogin = [NSMutableDictionary new]; |
466 |
| - for (id key in logins) { |
467 |
| - NSString *updatedKey = key; |
468 |
| - if ([key isKindOfClass:[NSNumber class]]) { |
469 |
| - switch ([(NSNumber *)key integerValue]) { |
470 |
| - case AWSCognitoLoginProviderKeyFacebook: |
471 |
| - updatedKey = @"graph.facebook.com"; |
472 |
| - break; |
473 |
| - case AWSCognitoLoginProviderKeyGoogle: |
474 |
| - updatedKey = @"accounts.google.com"; |
475 |
| - break; |
476 |
| - case AWSCognitoLoginProviderKeyLoginWithAmazon: |
477 |
| - updatedKey = @"www.amazon.com"; |
478 |
| - break; |
479 |
| - case AWSCognitoLoginProviderKeyUnknown: |
480 |
| - default: |
481 |
| - break; |
482 |
| - } |
483 |
| - } |
484 |
| - mutableLogin[updatedKey] = logins[key]; |
485 |
| - } |
486 |
| - |
487 |
| - return mutableLogin; |
| 427 | +- (NSDictionary *)logins { |
| 428 | + return self.identityProvider.logins; |
488 | 429 | }
|
489 | 430 |
|
490 |
| -- (void)postIdentityIdChangedNotification:(NSString *)newId { |
491 |
| - NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; |
492 |
| - if (self.identityId) { |
493 |
| - [userInfo setObject:self.identityId forKey:AWSCognitoNotificationPreviousId]; |
494 |
| - } |
495 |
| - [userInfo setObject:newId forKey:AWSCognitoNotificationNewId]; |
496 |
| - |
497 |
| - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ |
498 |
| - [[NSNotificationCenter defaultCenter] postNotificationName:AWSCognitoIdentityIdChangedNotification |
499 |
| - object:self |
500 |
| - userInfo:userInfo]; |
501 |
| - }); |
| 431 | +- (NSString *)identityPoolId { |
| 432 | + return self.identityProvider.identityPoolId; |
502 | 433 | }
|
503 | 434 |
|
504 | 435 | @end
|
0 commit comments