Skip to content

Commit

Permalink
[AWSMobileClient] Support ClientMetaData in verifyUserAttribute, rese…
Browse files Browse the repository at this point in the history
…ndSignUpCode, updateUserAttributes (#2872)
  • Loading branch information
lawmicha committed Jul 27, 2020
1 parent d69516a commit 60d3bd3
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 26 deletions.
26 changes: 19 additions & 7 deletions AWSAuthSDK/Sources/AWSMobileClient/AWSMobileClientExtensions.swift
Expand Up @@ -407,18 +407,24 @@ extension AWSMobileClient {
///
/// - Parameters:
/// - username: username of the user who wants a new registration code.
/// - clientMetaData: A map of custom key-value pairs that you can provide as input for any
/// custom workflows that this action triggers.
/// - completionHandler: completionHandler which will be called when a result is available.
public func resendSignUpCode(username: String, completionHandler: @escaping ((SignUpResult?, Error?) -> Void)) {
public func resendSignUpCode(username: String,
clientMetaData: [String:String] = [:],
completionHandler: @escaping ((SignUpResult?, Error?) -> Void)) {
if let uname = self.userpoolOpsHelper.signUpUser?.username, uname == username {
resendSignUpCode(user: self.userpoolOpsHelper.signUpUser!, completionHandler: completionHandler)
resendSignUpCode(user: self.userpoolOpsHelper.signUpUser!, clientMetaData: clientMetaData, completionHandler: completionHandler)
} else {
let user = self.userPoolClient?.getUser(username)
resendSignUpCode(user: user!, completionHandler: completionHandler)
resendSignUpCode(user: user!, clientMetaData: clientMetaData, completionHandler: completionHandler)
}
}

internal func resendSignUpCode(user: AWSCognitoIdentityUser, completionHandler: @escaping ((SignUpResult?, Error?) -> Void)) {
user.resendConfirmationCode().continueWith(block: { (task) -> Any? in
internal func resendSignUpCode(user: AWSCognitoIdentityUser,
clientMetaData: [String:String] = [:],
completionHandler: @escaping ((SignUpResult?, Error?) -> Void)) {
user.resendConfirmationCode(clientMetaData).continueWith(block: { (task) -> Any? in
if let error = task.error {
completionHandler(nil, AWSMobileClientError.makeMobileClientError(from: error))
} else if let result = task.result {
Expand Down Expand Up @@ -821,30 +827,36 @@ extension AWSMobileClient {
///
/// - Parameters:
/// - attributeName: name of the attribute.
/// - clientMetaData: A map of custom key-value pairs that you can provide as input for any
/// custom workflows that this action triggers.
/// - completionHandler: completionHandler which will be called when the result is avilable.
public func verifyUserAttribute(attributeName: String,
clientMetaData: [String:String] = [:],
completionHandler: @escaping ((UserCodeDeliveryDetails?, Error?) -> Void)) {
guard self.federationProvider == .userPools || self.federationProvider == .hostedUI else {
completionHandler(nil, AWSMobileClientError.notSignedIn(message: notSignedInErrorMessage))
return
}
let userDetails = AWSMobileClientUserDetails(with: self.userpoolOpsHelper.currentActiveUser!)
userDetails.verifyUserAttribute(attributeName: attributeName, completionHandler: completionHandler)
userDetails.verifyUserAttribute(attributeName: attributeName, clientMetaData: clientMetaData, completionHandler: completionHandler)
}

/// Update the attributes for a user.
///
/// - Parameters:
/// - attributeMap: the attribute map of the user.
/// - clientMetaData: A map of custom key-value pairs that you can provide as input for any
/// custom workflows that this action triggers.
/// - completionHandler: completionHandler which will be called when the result is avilable.
public func updateUserAttributes(attributeMap: [String: String],
clientMetaData: [String:String] = [:],
completionHandler: @escaping (([UserCodeDeliveryDetails]?, Error?) -> Void)) {
guard self.federationProvider == .userPools || self.federationProvider == .hostedUI else {
completionHandler(nil, AWSMobileClientError.notSignedIn(message: notSignedInErrorMessage))
return
}
let userDetails = AWSMobileClientUserDetails(with: self.userpoolOpsHelper.currentActiveUser!)
userDetails.updateUserAttributes(attributeMap: attributeMap, completionHandler: completionHandler)
userDetails.updateUserAttributes(attributeMap: attributeMap, clientMetaData: clientMetaData, completionHandler: completionHandler)
}

/// Fetches the attributes for logged in user.
Expand Down
Expand Up @@ -33,9 +33,14 @@ internal class AWSMobileClientUserDetails {
///
/// - Parameters:
/// - attributeName: name of the attribute.
/// - clientMetaData: A map of custom key-value pairs that you can provide as input for any
/// custom workflows that this action triggers.
/// - completionHandler: completionHandler which will be called when the result is avilable.
public func verifyUserAttribute(attributeName: String, completionHandler: @escaping ((UserCodeDeliveryDetails?, Error?) -> Void)) {
self.cognitoIdentityUser.getAttributeVerificationCode(attributeName).continueWith { (task) -> Any? in
public func verifyUserAttribute(attributeName: String,
clientMetaData: [String:String] = [:],
completionHandler: @escaping ((UserCodeDeliveryDetails?, Error?) -> Void)) {
self.cognitoIdentityUser.getAttributeVerificationCode(attributeName,
clientMetaData: clientMetaData).continueWith { (task) -> Any? in
if let error = task.error {
completionHandler(nil, AWSMobileClientError.makeMobileClientError(from: error))
} else if let result = task.result {
Expand All @@ -53,10 +58,12 @@ internal class AWSMobileClientUserDetails {
///
/// - Parameters:
/// - attributeMap: the attribute map of the user.
/// - clientMetaData: A map of custom key-value pairs that you can provide as input for any
/// custom workflows that this action triggers.
/// - completionHandler: completionHandler which will be called when the result is avilable.
public func updateUserAttributes(attributeMap: [String: String], completionHandler: @escaping (([UserCodeDeliveryDetails]?, Error?) -> Void)) {
public func updateUserAttributes(attributeMap: [String: String], clientMetaData: [String:String] = [:], completionHandler: @escaping (([UserCodeDeliveryDetails]?, Error?) -> Void)) {
let attributes = attributeMap.map {AWSCognitoIdentityUserAttributeType.init(name: $0, value: $1) }
self.cognitoIdentityUser.update(attributes).continueWith { (task) -> Any? in
self.cognitoIdentityUser.update(attributes, clientMetaData: clientMetaData).continueWith { (task) -> Any? in
if let error = task.error {
completionHandler(nil, AWSMobileClientError.makeMobileClientError(from: error))
} else if let result = task.result {
Expand Down
Expand Up @@ -30,7 +30,8 @@ class AWSMobileClientTests: AWSMobileClientTestBase {
signUpUser(username: username)

let verificationCodeSent = expectation(description: "verification code should be sent via email.")
AWSMobileClient.default().resendSignUpCode(username: username) { (result, error) in
let clientMetaData = ["client": "metadata"]
AWSMobileClient.default().resendSignUpCode(username: username, clientMetaData: clientMetaData) { (result, error) in
if let error = error {
XCTFail("Failed due to error: \(error.localizedDescription)")
return
Expand Down
Expand Up @@ -16,8 +16,8 @@ class AWSMobileClientUserAttributeTests: AWSMobileClientTestBase {
signUpAndVerifyUser(username: username)
signIn(username: username)
let verifyAttrExpectation = expectation(description: "verify attribute expectation.")

AWSMobileClient.default().verifyUserAttribute(attributeName: "email") { (codeDeliveryDetails, error) in
let clientMetaData = ["client": "metadata"]
AWSMobileClient.default().verifyUserAttribute(attributeName: "email", clientMetaData: clientMetaData) { (codeDeliveryDetails, error) in
if let codeDeliveryDetails = codeDeliveryDetails {
print(codeDeliveryDetails.deliveryMedium)
} else if let error = error {
Expand Down Expand Up @@ -63,8 +63,10 @@ class AWSMobileClientUserAttributeTests: AWSMobileClientTestBase {
"custom:mutableStringAttr1": "new value for previously set attribute",
"custom:mutableStringAttr2": "value for never-before-set attribute"
]

AWSMobileClient.default().updateUserAttributes(attributeMap: newUserAttributes) { result, error in
let clientMetaData = ["client": "metadata"]

AWSMobileClient.default().updateUserAttributes(attributeMap: newUserAttributes,
clientMetaData: clientMetaData) { result, error in
defer {
updateUserAttributesResultHandlerInvoked.fulfill()
}
Expand Down Expand Up @@ -106,9 +108,6 @@ class AWSMobileClientUserAttributeTests: AWSMobileClientTestBase {
wait(for: [getUserAttributesResultHandlerInvoked], timeout: 5)
}




/// Test to verify that tokens are valid after an update attritbue
/// Note: This test relies on the configuration of the test UserPools to have two mutable custom attributes:
/// custom:mutableStringAttr1;
Expand Down
8 changes: 8 additions & 0 deletions AWSCognitoIdentityProvider/AWSCognitoIdentityUser.h
Expand Up @@ -96,6 +96,8 @@ NS_ASSUME_NONNULL_BEGIN
/**
Resend the confirmation code sent during sign up
*/
- (AWSTask<AWSCognitoIdentityUserResendConfirmationCodeResponse *> *)resendConfirmationCode: (nullable NSDictionary<NSString *, NSString*> *) clientMetaData;

- (AWSTask<AWSCognitoIdentityUserResendConfirmationCodeResponse *> *)resendConfirmationCode;

/**
Expand Down Expand Up @@ -149,6 +151,9 @@ NS_ASSUME_NONNULL_BEGIN
/**
Update this user's attributes
*/
- (AWSTask<AWSCognitoIdentityUserUpdateAttributesResponse *> *)updateAttributes:(NSArray<AWSCognitoIdentityUserAttributeType *> *)attributes
clientMetaData:(nullable NSDictionary<NSString *, NSString*> *) clientMetaData;

- (AWSTask<AWSCognitoIdentityUserUpdateAttributesResponse *> *)updateAttributes:(NSArray<AWSCognitoIdentityUserAttributeType *> *)attributes;

/**
Expand All @@ -166,6 +171,9 @@ NS_ASSUME_NONNULL_BEGIN
/**
Request a verification code to verify an attribute.
*/
- (AWSTask<AWSCognitoIdentityUserGetAttributeVerificationCodeResponse *> *)getAttributeVerificationCode:(NSString *)attributeName
clientMetaData:(nullable NSDictionary<NSString *, NSString*> *) clientMetaData;

- (AWSTask<AWSCognitoIdentityUserGetAttributeVerificationCodeResponse *> *)getAttributeVerificationCode:(NSString *)attributeName;

/**
Expand Down
26 changes: 21 additions & 5 deletions AWSCognitoIdentityProvider/AWSCognitoIdentityUser.m
Expand Up @@ -137,22 +137,26 @@ -(instancetype) initWithUsername: (NSString *)username pool:(AWSCognitoIdentityU
clientMetaData:nil];
}


-(AWSTask<AWSCognitoIdentityUserResendConfirmationCodeResponse *> *) resendConfirmationCode {
-(AWSTask<AWSCognitoIdentityUserResendConfirmationCodeResponse *> *) resendConfirmationCode: (nullable NSDictionary<NSString *,NSString *> *)clientMetaData {
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]];

request.clientMetadata = clientMetaData;

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<AWSCognitoIdentityUserResendConfirmationCodeResponse *> *) resendConfirmationCode {
return [self resendConfirmationCode: nil];
}

-(AWSTask<AWSCognitoIdentityUserChangePasswordResponse *>*) changePassword: (NSString*)currentPassword proposedPassword: (NSString *)proposedPassword {
AWSCognitoIdentityProviderChangePasswordRequest* request = [AWSCognitoIdentityProviderChangePasswordRequest new];
request.previousPassword = currentPassword;
Expand Down Expand Up @@ -1141,12 +1145,14 @@ -(void) addSecretHashDeviceKeyAndUsername:(NSMutableDictionary<NSString *,NSStri
/**
* Update this user's attributes
*/
-(AWSTask<AWSCognitoIdentityUserUpdateAttributesResponse *>*) updateAttributes: (NSArray<AWSCognitoIdentityUserAttributeType *>*) attributes {
-(AWSTask<AWSCognitoIdentityUserUpdateAttributesResponse *>*) updateAttributes: (NSArray<AWSCognitoIdentityUserAttributeType *>*) attributes
clientMetaData: (nullable NSDictionary<NSString *,NSString *> *) clientMetaData {
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;
request.clientMetadata = clientMetaData;
for (AWSCognitoIdentityUserAttributeType * attribute in attributes) {
AWSCognitoIdentityProviderAttributeType *apiAttribute = [AWSCognitoIdentityProviderAttributeType new];
apiAttribute.name = attribute.name;
Expand All @@ -1163,6 +1169,10 @@ -(void) addSecretHashDeviceKeyAndUsername:(NSMutableDictionary<NSString *,NSStri
}];
}

-(AWSTask<AWSCognitoIdentityUserUpdateAttributesResponse *>*) updateAttributes: (NSArray<AWSCognitoIdentityUserAttributeType *>*) attributes {
return [self updateAttributes:attributes clientMetaData:nil];
}

/**
* Delete the attributes specified by attributeNames
*/
Expand Down Expand Up @@ -1199,11 +1209,13 @@ -(void) addSecretHashDeviceKeyAndUsername:(NSMutableDictionary<NSString *,NSStri
/**
* Request a verification code to verify an attribute.
*/
-(AWSTask<AWSCognitoIdentityUserGetAttributeVerificationCodeResponse *>*) getAttributeVerificationCode: (NSString *) attributeName {
-(AWSTask<AWSCognitoIdentityUserGetAttributeVerificationCodeResponse *>*) getAttributeVerificationCode: (NSString *) attributeName
clientMetaData: (nullable NSDictionary<NSString *,NSString *> *) clientMetaData {
AWSCognitoIdentityProviderGetUserAttributeVerificationCodeRequest *request = [AWSCognitoIdentityProviderGetUserAttributeVerificationCodeRequest new];
return [[self getSession] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserSession *> * _Nonnull task) {
request.accessToken = task.result.accessToken.tokenString;
request.attributeName = attributeName;
request.clientMetadata = clientMetaData;
return [[self.pool.client getUserAttributeVerificationCode:request] continueWithSuccessBlock:^id _Nullable(AWSTask<AWSCognitoIdentityProviderGetUserAttributeVerificationCodeResponse *> * _Nonnull task) {
AWSCognitoIdentityUserGetAttributeVerificationCodeResponse * response = [AWSCognitoIdentityUserGetAttributeVerificationCodeResponse new];
[response aws_copyPropertiesFromObject:task.result];
Expand All @@ -1212,6 +1224,10 @@ -(void) addSecretHashDeviceKeyAndUsername:(NSMutableDictionary<NSString *,NSStri
}];
}

-(AWSTask<AWSCognitoIdentityUserGetAttributeVerificationCodeResponse *>*) getAttributeVerificationCode: (NSString *) attributeName {
return [self getAttributeVerificationCode:attributeName clientMetaData:nil];
}

/**
* Set the user settings for this user such as MFA
*/
Expand Down
25 changes: 23 additions & 2 deletions AWSCognitoIdentityProviderTests/AWSCognitoIdentityProviderTests.m
Expand Up @@ -314,7 +314,8 @@ - (void)testUpdateAttribute {
name.name = @"name";
name.value = @"Joe Test";
AWSCognitoIdentityUser * user = [pool getUser:username];
[[user updateAttributes:@[name]] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserUpdateAttributesResponse *> * _Nonnull task) {
NSDictionary *clientMetaData = @{@"client":@"metadata"};
[[user updateAttributes:@[name] clientMetaData:clientMetaData] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserUpdateAttributesResponse *> * _Nonnull task) {
if(task.isCancelled || task.error){
XCTFail(@"Request returned an error %@",task.error);
}
Expand Down Expand Up @@ -374,7 +375,8 @@ - (void)testGetAttributeVerification {
XCTestExpectation *expectation =
[self expectationWithDescription:@"testGetAttributeVerification"];
AWSCognitoIdentityUser * user = [pool getUser:username];
[[user getAttributeVerificationCode:@"phone_number"] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserGetAttributeVerificationCodeResponse *> * _Nonnull task) {
NSDictionary *clientMetaData = @{@"client":@"metadata"};
[[user getAttributeVerificationCode:@"phone_number" clientMetaData:clientMetaData] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserGetAttributeVerificationCodeResponse *> * _Nonnull task) {
if(!task.error || task.error.code != AWSCognitoIdentityProviderErrorInvalidParameter){
XCTFail(@"Request should have failed with InvalidParameterException (Invalid phone number provided..)");
}
Expand All @@ -389,6 +391,25 @@ - (void)testGetAttributeVerification {

}

- (void)testResendConfirmationCode {
XCTestExpectation *expectation =
[self expectationWithDescription:@"testResendConfirmationCode"];
AWSCognitoIdentityUser * user = [pool getUser:username];
NSDictionary *clientMetaData = @{@"client":@"metadata"};
[[user resendConfirmationCode: clientMetaData] continueWithBlock:^id _Nullable(AWSTask<AWSCognitoIdentityUserResendConfirmationCodeResponse *> * _Nonnull task) {
if(!task.error || task.error.code != AWSCognitoIdentityProviderErrorNotAuthorized){
XCTFail(@"Request should have failed with AWSCognitoIdentityProviderErrorNotAuthorized (Cannot resend codes. Auto verification not turned on.)");
}
[expectation fulfill];
return task;
}];
[self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
if (error) {
NSLog(@"Timeout Error: %@", error);
}
}];
}


- (void)testChangePassword {
XCTestExpectation *expectation =
Expand Down

0 comments on commit 60d3bd3

Please sign in to comment.