123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644 |
- //
- // Copyright 2014-2018 Amazon.com,
- // Inc. or its affiliates. All Rights Reserved.
- //
- // Licensed under the Amazon Software License (the "License").
- // You may not use this file except in compliance with the
- // License. A copy of the License is located at
- //
- // http://aws.amazon.com/asl/
- //
- // or in the "license" file accompanying this file. This file is
- // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- // CONDITIONS OF ANY KIND, express or implied. See the License
- // for the specific language governing permissions and
- // limitations under the License.
- //
-
- #import "AWSCognitoIdentityProvider.h"
- #import "AWSCognitoIdentityUser_Internal.h"
- #import "AWSCognitoIdentityUserPool_Internal.h"
- #import "AWSCognitoIdentityProviderSrpHelper.h"
- #import "AWSJKBigInteger.h"
- #import "NSData+AWSCognitoIdentityProvider.h"
- #import <CommonCrypto/CommonDigest.h>
-
- @interface AWSCognitoIdentityUserPool()
-
- @property (nonatomic, strong) AWSCognitoIdentityProvider *client;
-
- @end
-
- @implementation AWSCognitoIdentityUser
-
- static const NSString * AWSCognitoIdentityUserDerivedKeyInfo = @"Caldera Derived Key";
- static const NSString * AWSCognitoIdentityUserAccessToken = @"accessToken";
- static const NSString * AWSCognitoIdentityUserIdToken = @"idToken";
- static const NSString * AWSCognitoIdentityUserRefreshToken = @"refreshToken";
- static const NSString * AWSCognitoIdentityUserTokenExpiration = @"tokenExpiration";
- static const NSString * AWSCognitoIdentityUserDeviceId = @"device.id";
- static const NSString * AWSCognitoIdentityUserAsfDeviceId = @"asf.device.id";
- static const NSString * AWSCognitoIdentityUserDeviceSecret = @"device.secret";
- static const NSString * AWSCognitoIdentityUserDeviceGroup = @"device.group";
- static const NSString * AWSCognitoIdentityUserUserAttributePrefix = @"userAttributes.";
-
- -(instancetype) initWithUsername: (NSString *)username pool:(AWSCognitoIdentityUserPool *)pool {
- self = [super init];
- if(self != nil) {
- _username = username;
- _pool = pool;
- _confirmedStatus = AWSCognitoIdentityUserStatusUnknown;
- }
- return self;
- }
-
- -(AWSTask<AWSCognitoIdentityUserConfirmSignUpResponse *> *) confirmSignUp:(NSString *) confirmationCode {
- return [self confirmSignUp:confirmationCode forceAliasCreation:NO];
- }
-
- -(AWSTask<AWSCognitoIdentityUserConfirmSignUpResponse *> *) confirmSignUp:(NSString *) confirmationCode forceAliasCreation:(BOOL)forceAliasCreation {
- AWSCognitoIdentityProviderConfirmSignUpRequest *request = [AWSCognitoIdentityProviderConfirmSignUpRequest new];
- request.clientId = self.pool.userPoolConfiguration.clientId;
- request.username = self.username;
- request.secretHash = [self.pool calculateSecretHash:self.username];
- request.confirmationCode = confirmationCode;
- request.forceAliasCreation = (forceAliasCreation?@(YES):@(NO));
- request.analyticsMetadata = [self.pool analyticsMetadata];
- request.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- return [[self.pool.client confirmSignUp:request] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderConfirmSignUpResponse *> * _Nonnull task) {
- if (task.error) {
- self.confirmedStatus = AWSCognitoIdentityUserStatusUnconfirmed;
- return task;
- } else {
- self.confirmedStatus = AWSCognitoIdentityUserStatusConfirmed;
- AWSCognitoIdentityUserConfirmSignUpResponse * response = [AWSCognitoIdentityUserConfirmSignUpResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }
- }];
- }
-
- -(AWSTask<AWSCognitoIdentityUserForgotPasswordResponse *> *) forgotPassword {
- AWSCognitoIdentityProviderForgotPasswordRequest *request = [AWSCognitoIdentityProviderForgotPasswordRequest new];
- request.clientId = self.pool.userPoolConfiguration.clientId;
- request.username = self.username;
- request.secretHash = [self.pool calculateSecretHash:self.username];
- request.analyticsMetadata = [self.pool analyticsMetadata];
- request.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- return [[self.pool.client forgotPassword:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderForgotPasswordResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserForgotPasswordResponse * response = [AWSCognitoIdentityUserForgotPasswordResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
-
- }
-
- -(AWSTask<AWSCognitoIdentityUserConfirmForgotPasswordResponse *> *) confirmForgotPassword: (NSString *)confirmationCode password:(NSString *) password {
- AWSCognitoIdentityProviderConfirmForgotPasswordRequest *request = [AWSCognitoIdentityProviderConfirmForgotPasswordRequest new];
- request.clientId = self.pool.userPoolConfiguration.clientId;
- request.username = self.username;
- request.secretHash = [self.pool calculateSecretHash:self.username];
- request.password = password;
- request.confirmationCode = confirmationCode;
- request.analyticsMetadata = [self.pool analyticsMetadata];
- request.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- return [[self.pool.client confirmForgotPassword:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderConfirmForgotPasswordResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserConfirmForgotPasswordResponse * response = [AWSCognitoIdentityUserConfirmForgotPasswordResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }
-
- -(AWSTask<AWSCognitoIdentityUserResendConfirmationCodeResponse *> *) resendConfirmationCode {
- AWSCognitoIdentityProviderResendConfirmationCodeRequest *request = [AWSCognitoIdentityProviderResendConfirmationCodeRequest new];
- request.clientId = self.pool.userPoolConfiguration.clientId;
- request.username = self.username;
- request.secretHash = [self.pool calculateSecretHash:self.username];
- request.analyticsMetadata = [self.pool analyticsMetadata];
- request.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- return [[self.pool.client resendConfirmationCode:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderResendConfirmationCodeResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserResendConfirmationCodeResponse * response = [AWSCognitoIdentityUserResendConfirmationCodeResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }
-
- -(AWSTask<AWSCognitoIdentityUserChangePasswordResponse *>*) changePassword: (NSString*)currentPassword proposedPassword: (NSString *)proposedPassword {
- AWSCognitoIdentityProviderChangePasswordRequest* request = [AWSCognitoIdentityProviderChangePasswordRequest new];
- request.previousPassword = currentPassword;
- request.proposedPassword = proposedPassword;
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- return [[self.pool.client changePassword:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderChangePasswordResponse *> * _Nonnull task) {
- AWSCognitoIdentityProviderChangePasswordResponse * apiResponse = task.result;
- AWSCognitoIdentityUserChangePasswordResponse *response = [AWSCognitoIdentityUserChangePasswordResponse new];
- [response aws_copyPropertiesFromObject:apiResponse];
- return [AWSTask taskWithResult:response];
- }];
-
- }];
- }
-
- -(AWSTask<AWSCognitoIdentityUserGetDetailsResponse *>*) getDetails {
- AWSCognitoIdentityProviderGetUserRequest* request = [AWSCognitoIdentityProviderGetUserRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- return [[self.pool.client getUser:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderGetUserResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserGetDetailsResponse * response = [AWSCognitoIdentityUserGetDetailsResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }];
- }
-
- /**
- Get a session
- */
- -(AWSTask<AWSCognitoIdentityUserSession*> *) getSession {
-
- //check to see if we have valid tokens
- __block NSString * keyChainNamespace = [self keyChainNamespaceClientId];
- NSString * expirationTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserTokenExpiration];
- NSString * expirationDate = self.pool.keychain[expirationTokenKey];
-
- if(expirationDate){
- NSDate *expiration = [NSDate aws_dateFromString:expirationDate format:AWSDateISO8601DateFormat1];
- NSString * refreshToken = [self refreshTokenFromKeyChain:keyChainNamespace];
-
- // Token exists, the user is confirmed
- self.confirmedStatus = AWSCognitoIdentityUserStatusConfirmed;
-
- NSString * accessTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserAccessToken];
- NSString * accessToken = self.pool.keychain[accessTokenKey];
- //if the session expires > 5 minutes return it and there is at least an accessToken.
- if(expiration && [expiration compare:[NSDate dateWithTimeIntervalSinceNow:5 * 60]] == NSOrderedDescending && accessToken){
- NSString * idTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserIdToken];
- AWSCognitoIdentityUserSession * session = [[AWSCognitoIdentityUserSession alloc] initWithIdToken:self.pool.keychain[idTokenKey] accessToken:accessToken refreshToken:refreshToken expirationTime:expiration];
-
- session.expirationTime = expiration;
- return [AWSTask taskWithResult:session];
- }
- //else refresh it using the refresh token
- else if(refreshToken){
- AWSCognitoIdentityProviderInitiateAuthRequest * request = [AWSCognitoIdentityProviderInitiateAuthRequest new];
- request.authFlow = AWSCognitoIdentityProviderAuthFlowTypeRefreshTokenAuth;
- request.clientId = self.pool.userPoolConfiguration.clientId;
- request.analyticsMetadata = [self.pool analyticsMetadata];
- request.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- NSMutableDictionary * authParameters = [[NSMutableDictionary alloc] initWithDictionary:@{@"REFRESH_TOKEN" : refreshToken}];
-
- //refresh token secret hash is actually client secret for this api, set it if it is supplied
- if(self.pool.userPoolConfiguration.clientSecret != nil){
- [authParameters setObject:self.pool.userPoolConfiguration.clientSecret forKey:@"SECRET_HASH"];
- }
-
- [self addDeviceKey:authParameters];
-
- request.authParameters = authParameters;
- return [[self.pool.client initiateAuth:request] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse *> * _Nonnull task) {
- if(task.error){
- //If this token is no longer valid, fall back on interactive auth.
- if(task.error.code == AWSCognitoIdentityProviderErrorNotAuthorized) {
- return [self interactiveAuth];
- } else {
- return task;
- }
- }
-
- AWSCognitoIdentityProviderInitiateAuthResponse *response = task.result;
- AWSCognitoIdentityProviderAuthenticationResultType *authResult = response.authenticationResult;
- /** Check to see if refreshToken is received in the response.
- If not, load it from the keychain.
- */
- NSString * refreshToken = authResult.refreshToken;
- if (refreshToken == nil){
- NSString * keyChainNamespace = [self keyChainNamespaceClientId];
- refreshToken = [self refreshTokenFromKeyChain:keyChainNamespace];
- }
- AWSCognitoIdentityUserSession * session = [[AWSCognitoIdentityUserSession alloc] initWithIdToken: authResult.idToken accessToken:authResult.accessToken refreshToken:refreshToken expiresIn:authResult.expiresIn];
- [self updateUsernameAndPersistTokens:session];
- return [AWSTask taskWithResult:session];
- }];
- }
- }
- return [self setConfirmationStatus: [self interactiveAuth]];
- }
-
-
-
- /**
- * Explicitly get a session without using any cached tokens/refresh tokens.
- */
- - (AWSTask<AWSCognitoIdentityUserSession*>*) getSession:(NSString *)username password:(NSString *)password validationData:(NSArray<AWSCognitoIdentityUserAttributeType*>*)validationData {
- AWSTask *authenticationTask = self.pool.userPoolConfiguration.migrationEnabled ? [self migrationAuth:username password:password validationData:validationData lastChallenge:nil] : [self srpAuthInternal:username password:password validationData:validationData lastChallenge:nil isInitialCustomChallenge:NO];
- return [self setConfirmationStatus: [authenticationTask continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- return [self getSessionInternal:task];
- }]];
- }
-
- - (AWSTask<AWSCognitoIdentityUserSession*>*) setConfirmationStatus: (AWSTask<AWSCognitoIdentityUserSession*>*) task {
-
- // If the user status is unknown
- if (self.confirmedStatus == AWSCognitoIdentityUserStatusUnknown) {
- if (task.error) {
- if (task.error.code == AWSCognitoIdentityProviderErrorUserNotConfirmed) {
- self.confirmedStatus = AWSCognitoIdentityUserStatusUnconfirmed;
- }
- } else {
- self.confirmedStatus = AWSCognitoIdentityUserStatusConfirmed;
- }
- }
-
- return task;
- }
-
-
- - (AWSTask<AWSCognitoIdentityUserSession*>*) getSessionInternal: (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *>*) task{
- return [task continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse * authenticateResult = task.result;
- AWSCognitoIdentityProviderAuthenticationResultType * authResult = task.result.authenticationResult;
- AWSCognitoIdentityProviderChallengeNameType nextChallenge = authenticateResult.challengeName;
-
- AWSCognitoIdentityUserSession * session = nil;
- //No more challenges we have a session
- if(authResult != nil){
- session = [[AWSCognitoIdentityUserSession alloc] initWithIdToken:authResult.idToken accessToken:authResult.accessToken refreshToken:authResult.refreshToken expiresIn:authResult.expiresIn];
- }
-
- //last step is to perform device auth if device key is supplied or we are being challenged with device auth
- if(authResult.latestDeviceMetadata != nil || nextChallenge == AWSCognitoIdentityProviderChallengeNameTypeDeviceSrpAuth){
- return [self performDeviceAuth: task session:session];
- }
-
- //if mfa required, present mfa challenge
- if(AWSCognitoIdentityProviderChallengeNameTypeSmsMfa == nextChallenge || AWSCognitoIdentityProviderChallengeNameTypeSoftwareTokenMfa == nextChallenge){
- if ([self.pool.delegate respondsToSelector:@selector(startMultiFactorAuthentication)]) {
- BOOL isSoftwareToken = AWSCognitoIdentityProviderChallengeNameTypeSoftwareTokenMfa == nextChallenge;
- id<AWSCognitoIdentityMultiFactorAuthentication> authenticationDelegate = [self.pool.delegate startMultiFactorAuthentication];
- NSString *deliveryMedium = isSoftwareToken ? @"SOFTWARE_TOKEN" : authenticateResult.challengeParameters[@"CODE_DELIVERY_DELIVERY_MEDIUM"];
- NSString *destination = isSoftwareToken ? authenticateResult.challengeParameters[@"FRIENDLY_DEVICE_NAME"] : authenticateResult.challengeParameters[@"CODE_DELIVERY_DESTINATION"];
- return [self mfaAuthInternal:deliveryMedium destination:destination authState:authenticateResult.session challengeName:nextChallenge authenticationDelegate:authenticationDelegate];
-
- }else {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorInvalidAuthenticationDelegate userInfo:@{NSLocalizedDescriptionKey: @"startMultiFactorAuthentication not implemented by authentication delegate"}]];
- }
- }else if(AWSCognitoIdentityProviderChallengeNameTypeSelectMfaType == nextChallenge){
- return [self startSelectMfaUI:authenticateResult];
- }else if(AWSCognitoIdentityProviderChallengeNameTypeMfaSetup == nextChallenge){
- return [self startMfaSetupRequiredUI:authenticateResult];
- }else if(AWSCognitoIdentityProviderChallengeNameTypeNewPasswordRequired == nextChallenge){
- return [self startNewPasswordRequiredUI:authenticateResult];
- }else if(AWSCognitoIdentityProviderAuthFlowTypeUserSrpAuth == nextChallenge){ //if srp auth happens mid auth
- return [self startPasswordAuthenticationUI:authenticateResult];
- }else if (session) { //we have a session, return it
- [self updateUsernameAndPersistTokens:session];
- return [AWSTask taskWithResult:session];
- }else { //this is a custom challenge
- if ([self.pool.delegate respondsToSelector:@selector(startCustomAuthentication)]) {
- id<AWSCognitoIdentityCustomAuthentication> authenticationDelegate = [self.pool.delegate startCustomAuthentication];
- AWSCognitoIdentityCustomAuthenticationInput *input = [AWSCognitoIdentityCustomAuthenticationInput new];
- input.challengeParameters = authenticateResult.challengeParameters;
- AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails *> *challengeDetails = [AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails *> new];
- [authenticationDelegate getCustomChallengeDetails:input customAuthCompletionSource:challengeDetails];
- return [challengeDetails.task continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityCustomChallengeDetails *> * _Nonnull task) {
- return [[self performRespondCustomAuthChallenge:task.result session:authenticateResult.session] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- [authenticationDelegate didCompleteCustomAuthenticationStepWithError:task.error];
- return [self getSessionInternal: task];
- }];
-
- }];
-
- }else {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorInvalidAuthenticationDelegate userInfo:@{NSLocalizedDescriptionKey: @"startCustomAuthentication not implemented by authentication delegate"}]];
- }
- }
- }];
- }
-
- - (AWSTask<AWSCognitoIdentityUserSession*>*) startPasswordAuthenticationUI:(AWSCognitoIdentityProviderRespondToAuthChallengeResponse*) lastChallenge {
- if([self.pool.delegate respondsToSelector:@selector(startPasswordAuthentication)]){
- id<AWSCognitoIdentityPasswordAuthentication> authenticationDelegate = [self.pool.delegate startPasswordAuthentication];
- return [self passwordAuthInternal:authenticationDelegate lastChallenge:lastChallenge isInitialCustomChallenge:lastChallenge == nil];
- }else {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorInvalidAuthenticationDelegate userInfo:@{NSLocalizedDescriptionKey: @"startPasswordAuthentication must be implemented on your AWSCognitoIdentityInteractiveAuthenticationDelegate"}]];
- }
- }
-
- - (AWSTask<AWSCognitoIdentityUserSession*>*) startNewPasswordRequiredUI:(AWSCognitoIdentityProviderRespondToAuthChallengeResponse*) lastChallenge {
- if ([self.pool.delegate respondsToSelector:@selector(startNewPasswordRequired)]) {
- id<AWSCognitoIdentityNewPasswordRequired> newPasswordRequiredDelegate = [self.pool.delegate startNewPasswordRequired];
- NSString * userAttributes = lastChallenge.challengeParameters[@"userAttributes"];
- NSString * requiredAttributes = lastChallenge.challengeParameters[@"requiredAttributes"];
- NSMutableDictionary<NSString*, NSString *> *userAttributesDict = [NSMutableDictionary new];
- NSMutableSet<NSString*> *requiredAttributesSet = [NSMutableSet new];
-
- if(userAttributes){
- [userAttributesDict addEntriesFromDictionary:[NSJSONSerialization JSONObjectWithData:[userAttributes dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil]];
- }
- if(requiredAttributes) {
- NSArray * requiredAttributesArray = [NSJSONSerialization JSONObjectWithData:[requiredAttributes dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
- for (NSString * requiredAttribute in requiredAttributesArray) {
- //strip off userAttributes. from all the attribute names
- NSString *strippedKey = [requiredAttribute substringFromIndex:[AWSCognitoIdentityUserUserAttributePrefix length]];
- [requiredAttributesSet addObject:strippedKey];
- }
- }
- AWSCognitoIdentityNewPasswordRequiredInput *newPasswordRequiredInput = [[AWSCognitoIdentityNewPasswordRequiredInput alloc] initWithUserAttributes:userAttributesDict requiredAttributes:requiredAttributesSet];
- AWSTaskCompletionSource<AWSCognitoIdentityNewPasswordRequiredDetails *> *newPasswordRequiredDetails = [AWSTaskCompletionSource<AWSCognitoIdentityNewPasswordRequiredDetails *> new];
- [newPasswordRequiredDelegate getNewPasswordDetails:newPasswordRequiredInput newPasswordRequiredCompletionSource:newPasswordRequiredDetails];
- return [[newPasswordRequiredDetails.task continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityNewPasswordRequiredDetails *> * _Nonnull task) {
- return [self performRespondToNewPasswordChallenge:task.result session:lastChallenge.session];
- }] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- [newPasswordRequiredDelegate didCompleteNewPasswordStepWithError:task.error];
- if(task.error){
- return [self startNewPasswordRequiredUI:lastChallenge];
- }
- return [self getSessionInternal:task];
- }];
-
- }else {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorInvalidAuthenticationDelegate userInfo:@{NSLocalizedDescriptionKey: @"startNewPasswordRequired not implemented by authentication delegate"}]];
- }
- }
-
- - (AWSTask<AWSCognitoIdentityUserSession*>*) startMfaSetupRequiredUI:(AWSCognitoIdentityProviderRespondToAuthChallengeResponse*) lastChallenge {
- NSString * availableMfas = lastChallenge.challengeParameters[@"MFAS_CAN_SETUP"];
- NSMutableSet<NSString*> *availableMfasSet = [NSMutableSet new];
-
- if(availableMfas) {
- NSArray * availableMfasArray = [NSJSONSerialization JSONObjectWithData:[availableMfas dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
- for (NSString * availableMfa in availableMfasArray) {
- [availableMfasSet addObject:availableMfa];
- }
- }
-
- if([availableMfasSet containsObject:@"SOFTWARE_TOKEN_MFA"]){
- if ([self.pool.delegate respondsToSelector:@selector(startSoftwareMfaSetupRequired)]) {
- id<AWSCognitoIdentitySoftwareMfaSetupRequired> softwareMfaSetupRequiredDelegate = [self.pool.delegate startSoftwareMfaSetupRequired];
- AWSCognitoIdentityProviderAssociateSoftwareTokenRequest *request = [AWSCognitoIdentityProviderAssociateSoftwareTokenRequest new];
- request.session = lastChallenge.session;
- return [[self.pool.client associateSoftwareToken:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderAssociateSoftwareTokenResponse *> * _Nonnull task) {
- AWSCognitoIdentitySoftwareMfaSetupRequiredInput *softwareMfaSetupRequiredInput = [[AWSCognitoIdentitySoftwareMfaSetupRequiredInput alloc] initWithSecretCode:task.result.secretCode username:self.username];
- return [self verifyMfaSetup:task.result.session selectMfaDelegate:softwareMfaSetupRequiredDelegate input:softwareMfaSetupRequiredInput];
- }];
- } else {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorInvalidAuthenticationDelegate userInfo:@{NSLocalizedDescriptionKey: @"startSoftwareMfaSetupRequired not implemented by authentication delegate"}]];
- }
- } else {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorInvalidAuthenticationDelegate userInfo:@{NSLocalizedDescriptionKey: @"This version of the SDK does not support setup of the MFA types necessary to authenticate"}]];
- }
-
- }
-
- - (AWSTask<AWSCognitoIdentityUserSession*>*) verifyMfaSetup:(NSString *) session selectMfaDelegate:(id<AWSCognitoIdentitySoftwareMfaSetupRequired> ) softwareMfaSetupRequiredDelegate input:(AWSCognitoIdentitySoftwareMfaSetupRequiredInput *) input {
- AWSTaskCompletionSource<AWSCognitoIdentitySoftwareMfaSetupRequiredDetails *> *softwareMfaSetupRequiredDetails = [AWSTaskCompletionSource<AWSCognitoIdentitySoftwareMfaSetupRequiredDetails *> new];
- [softwareMfaSetupRequiredDelegate getSoftwareMfaSetupDetails:input softwareMfaSetupRequiredCompletionSource:softwareMfaSetupRequiredDetails];
- return [[softwareMfaSetupRequiredDetails.task continueWithSuccessBlock:^id _Nullable(AWSTask <AWSCognitoIdentitySoftwareMfaSetupRequiredDetails *>* _Nonnull mfaDetails) {
- AWSCognitoIdentityProviderVerifySoftwareTokenRequest *verifyRequest = [AWSCognitoIdentityProviderVerifySoftwareTokenRequest new];
- verifyRequest.session = session;
- verifyRequest.friendlyDeviceName = mfaDetails.result.friendlyDeviceName;
- verifyRequest.userCode = mfaDetails.result.userCode;
- return [self.pool.client verifySoftwareToken:verifyRequest];
- }] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderVerifySoftwareTokenResponse *> *_Nonnull verifySoftwareToken) {
- [softwareMfaSetupRequiredDelegate didCompleteMfaSetupStepWithError:verifySoftwareToken.error];
- if(verifySoftwareToken.error){
- return [self verifyMfaSetup:session selectMfaDelegate:softwareMfaSetupRequiredDelegate input:input];
- }
-
- NSMutableDictionary<NSString *,NSString *> *challengeResponses = [NSMutableDictionary new];
-
- return [self getSessionInternal:[self performRespondToAuthChallenge:challengeResponses challengeName:AWSCognitoIdentityProviderChallengeNameTypeMfaSetup session:verifySoftwareToken.result.session]];
- }];
- }
-
- - (AWSTask<AWSCognitoIdentityUserSession*>*) startSelectMfaUI:(AWSCognitoIdentityProviderRespondToAuthChallengeResponse*) lastChallenge {
- if ([self.pool.delegate respondsToSelector:@selector(startSelectMfa)]) {
- id<AWSCognitoIdentitySelectMfa> selectMfaDelegate = [self.pool.delegate startSelectMfa];
- NSString * availableMfas = lastChallenge.challengeParameters[@"MFAS_CAN_CHOOSE"];
- NSMutableDictionary<NSString*,NSString*> *availableMfasDict = [NSMutableDictionary new];
-
- if(availableMfas) {
- NSArray * availableMfasArray = [NSJSONSerialization JSONObjectWithData:[availableMfas dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
- for (NSString * availableMfa in availableMfasArray) {
- NSString *value = nil;
- if([@"SOFTWARE_TOKEN_MFA" isEqualToString:availableMfa]){
- value = lastChallenge.challengeParameters[@"FRIENDLY_DEVICE_NAME"];
- }else if([@"SMS_MFA" isEqualToString:availableMfa]){
- value = lastChallenge.challengeParameters[@"CODE_DELIVERY_DESTINATION"];
- }
- if(value == nil){
- value = @"unknown";
- }
- [availableMfasDict setObject:value forKey:availableMfa];
- }
- }
- AWSCognitoIdentitySelectMfaInput *selectMfaInput = [[AWSCognitoIdentitySelectMfaInput alloc] initWithAvailableMfas:availableMfasDict];
- AWSTaskCompletionSource<AWSCognitoIdentitySelectMfaDetails *> *selectMfaDetails = [AWSTaskCompletionSource<AWSCognitoIdentitySelectMfaDetails *> new];
- [selectMfaDelegate getSelectMfaDetails:selectMfaInput selectMfaCompletionSource:selectMfaDetails];
- return [[selectMfaDetails.task continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentitySelectMfaDetails *> * _Nonnull task) {
- return [self performRespondToSelectMfaChallenge:task.result session:lastChallenge.session];
- }] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- [selectMfaDelegate didCompleteSelectMfaStepWithError:task.error];
- if(task.error){
- return [self startSelectMfaUI:lastChallenge];
- }
- return [self getSessionInternal:task];
- }];
- }else {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorInvalidAuthenticationDelegate userInfo:@{NSLocalizedDescriptionKey: @"startSelectMfa not implemented by authentication delegate"}]];
- }
- }
-
- - (AWSTask<AWSCognitoIdentityUserSession*>*) performDeviceAuth:(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *>*) lastChallengeResponse session: (AWSCognitoIdentityUserSession *) session {
- if(session){
- [self updateUsernameAndPersistTokens:session];
- }
- if(lastChallengeResponse.result.challengeName == AWSCognitoIdentityProviderChallengeNameTypeDeviceSrpAuth){
- return [[self deviceAuthInternal:lastChallengeResponse] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- if(task.cancelled || task.error) {
- return task;
- }else {
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse *response = task.result;
- AWSCognitoIdentityUserSession * session = [[AWSCognitoIdentityUserSession alloc] initWithIdToken:response.authenticationResult.idToken accessToken:response.authenticationResult.accessToken refreshToken:response.authenticationResult.refreshToken expiresIn:response.authenticationResult.expiresIn];
- [self updateUsernameAndPersistTokens:session];
- return [AWSTask taskWithResult:session];
- }
- }];
- }else {
- return [[self confirmDeviceInternal:lastChallengeResponse.result.authenticationResult] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) {
- if(task.error || task.isCancelled){
- return task;
- }else {
- return [AWSTask taskWithResult:session];
- }
- }];
- }
- }
-
- /**
- * Generates a device password, calls service to exchange the password verifier and prompts user to remember the device as required.
- */
- - (AWSTask*) confirmDeviceInternal:(AWSCognitoIdentityProviderAuthenticationResultType *) authResult {
- if(authResult.latestDeviceMetadata != nil){
- NSString * deviceKey = authResult.latestDeviceMetadata.deviceKey;
- NSString * deviceGroup = authResult.latestDeviceMetadata.deviceGroupKey;
- if(deviceKey != nil){
- NSString *secret = [[NSUUID UUID] UUIDString];
- AWSCognitoIdentityProviderConfirmDeviceRequest * request = [AWSCognitoIdentityProviderConfirmDeviceRequest new];
- request.accessToken = authResult.accessToken;
- request.deviceKey = deviceKey;
- request.deviceName = [[UIDevice currentDevice] name];
-
- AWSCognitoIdentityProviderSrpHelper * srpHelper = [[AWSCognitoIdentityProviderSrpHelper alloc] initWithPoolName:deviceGroup userName:deviceKey password:secret];
- request.deviceSecretVerifierConfig = [AWSCognitoIdentityProviderDeviceSecretVerifierConfigType new];
- request.deviceSecretVerifierConfig.salt = [[NSData aws_dataWithSignedBigInteger:srpHelper.salt] base64EncodedStringWithOptions:0];
- request.deviceSecretVerifierConfig.passwordVerifier = [[NSData aws_dataWithSignedBigInteger:srpHelper.v] base64EncodedStringWithOptions:0];
- return [[self.pool.client confirmDevice:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderConfirmDeviceResponse *> * _Nonnull task) {
- [self persistDevice:deviceKey deviceSecret:secret deviceGroup:deviceGroup];
- AWSCognitoIdentityProviderConfirmDeviceResponse *confirmDeviceResponse = task.result;
- if([confirmDeviceResponse.userConfirmationNecessary boolValue]) {
- if ([self.pool.delegate respondsToSelector:@selector(startRememberDevice)]) {
- id<AWSCognitoIdentityRememberDevice> rememberDeviceStep = [self.pool.delegate startRememberDevice];
- AWSTaskCompletionSource<NSNumber *> *rememberDevice = [[AWSTaskCompletionSource<NSNumber *> alloc] init];
- [rememberDeviceStep getRememberDevice:rememberDevice];
- return [rememberDevice.task continueWithBlock:^id _Nullable(AWSTask<NSNumber *> * _Nonnull rememberDeviceTask) {
- if(rememberDeviceTask.isCancelled || rememberDeviceTask.error){
- [rememberDeviceStep didCompleteRememberDeviceStepWithError:rememberDeviceTask.error];
- return rememberDeviceStep;
- }else if ([rememberDeviceTask.result boolValue]){
- AWSCognitoIdentityProviderUpdateDeviceStatusRequest * request = [AWSCognitoIdentityProviderUpdateDeviceStatusRequest new];
- request.accessToken = authResult.accessToken;
- request.deviceKey = deviceKey;
- request.deviceRememberedStatus = AWSCognitoIdentityProviderDeviceRememberedStatusTypeRemembered;
- return [[self.pool.client updateDeviceStatus:request] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderUpdateDeviceStatusResponse *> * _Nonnull updateDeviceStatusTask) {
- [rememberDeviceStep didCompleteRememberDeviceStepWithError:rememberDeviceTask.error];
- return updateDeviceStatusTask;
- }];
- }
- return task;
- }];
-
-
- }else {
- AWSDDLogWarn(@"startRememberDevice is not implemented by authentication delegate, defaulting to not remembered.");
- }
- }
- return task;
- }];
- }
- }
- return [AWSTask taskWithResult:nil];
- }
-
- /**
- * Kick off interactive auth to prompt developer to challenge end user for credentials
- */
- - (AWSTask<AWSCognitoIdentityUserSession*>*) interactiveAuth {
- if(self.pool.delegate != nil){
- if([self.pool.delegate respondsToSelector:@selector(startCustomAuthentication)] && !self.pool.userPoolConfiguration.migrationEnabled) {
- id<AWSCognitoIdentityCustomAuthentication> authenticationDelegate = [self.pool.delegate startCustomAuthentication];
- return [self customAuthInternal:authenticationDelegate];
- }else if([self.pool.delegate respondsToSelector:@selector(startPasswordAuthentication)]){
- id<AWSCognitoIdentityPasswordAuthentication> authenticationDelegate = [self.pool.delegate startPasswordAuthentication];
- return [self passwordAuthInternal:authenticationDelegate lastChallenge:nil isInitialCustomChallenge:NO];
- }else {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorInvalidAuthenticationDelegate userInfo:@{NSLocalizedDescriptionKey: @"Either startCustomAuthentication or startPasswordAuthentication must be implemented on your AWSCognitoIdentityInteractiveAuthenticationDelegate"}]];
- }
- } else {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorInvalidAuthenticationDelegate userInfo:@{NSLocalizedDescriptionKey: @"Authentication delegate not set"}]];
- };
- }
-
- /**
- * Prompt developer to obtain username/password and do SRP auth
- */
- - (AWSTask<AWSCognitoIdentityUserSession*>*) passwordAuthInternal: (id<AWSCognitoIdentityPasswordAuthentication>) authenticationDelegate lastChallenge:(AWSCognitoIdentityProviderRespondToAuthChallengeResponse*) lastChallenge isInitialCustomChallenge:(BOOL) isInitialCustomChallenge {
- AWSCognitoIdentityPasswordAuthenticationInput * input = [[AWSCognitoIdentityPasswordAuthenticationInput alloc] initWithLastKnownUsername:[self.pool currentUsername]];
- AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails*>*passwordAuthenticationDetails = [AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails*> new];
- [authenticationDelegate getPasswordAuthenticationDetails:input passwordAuthenticationCompletionSource:passwordAuthenticationDetails];
- return [passwordAuthenticationDetails.task continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityPasswordAuthenticationDetails *> * _Nonnull task) {
- AWSCognitoIdentityPasswordAuthenticationDetails * authDetails = task.result;
-
- if(self.pool.userPoolConfiguration.migrationEnabled){
- return [[self migrationAuth:authDetails.username password:authDetails.password validationData:authDetails.validationData lastChallenge:lastChallenge] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- [authenticationDelegate didCompletePasswordAuthenticationStepWithError:task.error];
- if(task.isCancelled){
- return task;
- }
- if(task.error){
- //retry password auth on error
- return [self passwordAuthInternal:authenticationDelegate lastChallenge:lastChallenge isInitialCustomChallenge:NO];
- }else {
- //morph this initiate auth response into a respond to auth challenge response so it works as input to getSessionInternal
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse * response = [AWSCognitoIdentityProviderRespondToAuthChallengeResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [self getSessionInternal:[AWSTask taskWithResult:response]];
- }
- }];
- } else {
- return [[self srpAuthInternal:authDetails.username password:authDetails.password validationData:authDetails.validationData lastChallenge:lastChallenge isInitialCustomChallenge:isInitialCustomChallenge] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- [authenticationDelegate didCompletePasswordAuthenticationStepWithError:task.error];
- if(task.isCancelled){
- return task;
- }
- if(task.error){
- //retry password auth on error
- return [self passwordAuthInternal:authenticationDelegate lastChallenge:lastChallenge isInitialCustomChallenge:isInitialCustomChallenge];
- }else {
- return [self getSessionInternal:task];
- }
- }];
- }
- }];
- }
-
- /**
- * Pass username and password in plaintext so developer can validate login and migrate as appropriate.
- **/
- - (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*>*) migrationAuth:(NSString *)username password:(NSString *)password validationData:(NSArray<AWSCognitoIdentityUserAttributeType*>*)validationData lastChallenge:(AWSCognitoIdentityProviderRespondToAuthChallengeResponse*) lastChallenge {
- self.username = username;
- NSMutableDictionary *challengeResponses = [NSMutableDictionary new];
- [self addSecretHashDeviceKeyAndUsername:challengeResponses];
- [challengeResponses setObject:password forKey:@"PASSWORD"];
-
- if(lastChallenge){
- AWSCognitoIdentityProviderRespondToAuthChallengeRequest *input = [AWSCognitoIdentityProviderRespondToAuthChallengeRequest new];
- input.challengeName = lastChallenge.challengeName;
- input.challengeResponses = challengeResponses;
- input.session = lastChallenge.session;
- input.analyticsMetadata = [self.pool analyticsMetadata];
- input.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- return [[self.pool.client respondToAuthChallenge:input] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- return [self forgetDeviceOnRespondDeviceNotFoundError:task retryContinuation:^AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> *{
- return [self migrationAuth:username password:password validationData:validationData lastChallenge:lastChallenge];
- }];
- }];
- }
- else{
- AWSCognitoIdentityProviderInitiateAuthRequest *input = [AWSCognitoIdentityProviderInitiateAuthRequest new];
- input.clientId = self.pool.userPoolConfiguration.clientId;
- input.clientMetadata = [self.pool getValidationData:validationData];
- input.analyticsMetadata = [self.pool analyticsMetadata];
- input.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
- input.authFlow = AWSCognitoIdentityProviderAuthFlowTypeUserPasswordAuth;
- input.authParameters = challengeResponses;
-
- return [[self.pool.client initiateAuth:input] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse *> * _Nonnull task) {
- //if there was an error, it may be due to the device being forgotten, reset the device and retry if that is the case
- return [self forgetDeviceOnInitiateDeviceNotFoundError:task retryContinuation:^AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> *{
- return [self migrationAuth:username password:password validationData:validationData lastChallenge:lastChallenge];
- }];
- }];
- }
- }
-
-
- /**
- * Prompt developer to obtain custom challenge details
- */
- - (AWSTask<AWSCognitoIdentityUserSession*>*) customAuthInternal: (id<AWSCognitoIdentityCustomAuthentication>) authenticationDelegate {
- AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails *> *customAuthenticationDetails = [AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails *> new];
- AWSCognitoIdentityCustomAuthenticationInput *input = [[AWSCognitoIdentityCustomAuthenticationInput alloc] initWithChallengeParameters: [NSDictionary new]];
- [authenticationDelegate getCustomChallengeDetails:input customAuthCompletionSource:customAuthenticationDetails];
- return [[customAuthenticationDetails.task continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityCustomChallengeDetails *> * _Nonnull task) {
-
- //if first challenge is SRP auth
- if([self isFirstCustomStepSRP:task.result]){
- return [self startPasswordAuthenticationUI:nil];
- }else {
- return [[self performInitiateCustomAuthChallenge:task.result]
- continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse *> * _Nonnull task) {
- [authenticationDelegate didCompleteCustomAuthenticationStepWithError:task.error];
- if(task.isCancelled){
- return task;
- }
- if(task.error){
- //retry auth on error
- return [self customAuthInternal:authenticationDelegate];
- }else {
- //morph this initiate auth response into a respond to auth challenge response so it works as input to getSessionInternal
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse * response = [AWSCognitoIdentityProviderRespondToAuthChallengeResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [self getSessionInternal:[AWSTask taskWithResult:response]];
- }
- }];
- }
- }] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- if(task.error){
- //retry auth on error
- return [self customAuthInternal:authenticationDelegate];
- }else {
- return task;
- }
- }];
- }
-
- - (BOOL) isFirstCustomStepSRP: (AWSCognitoIdentityCustomChallengeDetails *) customAuthenticationDetails {
- return customAuthenticationDetails.initialChallengeName != nil && [@"SRP_A" isEqualToString: customAuthenticationDetails.initialChallengeName];
- }
-
-
- /**
- * Run initiate auth on challenge responses from end user for custom auth
- */
- - (AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse*>*) performInitiateCustomAuthChallenge: (AWSCognitoIdentityCustomChallengeDetails *) challengeDetails {
- AWSCognitoIdentityProviderInitiateAuthRequest *input = [AWSCognitoIdentityProviderInitiateAuthRequest new];
- input.clientId = self.pool.userPoolConfiguration.clientId;
- input.clientMetadata = [self.pool getValidationData:challengeDetails.validationData];
- input.analyticsMetadata = [self.pool analyticsMetadata];
- input.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
-
- NSMutableDictionary * authParameters = [[NSMutableDictionary alloc] initWithDictionary:challengeDetails.challengeResponses];
- [self addSecretHashDeviceKeyAndUsername:authParameters];
-
- if(challengeDetails.initialChallengeName != nil){
- [authParameters setObject:challengeDetails.initialChallengeName forKey:@"CHALLENGE_NAME"];
- }
-
- input.authFlow = AWSCognitoIdentityProviderAuthFlowTypeCustomAuth;
- input.authParameters = authParameters;
-
- return [[self.pool.client initiateAuth:input] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse *> * _Nonnull task) {
- //if there was an error, it may be due to the device being forgotten, reset the device and retry if that is the case
- return [self forgetDeviceOnInitiateDeviceNotFoundError:task retryContinuation:^AWSTask *{
- return [self performInitiateCustomAuthChallenge:challengeDetails];
- }];
- }];
- }
-
-
- /**
- * Run respond to auth challenges on challenge responses from end user for custom auth
- */
- - (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*>*) performRespondCustomAuthChallenge: (AWSCognitoIdentityCustomChallengeDetails *) challengeDetails session: (NSString *) session{
- NSMutableDictionary<NSString *,NSString *> *challengeResponses = [NSMutableDictionary new];
- [challengeResponses addEntriesFromDictionary:challengeDetails.challengeResponses];
-
- if([challengeResponses objectForKey:@"USERNAME"] != nil){
- self.username = [challengeResponses objectForKey:@"USERNAME"];
- }
- return [[self performRespondToAuthChallenge:challengeResponses challengeName:AWSCognitoIdentityProviderChallengeNameTypeCustomChallenge session:session] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- //if there was an error, it may be due to the device being forgotten, reset the device and retry if that is the case
- return [self forgetDeviceOnRespondDeviceNotFoundError:task retryContinuation:^AWSTask *{
- return [self performRespondCustomAuthChallenge:challengeDetails session:session];
- }];
- }];
- }
-
-
- /**
- * Run respond to auth challenges on new password required responses from end user
- */
- - (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*>*) performRespondToNewPasswordChallenge: (AWSCognitoIdentityNewPasswordRequiredDetails *) details session: (NSString *) session{
- NSMutableDictionary<NSString *,NSString *> *challengeResponses = [NSMutableDictionary new];
- [challengeResponses setObject:details.proposedPassword forKey:@"NEW_PASSWORD"];
-
- for(AWSCognitoIdentityUserAttributeType *userAttribute in details.userAttributes){
- [challengeResponses setObject:userAttribute.value forKey: [NSString stringWithFormat:@"%@%@", AWSCognitoIdentityUserUserAttributePrefix, userAttribute.name]];
- }
-
- return [self performRespondToAuthChallenge:challengeResponses challengeName:AWSCognitoIdentityProviderChallengeNameTypeNewPasswordRequired session:session];
- }
-
-
- /**
- * Run respond to auth challenges on select mfa responses from end user
- */
- - (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*>*) performRespondToSelectMfaChallenge: (AWSCognitoIdentitySelectMfaDetails *) details session: (NSString *) session{
- NSMutableDictionary<NSString *,NSString *> *challengeResponses = [NSMutableDictionary new];
- [challengeResponses setObject:details.selectedMfa forKey:@"ANSWER"];
- return [self performRespondToAuthChallenge:challengeResponses challengeName:AWSCognitoIdentityProviderChallengeNameTypeSelectMfaType session:session];
- }
-
-
- /**
- * Run respond to auth challenges
- */
- - (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*>*) performRespondToAuthChallenge: (NSMutableDictionary *) challengeResponses challengeName: (AWSCognitoIdentityProviderChallengeNameType) challengeName session: (NSString *) session{
- AWSCognitoIdentityProviderRespondToAuthChallengeRequest *request = [AWSCognitoIdentityProviderRespondToAuthChallengeRequest new];
- request.session = session;
- request.clientId = self.pool.userPoolConfiguration.clientId;
- request.challengeName = challengeName;
- request.analyticsMetadata = [self.pool analyticsMetadata];
- request.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- [self addSecretHashDeviceKeyAndUsername:challengeResponses];
- request.challengeResponses = challengeResponses;
-
- return [self.pool.client respondToAuthChallenge:request];
- }
-
- /**
- * Perform SRP based authentication (initiateAuth(SRP_AUTH) and respondToAuthChallenge) given a username and password. If lastChallenge is supplied it starts with respondToAuthChallenge instead of initiate.
- */
- - (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*>*) srpAuthInternal:(NSString *)username password:(NSString *)password validationData:(NSArray<AWSCognitoIdentityUserAttributeType*>*)validationData lastChallenge:(AWSCognitoIdentityProviderRespondToAuthChallengeResponse*) lastChallenge isInitialCustomChallenge:(BOOL) isInitialCustomChallenge {
- self.username = username;
- AWSCognitoIdentityProviderSrpHelper *srpHelper = [AWSCognitoIdentityProviderSrpHelper beginUserAuthentication:self.username password:password];
- NSMutableDictionary * challengeResponses = [[NSMutableDictionary alloc] initWithDictionary:@{@"SRP_A" : [srpHelper.clientState.publicA stringValueWithRadix:16]}];
- [self addSecretHashDeviceKeyAndUsername:challengeResponses];
-
- if(lastChallenge){
- AWSCognitoIdentityProviderRespondToAuthChallengeRequest *input = [AWSCognitoIdentityProviderRespondToAuthChallengeRequest new];
- input.clientId = self.pool.userPoolConfiguration.clientId;
- input.challengeName = lastChallenge.challengeName;
- input.challengeResponses = challengeResponses;
- input.session = lastChallenge.session;
- input.analyticsMetadata = [self.pool analyticsMetadata];
- input.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- return [[self.pool.client respondToAuthChallenge:input] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- //if there was an error, it may be due to the device being forgotten, reset the device and retry if that is the case
- return [[self forgetDeviceOnRespondDeviceNotFoundError:task retryContinuation:^AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> *{
- return [self srpAuthInternal:username password:password validationData:validationData lastChallenge:lastChallenge isInitialCustomChallenge:isInitialCustomChallenge];
- }] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse *> * _Nonnull task) {
- //morph this initiate auth response into a respond to auth challenge response so it works as input to srpAuthInternalStep2
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse * response = [AWSCognitoIdentityProviderRespondToAuthChallengeResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- //continue with second step of SRP auth
- return [self srpAuthInternalStep2:[AWSTask taskWithResult:response] srpHelper:srpHelper];
- }];
- }];
- }else{
- AWSCognitoIdentityProviderInitiateAuthRequest *input = [AWSCognitoIdentityProviderInitiateAuthRequest new];
- input.clientId = self.pool.userPoolConfiguration.clientId;
- input.clientMetadata = [self.pool getValidationData:validationData];
- input.analyticsMetadata = [self.pool analyticsMetadata];
- input.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- //based on whether this is custom auth or not set the auth flow
- if(isInitialCustomChallenge){
- input.authFlow = AWSCognitoIdentityProviderAuthFlowTypeCustomAuth;
- //set challenge name parameter to SRP_A
- [challengeResponses setObject:@"SRP_A" forKey:@"CHALLENGE_NAME"];
- }else {
- input.authFlow = AWSCognitoIdentityProviderAuthFlowTypeUserSrpAuth;
- }
-
-
- input.authParameters = challengeResponses;
-
- return [[self.pool.client initiateAuth:input] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse *> * _Nonnull task) {
- //if there was an error, it may be due to the device being forgotten, reset the device and retry if that is the case
- return [[self forgetDeviceOnInitiateDeviceNotFoundError:task retryContinuation:^AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> *{
- return [self srpAuthInternal:username password:password validationData:validationData lastChallenge:lastChallenge isInitialCustomChallenge:isInitialCustomChallenge];
- }] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse *> * _Nonnull task) {
- //morph this initiate auth response into a respond to auth challenge response so it works as input to getSessionInternal
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse * response = [AWSCognitoIdentityProviderRespondToAuthChallengeResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- //continue with second step of SRP auth
- return [self srpAuthInternalStep2:[AWSTask taskWithResult:response] srpHelper:srpHelper];
- }];
- }];
- }
- }
-
- - (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> *) srpAuthInternalStep2: (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> *) task srpHelper:(AWSCognitoIdentityProviderSrpHelper *) srpHelper {
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse *authDetails = task.result;
- AWSCognitoIdentityProviderSrpServerState *serverState =
- [AWSCognitoIdentityProviderSrpServerState
- serverStateForPoolName:[self.pool strippedPoolId]
- publicBHexString:authDetails.challengeParameters[@"SRP_B"]
- saltHexString:authDetails.challengeParameters[@"SALT"]
- derivedKeyInfo:AWSCognitoIdentityUserDerivedKeyInfo
- derivedKeySize:16
- serviceSecretBlock:[[NSData alloc] initWithBase64EncodedString:authDetails.challengeParameters[@"SECRET_BLOCK"] options:0]];
-
- self.username = authDetails.challengeParameters[@"USERNAME"];
- self.userIdForSRP = authDetails.challengeParameters[@"USER_ID_FOR_SRP"];
- srpHelper.clientState.userName = self.userIdForSRP;
-
- AWSCognitoIdentityProviderRespondToAuthChallengeRequest *authInput = [AWSCognitoIdentityProviderRespondToAuthChallengeRequest new];
- authInput.session = authDetails.session;
- authInput.challengeName = authDetails.challengeName;
- authInput.analyticsMetadata = [self.pool analyticsMetadata];
- authInput.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
-
- NSMutableDictionary * authParameters = [[NSMutableDictionary alloc] initWithDictionary:@{@"TIMESTAMP": [AWSCognitoIdentityProviderSrpHelper generateDateString:srpHelper.clientState.timestamp],
- @"PASSWORD_CLAIM_SECRET_BLOCK" : authDetails.challengeParameters[@"SECRET_BLOCK"],
- @"PASSWORD_CLAIM_SIGNATURE" : [[srpHelper completeAuthentication:serverState] base64EncodedStringWithOptions:0]
- }];
-
- [self addSecretHashDeviceKeyAndUsername:authParameters];
-
- authInput.challengeResponses = authParameters;
- authInput.clientId = self.pool.userPoolConfiguration.clientId;
- return [[self.pool.client respondToAuthChallenge:authInput] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull responseTask) {
- return [self forgetDeviceOnRespondDeviceNotFoundError:responseTask retryContinuation:^AWSTask *{
- return [self srpAuthInternalStep2:task srpHelper:srpHelper];
- }];
- }];
- }
-
-
- //Determine whether the error (if any) on the initiateAuth is a device not found error and if so forget the device and retry
- - (AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse*>*) forgetDeviceOnInitiateDeviceNotFoundError:(AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse*> * _Nonnull) task retryContinuation: (AWSTask<AWSCognitoIdentityProviderInitiateAuthResponse*>* (^_Nonnull)(void)) retryContinuation {
- if([self isDeviceNotFoundError:task.error]){
- [self forgetDeviceInternal];
- return retryContinuation();
- }
- return task;
- }
-
- //Determine whether the error (if any) on the respondToAuthChallenge is a device not found error and if so forget the device and retry
- - (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*>*) forgetDeviceOnRespondDeviceNotFoundError:(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*> * _Nonnull) task retryContinuation: (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*>* (^_Nonnull)(void)) retryContinuation {
- if([self isDeviceNotFoundError:task.error]){
- [self forgetDeviceInternal];
- return retryContinuation();
- }
- return task;
- }
-
- - (BOOL) isDeviceNotFoundError: (NSError *) error {
- return error != nil && error.code == AWSCognitoIdentityProviderErrorResourceNotFound && [@"Device does not exist." isEqualToString:error.userInfo[@"message"]];
- }
-
- /**
- * Perform SRP based authentication (initiateAuth(SRP_AUTH) and respondToAuthChallenge) given a username and password
- */
- - (AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse*>*) deviceAuthInternal:(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *>*) deviceChallengeResponse {
- AWSCognitoIdentityProviderRespondToAuthChallengeRequest *input = [AWSCognitoIdentityProviderRespondToAuthChallengeRequest new];
- input.clientId = self.pool.userPoolConfiguration.clientId;
- AWSCognitoIdentityUserDeviceCredentials *deviceCredentials = [self getDeviceCredentials];
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse * deviceChallenge = deviceChallengeResponse.result;
-
-
- AWSCognitoIdentityProviderSrpHelper *srpHelper = [AWSCognitoIdentityProviderSrpHelper beginUserAuthentication:deviceCredentials.deviceId password:deviceCredentials.deviceSecret];
- NSMutableDictionary * challengeResponses = [[NSMutableDictionary alloc] initWithDictionary:@{@"SRP_A" : [srpHelper.clientState.publicA stringValueWithRadix:16]}];
- [self addSecretHashDeviceKeyAndUsername:challengeResponses];
-
- input.challengeName = deviceChallenge.challengeName;
- input.session = deviceChallenge.session;
- input.challengeResponses = challengeResponses;
- input.analyticsMetadata = [self.pool analyticsMetadata];
- input.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- return [[self.pool.client respondToAuthChallenge:input] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
-
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse *authDetails = task.result;
- AWSCognitoIdentityProviderSrpServerState *serverState =
- [AWSCognitoIdentityProviderSrpServerState
-
- serverStateForPoolName:deviceCredentials.deviceGroup
- publicBHexString:authDetails.challengeParameters[@"SRP_B"]
- saltHexString:authDetails.challengeParameters[@"SALT"]
- derivedKeyInfo:AWSCognitoIdentityUserDerivedKeyInfo
- derivedKeySize:16
- serviceSecretBlock:[[NSData alloc] initWithBase64EncodedString:authDetails.challengeParameters[@"SECRET_BLOCK"] options:0]];
-
- AWSCognitoIdentityProviderRespondToAuthChallengeRequest *authInput = [AWSCognitoIdentityProviderRespondToAuthChallengeRequest new];
- authInput.session = authDetails.session;
- authInput.challengeName = authDetails.challengeName;
- authInput.analyticsMetadata = [self.pool analyticsMetadata];
- authInput.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- NSMutableDictionary * authParameters = [[NSMutableDictionary alloc] initWithDictionary:@{@"TIMESTAMP": [AWSCognitoIdentityProviderSrpHelper generateDateString:srpHelper.clientState.timestamp],
- @"PASSWORD_CLAIM_SECRET_BLOCK" : authDetails.challengeParameters[@"SECRET_BLOCK"],
- @"PASSWORD_CLAIM_SIGNATURE" : [[srpHelper completeAuthentication:serverState] base64EncodedStringWithOptions:0]
- }];
- [self addSecretHashDeviceKeyAndUsername:authParameters];
-
- authInput.challengeResponses = authParameters;
- authInput.clientId = self.pool.userPoolConfiguration.clientId;
- return [self.pool.client respondToAuthChallenge:authInput];
-
- }];
- }
-
- /**
- * Adds a device key to the authParameters dictionary if it is known for this username
- */
- -(void) addDeviceKey:(NSMutableDictionary<NSString *,NSString*> *) authParameters {
- AWSCognitoIdentityUserDeviceCredentials *deviceCredentials = [self getDeviceCredentials];
- if(deviceCredentials != nil){
- [authParameters setObject:deviceCredentials.deviceId forKey:@"DEVICE_KEY"];
- }
- }
-
- /**
- * Adds a SECRET_HASH and USERNAME and DEVICE_KEY to the authParameters dictionary.
- */
- -(void) addSecretHashDeviceKeyAndUsername:(NSMutableDictionary<NSString *,NSString*> *) authParameters {
- if(self.username == nil) {
- self.username = authParameters[@"USERNAME"];
- }
-
- [authParameters setObject:self.username forKey:@"USERNAME"];
- NSString* secretHash = [self.pool calculateSecretHash:self.username];
-
- if(secretHash != nil){
- [authParameters setObject:secretHash forKey:@"SECRET_HASH"];
- }
- [self addDeviceKey:authParameters];
- }
-
- /**
- * Invoke developer's ui to prompt user for mfa code and call enhanceAuth
- */
- -(AWSTask<AWSCognitoIdentityUserSession *>*) mfaAuthInternal: (NSString *) deliveryMedium destination:(NSString *) destination authState:(NSString *) authState challengeName: (AWSCognitoIdentityProviderChallengeNameType) challengeName authenticationDelegate:(id<AWSCognitoIdentityMultiFactorAuthentication>)authenticationDelegate{
- AWSTaskCompletionSource<NSString *> *mfaCode = [[AWSTaskCompletionSource<NSString *> alloc] init];
- AWSCognitoIdentityMultifactorAuthenticationInput* authenticationInput = [[AWSCognitoIdentityMultifactorAuthenticationInput alloc] initWithDeliveryMedium:deliveryMedium destination:destination];
- [authenticationDelegate getMultiFactorAuthenticationCode:authenticationInput mfaCodeCompletionSource:mfaCode];
- return [mfaCode.task
- continueWithSuccessBlock:^id _Nullable(AWSTask<NSString *> * _Nonnull task) {
- AWSCognitoIdentityProviderRespondToAuthChallengeRequest *mfaChallenge = [AWSCognitoIdentityProviderRespondToAuthChallengeRequest new];
- mfaChallenge.session = authState;
- mfaChallenge.challengeName = challengeName;
- mfaChallenge.clientId = self.pool.userPoolConfiguration.clientId;
-
- NSString * responseKey = @"SMS_MFA_CODE";
- if(AWSCognitoIdentityProviderChallengeNameTypeSoftwareTokenMfa == challengeName){
- responseKey = @"SOFTWARE_TOKEN_MFA_CODE";
- }
- NSMutableDictionary * challengeResponses = [[NSMutableDictionary alloc] initWithDictionary:@{responseKey: mfaCode.task.result}];
- [self addSecretHashDeviceKeyAndUsername:challengeResponses];
- mfaChallenge.challengeResponses = challengeResponses;
- mfaChallenge.analyticsMetadata = [self.pool analyticsMetadata];
- mfaChallenge.userContextData = [self.pool userContextData:self.username deviceId: [self asfDeviceId]];
-
- return [[[self.pool.client respondToAuthChallenge:mfaChallenge] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderRespondToAuthChallengeResponse *> * _Nonnull task) {
- AWSCognitoIdentityProviderRespondToAuthChallengeResponse *response = task.result;
- AWSCognitoIdentityProviderAuthenticationResultType * authResult = response.authenticationResult;
- AWSCognitoIdentityUserSession * session = [[AWSCognitoIdentityUserSession alloc] initWithIdToken:authResult.idToken accessToken:authResult.accessToken refreshToken:authResult.refreshToken expiresIn:authResult.expiresIn];
- //last step is to perform device auth if device key is supplied or we are being challenged with device auth
- if(authResult.latestDeviceMetadata != nil || response.challengeName == AWSCognitoIdentityProviderChallengeNameTypeDeviceSrpAuth){
- return [self performDeviceAuth: task session:session];
- }else{
- [self updateUsernameAndPersistTokens:session];
- return [AWSTask taskWithResult:session];
- }
- }] continueWithBlock:^id _Nullable(AWSTask * _Nonnull task) {
- [authenticationDelegate didCompleteMultifactorAuthenticationStepWithError:task.error];
- if([task isCancelled]){
- return task;
- }
- if(task.error){
- //retry on error
- return [self mfaAuthInternal:deliveryMedium destination:destination authState:authState challengeName: challengeName authenticationDelegate:authenticationDelegate];
- }else {
- return task;
- }
- }];
- }];
- }
-
- /**
- * Update this user's attributes
- */
- -(AWSTask<AWSCognitoIdentityUserUpdateAttributesResponse *>*) updateAttributes: (NSArray<AWSCognitoIdentityUserAttributeType *>*) attributes {
- AWSCognitoIdentityProviderUpdateUserAttributesRequest *request = [AWSCognitoIdentityProviderUpdateUserAttributesRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- NSMutableArray *userAttributes = [NSMutableArray new];
- request.userAttributes = userAttributes;
- for (AWSCognitoIdentityUserAttributeType * attribute in attributes) {
- AWSCognitoIdentityProviderAttributeType *apiAttribute = [AWSCognitoIdentityProviderAttributeType new];
- apiAttribute.name = attribute.name;
- apiAttribute.value = attribute.value;
- [userAttributes addObject: apiAttribute];
- }
- return [[self.pool.client updateUserAttributes:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderUpdateUserAttributesResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserUpdateAttributesResponse * response = [AWSCognitoIdentityUserUpdateAttributesResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- // drop id and access token to force a refresh
- [self clearSession];
- return [AWSTask taskWithResult:response];
- }];
- }];
- }
-
- /**
- * Delete the attributes specified by attributeNames
- */
- -(AWSTask<AWSCognitoIdentityUserDeleteAttributesResponse *>*) deleteAttributes: (NSArray<NSString *>*) attributeNames {
- AWSCognitoIdentityProviderDeleteUserAttributesRequest *request = [AWSCognitoIdentityProviderDeleteUserAttributesRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- request.userAttributeNames = attributeNames;
- return [[self.pool.client deleteUserAttributes:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderDeleteUserAttributesResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserDeleteAttributesResponse * response = [AWSCognitoIdentityUserDeleteAttributesResponse new];
- return [AWSTask taskWithResult:response];
- }];
- }];
- }
-
-
- /**
- * Verify a user attribute upon receiving the verification code.
- */
- -(AWSTask<AWSCognitoIdentityUserVerifyAttributeResponse *>*) verifyAttribute: (NSString *) attributeName code: (NSString *) code {
- AWSCognitoIdentityProviderVerifyUserAttributeRequest *request = [AWSCognitoIdentityProviderVerifyUserAttributeRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- request.attributeName = attributeName;
- request.code = code;
- return [[self.pool.client verifyUserAttribute:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderVerifyUserAttributeResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserVerifyAttributeResponse * response = [AWSCognitoIdentityUserVerifyAttributeResponse new];
- return [AWSTask taskWithResult:response];
- }];
- }];
-
- }
-
- /**
- * Request a verification code to verify an attribute.
- */
- -(AWSTask<AWSCognitoIdentityUserGetAttributeVerificationCodeResponse *>*) getAttributeVerificationCode: (NSString *) attributeName {
- AWSCognitoIdentityProviderGetUserAttributeVerificationCodeRequest *request = [AWSCognitoIdentityProviderGetUserAttributeVerificationCodeRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- request.attributeName = attributeName;
- return [[self.pool.client getUserAttributeVerificationCode:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderGetUserAttributeVerificationCodeResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserGetAttributeVerificationCodeResponse * response = [AWSCognitoIdentityUserGetAttributeVerificationCodeResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }];
- }
-
- /**
- * Set the user settings for this user such as MFA
- */
- -(AWSTask<AWSCognitoIdentityUserSetUserSettingsResponse *>*) setUserSettings: (AWSCognitoIdentityUserSettings *) settings; {
-
- AWSCognitoIdentityProviderSetUserSettingsRequest *request = [AWSCognitoIdentityProviderSetUserSettingsRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- NSMutableArray * mfaOptions = [NSMutableArray new];
- for(AWSCognitoIdentityUserMFAOption* mfaOption in settings.mfaOptions){
- [mfaOptions addObject:[mfaOption mfaOptionTypeValue]];
- }
- request.MFAOptions = mfaOptions;
- return [[self.pool.client setUserSettings:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderSetUserSettingsResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserSetUserSettingsResponse * response = [AWSCognitoIdentityUserSetUserSettingsResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }];
- }
-
-
- /**
- * Set the user settings for this user such as MFA
- */
- -(AWSTask<AWSCognitoIdentityUserSetUserSettingsResponse *>*) setUserMfaPreference: (AWSCognitoIdentityUserMfaPreferences*) settings; {
-
- AWSCognitoIdentityProviderSetUserMFAPreferenceRequest *request = [AWSCognitoIdentityProviderSetUserMFAPreferenceRequest new];
- if(settings.smsMfa != nil){
- AWSCognitoIdentityProviderSMSMfaSettingsType* smsMfaSettings = [AWSCognitoIdentityProviderSMSMfaSettingsType new];
- smsMfaSettings.enabled = [NSNumber numberWithBool:settings.smsMfa.enabled];
- smsMfaSettings.preferredMfa = [NSNumber numberWithBool:settings.smsMfa.preferred];
- request.SMSMfaSettings = smsMfaSettings;
- }
- if(settings.softwareTokenMfa != nil){
- AWSCognitoIdentityProviderSoftwareTokenMfaSettingsType* softwareTokenMfaSettings = [AWSCognitoIdentityProviderSoftwareTokenMfaSettingsType new];
- softwareTokenMfaSettings.enabled = [NSNumber numberWithBool:settings.softwareTokenMfa.enabled];
- softwareTokenMfaSettings.preferredMfa = [NSNumber numberWithBool:settings.softwareTokenMfa.preferred];
- request.softwareTokenMfaSettings = softwareTokenMfaSettings;
- }
-
- return [[[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- return [self.pool.client setUserMFAPreference:request];
- }] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderSetUserMFAPreferenceResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserSetUserMfaPreferenceResponse * response = [AWSCognitoIdentityUserSetUserMfaPreferenceResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }
-
-
- /**
- * Start the process of associating a software token
- */
- -(AWSTask<AWSCognitoIdentityUserAssociateSoftwareTokenResponse *>*) associateSoftwareToken {
- AWSCognitoIdentityProviderAssociateSoftwareTokenRequest * request = [AWSCognitoIdentityProviderAssociateSoftwareTokenRequest new];
- return [[[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- return [self.pool.client associateSoftwareToken:request];
- }] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserAssociateSoftwareTokenResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserAssociateSoftwareTokenResponse * response = [AWSCognitoIdentityUserAssociateSoftwareTokenResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }
-
-
- /**
- * Complete the process of associating a software token by verifying the code and setting device friendly name
- */
- -(AWSTask<AWSCognitoIdentityUserVerifySoftwareTokenResponse *>*) verifySoftwareToken: (NSString*) userCode friendlyDeviceName: (NSString* _Nullable) friendlyDeviceName {
-
- AWSCognitoIdentityProviderVerifySoftwareTokenRequest *request = [AWSCognitoIdentityProviderVerifySoftwareTokenRequest new];
- request.friendlyDeviceName = friendlyDeviceName;
- request.userCode = userCode;
- return [[[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- return [self.pool.client verifySoftwareToken:request];
- }] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderVerifySoftwareTokenResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserVerifySoftwareTokenResponse * response = [AWSCognitoIdentityUserVerifySoftwareTokenResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }
-
- /**
- * Delete this user
- */
- -(AWSTask*) deleteUser {
- AWSCognitoIdentityProviderDeleteUserRequest *request = [AWSCognitoIdentityProviderDeleteUserRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- return [self.pool.client deleteUser:request];
- }];
-
- }
-
- -(void) signOut {
- if(self.username){
- NSArray *keys = self.pool.keychain.allKeys;
- NSString *keyChainPrefix = [[self keyChainNamespaceClientId] stringByAppendingString:@"."];
- for (NSString *key in keys) {
- //clear tokens associated with this user
- if([key hasPrefix:keyChainPrefix]){
- [self.pool.keychain removeItemForKey:key];
- }
- }
- }
- }
-
- -(void) signOutAndClearLastKnownUser{
- [self signOut];
- [self.pool clearLastKnownUser];
- }
-
- -(void) clearSession{
- if(self.username){
- NSString * keyChainNamespace = [self keyChainNamespaceClientId];
- NSString * idTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserIdToken];
- NSString * accessTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserAccessToken];
- [self.pool.keychain removeItemForKey:idTokenKey];
- [self.pool.keychain removeItemForKey:accessTokenKey];
- }
- }
-
- - (NSString *) refreshTokenFromKeyChain: (NSString *) keyChainNamespace {
- NSString * refreshTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserRefreshToken];
- NSString * refreshToken = self.pool.keychain[refreshTokenKey];
- return refreshToken;
- }
-
- -(BOOL) isSignedIn {
- if(self.username == nil){
- return NO;
- }
-
- NSString * keyChainNamespace = [self keyChainNamespaceClientId];
- NSString * refreshToken = [self refreshTokenFromKeyChain:keyChainNamespace];
- return refreshToken != nil;
- }
-
- - (AWSTask<AWSCognitoIdentityUserGlobalSignOutResponse *> *) globalSignOut {
- AWSCognitoIdentityProviderGlobalSignOutRequest *request = [AWSCognitoIdentityProviderGlobalSignOutRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- return [[self.pool.client globalSignOut:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderGlobalSignOutResponse *> * _Nonnull task) {
- [self signOut];
- return task;
- }];
- }];
- }
-
- - (AWSTask<AWSCognitoIdentityUserListDevicesResponse *> *) listDevices:(int) limit paginationToken:(NSString * _Nullable) paginationToken {
- AWSCognitoIdentityProviderListDevicesRequest *request = [AWSCognitoIdentityProviderListDevicesRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- request.paginationToken = paginationToken;
- request.limit = [NSNumber numberWithInt:limit];
- return [[self.pool.client listDevices:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderListDevicesResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserListDevicesResponse * response = [AWSCognitoIdentityUserListDevicesResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }];
- }
-
- - (AWSTask<AWSCognitoIdentityUserUpdateDeviceStatusResponse *> *) updateDeviceStatus: (NSString *) deviceId remembered:(BOOL) remembered {
- AWSCognitoIdentityProviderUpdateDeviceStatusRequest *request = [AWSCognitoIdentityProviderUpdateDeviceStatusRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- request.deviceKey = deviceId;
- request.deviceRememberedStatus = remembered ? AWSCognitoIdentityProviderDeviceRememberedStatusTypeRemembered : AWSCognitoIdentityProviderDeviceRememberedStatusTypeNotRemembered;
- return [[self.pool.client updateDeviceStatus:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderUpdateDeviceStatusRequest *> * _Nonnull task) {
- AWSCognitoIdentityUserUpdateDeviceStatusResponse * response = [AWSCognitoIdentityUserUpdateDeviceStatusResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }];
- }
-
-
- - (AWSTask<AWSCognitoIdentityUserUpdateDeviceStatusResponse *> *) updateDeviceStatus: (BOOL) remembered {
- AWSCognitoIdentityUserDeviceCredentials * credentials = [self getDeviceCredentials];
- if(credentials){
- return [self updateDeviceStatus:[self getDeviceCredentials].deviceId remembered:remembered];
- }else{
- return [self deviceNotTrackedError];
- }
- }
-
-
- - (AWSTask<AWSCognitoIdentityUserGetDeviceResponse *> *) getDevice: (NSString *) deviceId {
- AWSCognitoIdentityProviderGetDeviceRequest *request = [AWSCognitoIdentityProviderGetDeviceRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- request.deviceKey = deviceId;
- return [[self.pool.client getDevice:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderGetDeviceResponse *> * _Nonnull task) {
- AWSCognitoIdentityUserGetDeviceResponse * response = [AWSCognitoIdentityUserGetDeviceResponse new];
- [response aws_copyPropertiesFromObject:task.result];
- return [AWSTask taskWithResult:response];
- }];
- }];
- }
-
- - (AWSTask<AWSCognitoIdentityUserGetDeviceResponse *> *) getDevice {
- AWSCognitoIdentityUserDeviceCredentials * credentials = [self getDeviceCredentials];
- if(credentials){
- return [self getDevice:credentials.deviceId];
- }else{
- return [self deviceNotTrackedError];
- }
- }
-
- - (AWSTask *) forgetDevice {
- AWSCognitoIdentityUserDeviceCredentials * credentials = [self getDeviceCredentials];
- if(credentials){
- return [self forgetDevice:credentials.deviceId];
- }else{
- return [self deviceNotTrackedError];
- }
- }
-
- - (AWSTask *) deviceNotTrackedError {
- return [AWSTask taskWithError:[NSError errorWithDomain:AWSCognitoIdentityProviderErrorDomain code:AWSCognitoIdentityProviderClientErrorDeviceNotTracked userInfo:@{NSLocalizedDescriptionKey: @"This device does not have an id, either it was never tracked or previously forgotten."}]];
- }
-
-
- - (AWSTask *) forgetDevice: (NSString *) deviceId {
- AWSCognitoIdentityProviderForgetDeviceRequest * request = [AWSCognitoIdentityProviderForgetDeviceRequest new];
- return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
- request.accessToken = task.result.accessToken.tokenString;
- request.deviceKey = deviceId;
- return [[self.pool.client forgetDevice:request] continueWithSuccessBlock:^id _Nullable(AWSTask * _Nonnull task) {
-
- AWSCognitoIdentityUserDeviceCredentials * credentials = [self getDeviceCredentials];
- //if it was this device that was forgotten and call was successful, clear cached device.
- if(credentials && credentials.deviceId && [credentials.deviceId isEqualToString:deviceId]){
- [self forgetDeviceInternal];
- }
- return task;
- }];
- }];
- }
-
- - (void) updateUsernameAndPersistTokens: (AWSCognitoIdentityUserSession *) session {
- [self.pool setCurrentUser:self.username];
- NSString * keyChainNamespace = [self keyChainNamespaceClientId];
- if(session.idToken){
- NSString * idTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserIdToken];
- self.pool.keychain[idTokenKey] = session.idToken.tokenString;
- }
- if(session.accessToken){
- NSString * accessTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserAccessToken];
- self.pool.keychain[accessTokenKey] = session.accessToken.tokenString;
- }
- if(session.refreshToken){
- NSString * refreshTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserRefreshToken];
- self.pool.keychain[refreshTokenKey] = session.refreshToken.tokenString;
- }
- if(session.expirationTime){
- NSString * expirationTokenKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserTokenExpiration];
- self.pool.keychain[expirationTokenKey] = [session.expirationTime aws_stringValue:AWSDateISO8601DateFormat1];
- }
- }
-
- - (void) persistDevice:(NSString *) deviceKey deviceSecret: (NSString *) deviceSecret deviceGroup: (NSString *) deviceGroup {
- NSString * keyChainNamespace = [self keyChainNamespacePoolId];
- if(deviceKey){
- NSString * deviceIdKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserDeviceId];
- self.pool.keychain[deviceIdKey] = deviceKey;
- }
- if(deviceSecret){
- NSString * deviceSecretKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserDeviceSecret];
- self.pool.keychain[deviceSecretKey] = deviceSecret;
- }
-
- if(deviceGroup){
- NSString * deviceGroupKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserDeviceGroup];
- self.pool.keychain[deviceGroupKey] = deviceGroup;
- }
- }
-
- - (void) forgetDeviceInternal {
- NSString * keyChainNamespace = [self keyChainNamespacePoolId];
- NSString * deviceIdKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserDeviceId];
- self.pool.keychain[deviceIdKey] = nil;
- NSString * deviceSecretKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserDeviceSecret];
- self.pool.keychain[deviceSecretKey] = nil;
- NSString * deviceGroupKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserDeviceGroup];
- self.pool.keychain[deviceGroupKey] = nil;
- }
-
- - (AWSCognitoIdentityUserDeviceCredentials *) getDeviceCredentials {
- AWSCognitoIdentityUserDeviceCredentials *deviceCredentials = [[AWSCognitoIdentityUserDeviceCredentials alloc] initWithUser:self];
- if(deviceCredentials.deviceId && deviceCredentials.deviceSecret){
- return deviceCredentials;
- }else {
- return nil;
- }
- }
-
- - (NSString *) keyChainNamespaceClientId {
- return [NSString stringWithFormat:@"%@.%@", self.pool.userPoolConfiguration.clientId, self.username];
- }
-
- - (NSString *) keyChainNamespacePoolId {
- return [NSString stringWithFormat:@"%@.%@", self.pool.userPoolConfiguration.poolId, self.username];
- }
-
- - (NSString *) asfDeviceId {
- NSString *asfDeviceId = [self getDeviceCredentials].deviceId;
- if(asfDeviceId == nil){
- NSString * keyChainNamespace = [self keyChainNamespacePoolId];
- NSString * asfDeviceIdKey = [self keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserAsfDeviceId];
- asfDeviceId = self.pool.keychain[asfDeviceIdKey];
- if(asfDeviceId == nil){
- asfDeviceId = [[[NSUUID UUID] UUIDString] lowercaseString];
- self.pool.keychain[asfDeviceIdKey] = asfDeviceId;
- }
- }
- return asfDeviceId;
- }
-
- /**
- * Get a namespaced keychain key given a namespace and key
- */
- - (NSString *) keyChainKey: (NSString *) namespace key:(const NSString *) key {
- return [NSString stringWithFormat:@"%@.%@", namespace, key];
- }
-
- - (NSString*) strippedPoolName {
- return [self.pool.userPoolConfiguration.poolId substringFromIndex:[self.pool.userPoolConfiguration.poolId rangeOfString:@"_" ].location+1];
- }
-
- - (NSString*) deviceId {
- AWSCognitoIdentityUserDeviceCredentials *deviceCredentials = [self getDeviceCredentials];
- return deviceCredentials?deviceCredentials.deviceId:nil;
- }
-
- @end
-
- @implementation AWSCognitoIdentityUserSession
-
- -(instancetype) initWithIdToken:(NSString *)idToken accessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken expiresIn:(NSNumber *) expiresIn {
- self = [self initWithIdToken:idToken accessToken:accessToken refreshToken:refreshToken expirationTime:[NSDate dateWithTimeIntervalSinceNow:expiresIn.doubleValue]];
- return self;
- }
-
- -(instancetype) initWithIdToken:(NSString *)idToken accessToken:(NSString *)accessToken refreshToken:(NSString *)refreshToken expirationTime:(NSDate *) expirationTime {
- self = [super init];
- if(self != nil) {
- self.idToken = [[AWSCognitoIdentityUserSessionToken alloc] initWithToken:idToken];
- self.accessToken = [[AWSCognitoIdentityUserSessionToken alloc] initWithToken:accessToken];
- self.refreshToken = [[AWSCognitoIdentityUserSessionToken alloc] initWithToken:refreshToken];
- self.expirationTime = expirationTime;
- }
- return self;
- }
- @end
-
- @implementation AWSCognitoIdentityUserSessionToken
-
- -(instancetype) initWithToken:(NSString *)token {
- if(token == nil){
- return nil;
- }
- self = [super init];
- if(self != nil) {
- self.tokenString = token;
- }
- return self;
- }
-
- -(NSDictionary<NSString *, NSString*> *) claims {
- return [self tokenClaims];
- }
-
- -(NSDictionary<NSString *, id> *) tokenClaims {
- NSDictionary * result = nil;
- NSArray *pieces = [self.tokenString componentsSeparatedByString:@"."];
- if(pieces.count > 2){
- NSString * claims = pieces[1];
- //JWT is not padded with =, pad it if necessary
- NSUInteger paddedLength = claims.length + (4 - (claims.length % 4)) % 4;;
- claims = [claims stringByPaddingToLength:paddedLength withString:@"=" startingAtIndex:0];
-
- NSData * claimsData = [[NSData alloc] initWithBase64EncodedString:claims options:NSDataBase64DecodingIgnoreUnknownCharacters];
- NSError *error = nil;
- if(claimsData != nil){
- result = [NSJSONSerialization JSONObjectWithData:claimsData options:kNilOptions error:&error];
- if(error) {
- AWSDDLogError(@"Unable to deserialize token claims: %@", error);
- }
- } else {
- AWSDDLogError(@"Token is not valid base64");
- }
- }
- return result;
- }
-
- @end
-
- @implementation AWSCognitoIdentityUserSettings
-
- @end
-
-
- @implementation AWSCognitoIdentityUserMfaPreferences
-
- @end
-
- @implementation AWSCognitoIdentityUserMfaType
- - (instancetype) initWithEnabled:(BOOL) enabled preferred:(BOOL) preferred {
- if(self = [super init]){
- self.enabled = enabled;
- self.preferred = preferred;
- }
- return self;
- }
- @end
-
- @implementation AWSCognitoIdentityUserMFAOption
-
- - (AWSCognitoIdentityProviderMFAOptionType *) mfaOptionTypeValue{
- AWSCognitoIdentityProviderMFAOptionType *result = [AWSCognitoIdentityProviderMFAOptionType new];
- [result aws_copyPropertiesFromObject:self];
- return result;
- }
- @end
-
- @implementation AWSCognitoIdentityUserAttributeType
- - (instancetype) initWithName: (NSString *) name value: (NSString *) value{
- if(self = [super init]){
- self.name = name;
- self.value = value;
- }
- return self;
- }
- @end
-
- @implementation AWSCognitoIdentityUserConfirmSignUpResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserResendConfirmationCodeResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserGetDetailsResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserForgotPasswordResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserConfirmForgotPasswordResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserChangePasswordResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserUpdateAttributesResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserDeleteAttributesResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserVerifyAttributeResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserGetAttributeVerificationCodeResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserSetUserSettingsResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserListDevicesResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserUpdateDeviceStatusResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserGlobalSignOutResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserGetDeviceResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserAssociateSoftwareTokenResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserVerifySoftwareTokenResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserSetUserMfaPreferenceResponse
-
- @end
-
- @implementation AWSCognitoIdentityUserDeviceCredentials
- - (instancetype) initWithUser:(AWSCognitoIdentityUser *) user {
- if(self = [super init]){
- _user = user;
- }
- return self;
- }
-
- - (NSString *) deviceId {
- NSString * keyChainNamespace = [self.user keyChainNamespacePoolId];
- NSString * deviceIdKey = [self.user keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserDeviceId];
- return self.user.pool.keychain[deviceIdKey];
- }
-
- - (NSString *) deviceSecret {
- NSString * keyChainNamespace = [self.user keyChainNamespacePoolId];
- NSString * deviceSecretKey = [self.user keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserDeviceSecret];
- return self.user.pool.keychain[deviceSecretKey];
- }
-
- - (NSString *) deviceGroup {
- NSString * keyChainNamespace = [self.user keyChainNamespacePoolId];
- NSString * deviceGroupKey = [self.user keyChainKey:keyChainNamespace key:AWSCognitoIdentityUserDeviceGroup];
- return self.user.pool.keychain[deviceGroupKey];
- }
- @end
|