Skip to content

Commit b73b9d5

Browse files
authored
fix: adds ConfirmSignInOptions for confirmSignIn API method (#1297)
1 parent f6b9570 commit b73b9d5

File tree

12 files changed

+355
-10
lines changed

12 files changed

+355
-10
lines changed

aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthPlugin.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@
3333
import com.amplifyframework.auth.AuthUser;
3434
import com.amplifyframework.auth.AuthUserAttribute;
3535
import com.amplifyframework.auth.AuthUserAttributeKey;
36+
import com.amplifyframework.auth.cognito.options.AWSCognitoAuthConfirmSignInOptions;
3637
import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignInOptions;
3738
import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignOutOptions;
3839
import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignUpOptions;
3940
import com.amplifyframework.auth.cognito.options.AWSCognitoAuthWebUISignInOptions;
4041
import com.amplifyframework.auth.cognito.util.AuthProviderConverter;
4142
import com.amplifyframework.auth.cognito.util.CognitoAuthExceptionConverter;
4243
import com.amplifyframework.auth.cognito.util.SignInStateConverter;
44+
import com.amplifyframework.auth.options.AuthConfirmSignInOptions;
4345
import com.amplifyframework.auth.options.AuthSignInOptions;
4446
import com.amplifyframework.auth.options.AuthSignOutOptions;
4547
import com.amplifyframework.auth.options.AuthSignUpOptions;
@@ -389,10 +391,16 @@ public void signIn(
389391
@Override
390392
public void confirmSignIn(
391393
@NonNull String confirmationCode,
394+
@NonNull AuthConfirmSignInOptions options,
392395
@NonNull Consumer<AuthSignInResult> onSuccess,
393396
@NonNull Consumer<AuthException> onException
394397
) {
395-
awsMobileClient.confirmSignIn(confirmationCode, new Callback<SignInResult>() {
398+
final Map<String, String> metadata = new HashMap<>();
399+
if (options instanceof AWSCognitoAuthConfirmSignInOptions) {
400+
metadata.putAll(((AWSCognitoAuthConfirmSignInOptions) options).getMetadata());
401+
}
402+
403+
awsMobileClient.confirmSignIn(confirmationCode, metadata, new Callback<SignInResult>() {
396404
@Override
397405
public void onResult(SignInResult result) {
398406
try {
@@ -413,6 +421,15 @@ public void onError(Exception error) {
413421
});
414422
}
415423

424+
@Override
425+
public void confirmSignIn(
426+
@NonNull String confirmationCode,
427+
@NonNull Consumer<AuthSignInResult> onSuccess,
428+
@NonNull Consumer<AuthException> onException
429+
) {
430+
confirmSignIn(confirmationCode, AuthConfirmSignInOptions.defaults(), onSuccess, onException);
431+
}
432+
416433
@Override
417434
public void signInWithSocialWebUI(
418435
@NonNull AuthProvider provider,
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package com.amplifyframework.auth.cognito.options;
17+
18+
import androidx.annotation.NonNull;
19+
import androidx.core.util.ObjectsCompat;
20+
21+
import com.amplifyframework.auth.options.AuthConfirmSignInOptions;
22+
import com.amplifyframework.util.Immutable;
23+
24+
import java.util.HashMap;
25+
import java.util.Map;
26+
import java.util.Objects;
27+
28+
/**
29+
* Cognito extension of confirm sign in options to add the platform specific fields.
30+
*/
31+
public final class AWSCognitoAuthConfirmSignInOptions extends AuthConfirmSignInOptions {
32+
private final Map<String, String> metadata;
33+
34+
/**
35+
* Advanced options for confirming sign in.
36+
* @param metadata Additional custom attributes to be sent to the service such as information about the client
37+
*/
38+
protected AWSCognitoAuthConfirmSignInOptions(
39+
Map<String, String> metadata
40+
) {
41+
this.metadata = metadata;
42+
}
43+
44+
/**
45+
* Get custom attributes to be sent to the service such as information about the client.
46+
* @return custom attributes to be sent to the service such as information about the client
47+
*/
48+
@NonNull
49+
public Map<String, String> getMetadata() {
50+
return metadata;
51+
}
52+
53+
/**
54+
* Get a builder object.
55+
* @return a builder object.
56+
*/
57+
@NonNull
58+
public static CognitoBuilder builder() {
59+
return new CognitoBuilder();
60+
}
61+
62+
@Override
63+
public int hashCode() {
64+
return ObjectsCompat.hash(
65+
getMetadata()
66+
);
67+
}
68+
69+
@Override
70+
public boolean equals(Object obj) {
71+
if (this == obj) {
72+
return true;
73+
} else if (obj == null || getClass() != obj.getClass()) {
74+
return false;
75+
} else {
76+
AWSCognitoAuthConfirmSignInOptions authConfirmSignInOptions = (AWSCognitoAuthConfirmSignInOptions) obj;
77+
return ObjectsCompat.equals(getMetadata(), authConfirmSignInOptions.getMetadata());
78+
}
79+
}
80+
81+
@Override
82+
public String toString() {
83+
return "AWSCognitoAuthConfirmSignInOptions{" +
84+
"metadata=" + metadata +
85+
'}';
86+
}
87+
88+
/**
89+
* The builder for this class.
90+
*/
91+
public static final class CognitoBuilder extends Builder<CognitoBuilder> {
92+
private Map<String, String> metadata;
93+
94+
/**
95+
* Constructor for the builder.
96+
*/
97+
public CognitoBuilder() {
98+
super();
99+
this.metadata = new HashMap<>();
100+
}
101+
102+
/**
103+
* Returns the type of builder this is to support proper flow with it being an extended class.
104+
* @return the type of builder this is to support proper flow with it being an extended class.
105+
*/
106+
@Override
107+
public CognitoBuilder getThis() {
108+
return this;
109+
}
110+
111+
/**
112+
* Set the metadata field for the object being built.
113+
* @param metadata Custom user metadata to be sent with the sign in request.
114+
* @return The builder object to continue building.
115+
*/
116+
@NonNull
117+
public CognitoBuilder metadata(@NonNull Map<String, String> metadata) {
118+
Objects.requireNonNull(metadata);
119+
this.metadata.clear();
120+
this.metadata.putAll(metadata);
121+
return getThis();
122+
}
123+
124+
/**
125+
* Construct and return the object with the values set in the builder.
126+
* @return a new instance of AWSCognitoAuthConfirmSignInOptions with the values specified in the builder.
127+
*/
128+
@NonNull
129+
public AWSCognitoAuthConfirmSignInOptions build() {
130+
return new AWSCognitoAuthConfirmSignInOptions(
131+
Immutable.of(metadata));
132+
}
133+
}
134+
}

aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/AuthComponentTest.java

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.amplifyframework.auth.AuthUser;
3030
import com.amplifyframework.auth.AuthUserAttribute;
3131
import com.amplifyframework.auth.AuthUserAttributeKey;
32+
import com.amplifyframework.auth.cognito.options.AWSCognitoAuthConfirmSignInOptions;
3233
import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignInOptions;
3334
import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignOutOptions;
3435
import com.amplifyframework.auth.cognito.options.AWSCognitoAuthSignUpOptions;
@@ -353,14 +354,55 @@ public void confirmSignIn() throws AuthException {
353354
}).when(mobileClient).getTokens(any());
354355

355356
doAnswer(invocation -> {
356-
Callback<SignInResult> callback = invocation.getArgument(1);
357+
Callback<SignInResult> callback = invocation.getArgument(2);
357358
callback.onResult(amcResult);
358359
return null;
359-
}).when(mobileClient).confirmSignIn(any(String.class), (Callback<SignInResult>) any());
360+
}).when(mobileClient).confirmSignIn(any(String.class), any(), (Callback<SignInResult>) any());
360361

361362
AuthSignInResult result = synchronousAuth.confirmSignIn(CONFIRMATION_CODE);
362363
validateSignInResult(result, true, AuthSignInStep.DONE);
363-
verify(mobileClient).confirmSignIn(eq(CONFIRMATION_CODE), (Callback<SignInResult>) any());
364+
verify(mobileClient).confirmSignIn(eq(CONFIRMATION_CODE), any(), (Callback<SignInResult>) any());
365+
}
366+
367+
/**
368+
* Tests that the confirmSignIn method of the Auth wrapper of AWSMobileClient (AMC) calls AMC.confirmSignIn with
369+
* the confirmation code and options it received and the success callback receives a valid AuthSignInResult.
370+
* @throws AuthException test fails if this gets thrown since method should succeed
371+
*/
372+
@Test
373+
@SuppressWarnings("unchecked") // Casts final parameter to Callback to differentiate methods
374+
public void confirmSignInWithOptions() throws AuthException {
375+
SignInResult amcResult = new SignInResult(
376+
SignInState.DONE,
377+
new UserCodeDeliveryDetails(
378+
DESTINATION,
379+
DELIVERY_MEDIUM,
380+
ATTRIBUTE_NAME
381+
)
382+
);
383+
384+
Tokens tokensResult = new Tokens(ACCESS_TOKEN, ID_TOKEN, REFRESH_TOKEN);
385+
AWSCognitoAuthConfirmSignInOptions.CognitoBuilder options = AWSCognitoAuthConfirmSignInOptions.builder();
386+
Map<String, String> metadata = new HashMap<String, String>();
387+
metadata.put("key", "value");
388+
options.metadata(metadata);
389+
AWSCognitoAuthConfirmSignInOptions builtOptions = options.build();
390+
391+
doAnswer(invocation -> {
392+
Callback<Tokens> callback = invocation.getArgument(0);
393+
callback.onResult(tokensResult);
394+
return null;
395+
}).when(mobileClient).getTokens(any());
396+
397+
doAnswer(invocation -> {
398+
Callback<SignInResult> callback = invocation.getArgument(2);
399+
callback.onResult(amcResult);
400+
return null;
401+
}).when(mobileClient).confirmSignIn(any(String.class), any(), (Callback<SignInResult>) any());
402+
403+
AuthSignInResult result = synchronousAuth.confirmSignIn(CONFIRMATION_CODE, builtOptions);
404+
validateSignInResult(result, true, AuthSignInStep.DONE);
405+
verify(mobileClient).confirmSignIn(eq(CONFIRMATION_CODE), eq(metadata), (Callback<SignInResult>) any());
364406
}
365407

366408
/**

core-kotlin/src/main/java/com/amplifyframework/kotlin/auth/Auth.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.amplifyframework.auth.AuthSession
2525
import com.amplifyframework.auth.AuthUser
2626
import com.amplifyframework.auth.AuthUserAttribute
2727
import com.amplifyframework.auth.AuthUserAttributeKey
28+
import com.amplifyframework.auth.options.AuthConfirmSignInOptions
2829
import com.amplifyframework.auth.options.AuthSignInOptions
2930
import com.amplifyframework.auth.options.AuthSignOutOptions
3031
import com.amplifyframework.auth.options.AuthSignUpOptions
@@ -108,10 +109,16 @@ interface Auth {
108109
/**
109110
* Submit the confirmation code received as part of multi-factor Authentication during sign in.
110111
* @param confirmationCode The code received as part of the multi-factor authentication process
112+
* @param options Advanced options such as a map of auth information for custom auth,
113+
* If not provided, default options will be used
111114
* @return A sign-in result; check the nextStep field for cues on additional sign-in challenges
112115
*/
113116
@Throws(AuthException::class)
114-
suspend fun confirmSignIn(confirmationCode: String): AuthSignInResult
117+
suspend fun confirmSignIn(
118+
confirmationCode: String,
119+
options: AuthConfirmSignInOptions = AuthConfirmSignInOptions.defaults()
120+
):
121+
AuthSignInResult
115122

116123
/**
117124
* Launch the specified auth provider's web UI sign in experience. You should also put the

core-kotlin/src/main/java/com/amplifyframework/kotlin/auth/KotlinAuthFacade.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.amplifyframework.auth.AuthSession
2525
import com.amplifyframework.auth.AuthUser
2626
import com.amplifyframework.auth.AuthUserAttribute
2727
import com.amplifyframework.auth.AuthUserAttributeKey
28+
import com.amplifyframework.auth.options.AuthConfirmSignInOptions
2829
import com.amplifyframework.auth.options.AuthSignInOptions
2930
import com.amplifyframework.auth.options.AuthSignOutOptions
3031
import com.amplifyframework.auth.options.AuthSignUpOptions
@@ -95,10 +96,14 @@ class KotlinAuthFacade(private val delegate: Delegate = Amplify.Auth) : Auth {
9596
}
9697
}
9798

98-
override suspend fun confirmSignIn(confirmationCode: String): AuthSignInResult {
99+
override suspend fun confirmSignIn(
100+
confirmationCode: String,
101+
options: AuthConfirmSignInOptions
102+
): AuthSignInResult {
99103
return suspendCoroutine { continuation ->
100104
delegate.confirmSignIn(
101105
confirmationCode,
106+
options,
102107
{ continuation.resume(it) },
103108
{ continuation.resumeWithException(it) }
104109
)

core-kotlin/src/test/java/com/amplifyframework/kotlin/auth/KotlinAuthFacadeTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ class KotlinAuthFacadeTest {
208208
val code = "CoolCode511"
209209
val signInResult = mockk<AuthSignInResult>()
210210
every {
211-
delegate.confirmSignIn(eq(code), any(), any())
211+
delegate.confirmSignIn(eq(code), any(), any(), any())
212212
} answers {
213-
val indexOfResultConsumer = 1
213+
val indexOfResultConsumer = 2
214214
val onResult = it.invocation.args[indexOfResultConsumer] as Consumer<AuthSignInResult>
215215
onResult.accept(signInResult)
216216
}
@@ -226,9 +226,9 @@ class KotlinAuthFacadeTest {
226226
val code = "IncorrectCodePerhaps"
227227
val error = AuthException("uh", "oh")
228228
every {
229-
delegate.confirmSignIn(eq(code), any(), any())
229+
delegate.confirmSignIn(eq(code), any(), any(), any())
230230
} answers {
231-
val indexOfErrorConsumer = 2
231+
val indexOfErrorConsumer = 3
232232
val onError = it.invocation.args[indexOfErrorConsumer] as Consumer<AuthException>
233233
onError.accept(error)
234234
}

core/src/main/java/com/amplifyframework/auth/AuthCategory.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import androidx.annotation.NonNull;
2121
import androidx.annotation.Nullable;
2222

23+
import com.amplifyframework.auth.options.AuthConfirmSignInOptions;
2324
import com.amplifyframework.auth.options.AuthSignInOptions;
2425
import com.amplifyframework.auth.options.AuthSignOutOptions;
2526
import com.amplifyframework.auth.options.AuthSignUpOptions;
@@ -100,6 +101,16 @@ public void signIn(
100101
getSelectedPlugin().signIn(username, password, onSuccess, onError);
101102
}
102103

104+
@Override
105+
public void confirmSignIn(
106+
@NonNull String confirmationCode,
107+
@NonNull AuthConfirmSignInOptions options,
108+
@NonNull Consumer<AuthSignInResult> onSuccess,
109+
@NonNull Consumer<AuthException> onError
110+
) {
111+
getSelectedPlugin().confirmSignIn(confirmationCode, options, onSuccess, onError);
112+
}
113+
103114
@Override
104115
public void confirmSignIn(
105116
@NonNull String confirmationCode,

core/src/main/java/com/amplifyframework/auth/AuthCategoryBehavior.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import androidx.annotation.NonNull;
2121
import androidx.annotation.Nullable;
2222

23+
import com.amplifyframework.auth.options.AuthConfirmSignInOptions;
2324
import com.amplifyframework.auth.options.AuthSignInOptions;
2425
import com.amplifyframework.auth.options.AuthSignOutOptions;
2526
import com.amplifyframework.auth.options.AuthSignUpOptions;
@@ -111,6 +112,19 @@ void signIn(
111112
@NonNull Consumer<AuthSignInResult> onSuccess,
112113
@NonNull Consumer<AuthException> onError);
113114

115+
/**
116+
* Submit the confirmation code received as part of multi-factor Authentication during sign in.
117+
* @param confirmationCode The code received as part of the multi-factor authentication process
118+
* @param options Advanced options such as a map of auth information for custom auth
119+
* @param onSuccess Success callback
120+
* @param onError Error callback
121+
*/
122+
void confirmSignIn(
123+
@NonNull String confirmationCode,
124+
@NonNull AuthConfirmSignInOptions options,
125+
@NonNull Consumer<AuthSignInResult> onSuccess,
126+
@NonNull Consumer<AuthException> onError);
127+
114128
/**
115129
* Submit the confirmation code received as part of multi-factor Authentication during sign in.
116130
* @param confirmationCode The code received as part of the multi-factor authentication process

0 commit comments

Comments
 (0)