Skip to content

Commit

Permalink
Merge branch 'main' into edisooon/use-last-syncexpression-in-lookupLa…
Browse files Browse the repository at this point in the history
…stSyncTime
  • Loading branch information
edisooon authored Oct 30, 2024
2 parents 3046a41 + f267334 commit b852be6
Show file tree
Hide file tree
Showing 28 changed files with 1,621 additions and 84 deletions.
2 changes: 2 additions & 0 deletions aws-auth-cognito/api/aws-auth-cognito.api
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ public final class com/amplifyframework/auth/cognito/AWSCognitoAuthPlugin : com/
public fun signOut (Lcom/amplifyframework/auth/options/AuthSignOutOptions;Lcom/amplifyframework/core/Consumer;)V
public fun signOut (Lcom/amplifyframework/core/Consumer;)V
public fun signUp (Ljava/lang/String;Ljava/lang/String;Lcom/amplifyframework/auth/options/AuthSignUpOptions;Lcom/amplifyframework/core/Consumer;Lcom/amplifyframework/core/Consumer;)V
public final fun updateMFAPreference (Lcom/amplifyframework/auth/cognito/MFAPreference;Lcom/amplifyframework/auth/cognito/MFAPreference;Lcom/amplifyframework/auth/cognito/MFAPreference;Lcom/amplifyframework/core/Action;Lcom/amplifyframework/core/Consumer;)V
public final fun updateMFAPreference (Lcom/amplifyframework/auth/cognito/MFAPreference;Lcom/amplifyframework/auth/cognito/MFAPreference;Lcom/amplifyframework/core/Action;Lcom/amplifyframework/core/Consumer;)V
public static synthetic fun updateMFAPreference$default (Lcom/amplifyframework/auth/cognito/AWSCognitoAuthPlugin;Lcom/amplifyframework/auth/cognito/MFAPreference;Lcom/amplifyframework/auth/cognito/MFAPreference;Lcom/amplifyframework/auth/cognito/MFAPreference;Lcom/amplifyframework/core/Action;Lcom/amplifyframework/core/Consumer;ILjava/lang/Object;)V
public fun updatePassword (Ljava/lang/String;Ljava/lang/String;Lcom/amplifyframework/core/Action;Lcom/amplifyframework/core/Consumer;)V
public fun updateUserAttribute (Lcom/amplifyframework/auth/AuthUserAttribute;Lcom/amplifyframework/auth/options/AuthUpdateUserAttributeOptions;Lcom/amplifyframework/core/Consumer;Lcom/amplifyframework/core/Consumer;)V
public fun updateUserAttribute (Lcom/amplifyframework/auth/AuthUserAttribute;Lcom/amplifyframework/core/Consumer;Lcom/amplifyframework/core/Consumer;)V
Expand Down
2 changes: 2 additions & 0 deletions aws-auth-cognito/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ dependencies {
androidTestImplementation(libs.test.androidx.runner)
androidTestImplementation(libs.test.androidx.junit)
androidTestImplementation(libs.test.kotlin.coroutines)
androidTestImplementation(libs.test.kotlin.kotlinTest)
androidTestImplementation(libs.test.totp)

androidTestImplementation(project(":aws-api"))
androidTestImplementation(project(":aws-api-appsync"))
androidTestImplementation(project(":testutils"))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
subscription OnCreateMfaInfo {
onCreateMfaInfo {
username
code
expirationTime
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (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/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package com.amplifyframework.auth.cognito

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.amplifyframework.api.aws.AWSApiPlugin
import com.amplifyframework.api.graphql.SimpleGraphQLRequest
import com.amplifyframework.auth.AuthUserAttribute
import com.amplifyframework.auth.AuthUserAttributeKey
import com.amplifyframework.auth.MFAType
import com.amplifyframework.auth.cognito.exceptions.service.CodeMismatchException
import com.amplifyframework.auth.cognito.test.R
import com.amplifyframework.auth.options.AuthSignUpOptions
import com.amplifyframework.auth.result.AuthSignUpResult
import com.amplifyframework.auth.result.step.AuthSignInStep
import com.amplifyframework.core.configuration.AmplifyOutputs
import com.amplifyframework.core.configuration.AmplifyOutputsData
import com.amplifyframework.datastore.generated.model.MfaInfo
import com.amplifyframework.testutils.Assets
import com.amplifyframework.testutils.sync.SynchronousAuth
import java.util.Random
import java.util.UUID
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import org.junit.After
import org.junit.Before
import org.junit.Test

class AWSCognitoAuthPluginEmailMFATests {

private val password = "${UUID.randomUUID()}BleepBloop1234!"
private val userName = "test${Random().nextInt()}"
private val email = "$userName@amplify-swift-gamma.awsapps.com"

private var authPlugin = AWSCognitoAuthPlugin()
private var apiPlugin = AWSApiPlugin()
private lateinit var synchronousAuth: SynchronousAuth
private var mfaCode = ""
private var latch: CountDownLatch? = null

@Before
fun initializePlugin() {
val context = ApplicationProvider.getApplicationContext<Context>()
val config = AmplifyOutputsData
.deserialize(context, AmplifyOutputs.fromResource(R.raw.amplify_outputs_email_or_totp_mfa))

authPlugin.configure(config, context)
apiPlugin.configure(config, context)
synchronousAuth = SynchronousAuth.delegatingTo(authPlugin)

apiPlugin.subscribe(
SimpleGraphQLRequest<MfaInfo>(
Assets.readAsString("create-mfa-subscription.graphql"),
MfaInfo::class.java,
null
),
{ println("====== Subscription Established ======") },
{
println("====== Received some MFA Info ======")
mfaCode = it.data.code
latch?.countDown()
},
{ println("====== Subscription Failed $it ======") },
{ }
)
}

@After
fun tearDown() {
mfaCode = ""
synchronousAuth.deleteUser()
}

@Test
fun fresh_email_mfa_setup() {
// Step 1: Sign up a new user
signUpNewUser()

// Step 2: Attempt to sign in with the newly created user
var signInResult = synchronousAuth.signIn(userName, password)

// Validation 1: Validate that the next step is MFA Setup Selection
assertEquals(AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SETUP_SELECTION, signInResult.nextStep.signInStep)

// Validation 2: Validate that the available MFA choices are Email and TOTP
assertEquals(setOf(MFAType.EMAIL, MFAType.TOTP), signInResult.nextStep.allowedMFATypes)

// Step 3: Select "Email" as the MFA to set up
signInResult = synchronousAuth.confirmSignIn("EMAIL_OTP")

// Validation 2: Validate that the next step is to input the user's email address
assertEquals(AuthSignInStep.CONTINUE_SIGN_IN_WITH_EMAIL_MFA_SETUP, signInResult.nextStep.signInStep)

// Step 4: Input the email address to send the code to then wait for the MFA code
latch = CountDownLatch(1)
signInResult = synchronousAuth.confirmSignIn(email)

// Validation 3: Validate that the next step is to confirm the emailed MFA code
assertEquals(AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP, signInResult.nextStep.signInStep)

// Wait until the MFA code has been received
latch?.await(20, TimeUnit.SECONDS)

// Step 5: Input the emailed MFA code for confirmation
signInResult = synchronousAuth.confirmSignIn(mfaCode)

// Validation 4: Validate that MFA setup is done
assertEquals(AuthSignInStep.DONE, signInResult.nextStep.signInStep)
}

@Test
fun sign_in_to_existing_email_mfa() {
// Step 1: Sign up a new user with an existing email address
signUpNewUser(email)

// Step 2: Attempt to sign in with the newly created user
latch = CountDownLatch(1)
var signInResult = synchronousAuth.signIn(userName, password)

// Validation 1: Validate that the next step is to confirm the emailed MFA code
assertEquals(AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP, signInResult.nextStep.signInStep)

// Wait until the MFA code has been received
latch?.await(20, TimeUnit.SECONDS)

// Step 4: Input the emailed MFA code for confirmation
signInResult = synchronousAuth.confirmSignIn(mfaCode)

// Validation 2: Validate that MFA setup is done
assertEquals(AuthSignInStep.DONE, signInResult.nextStep.signInStep)
}

@Test
fun use_an_incorrect_MFA_code_then_sign_in_using_the_correct_one() {
// Step 1: Sign up a new user with an existing email address
signUpNewUser(email)

// Step 2: Attempt to sign in with the newly created user
latch = CountDownLatch(1)
var signInResult = synchronousAuth.signIn(userName, password)

// Validation 1: Validate that the next step is to confirm the emailed MFA code
assertEquals(AuthSignInStep.CONFIRM_SIGN_IN_WITH_OTP, signInResult.nextStep.signInStep)

// Wait until the MFA code has been received
latch?.await(20, TimeUnit.SECONDS)

// Step 4: Input the an incorrect MFA code
// Validation 2: Validate that an incorrect MFA code throws a CodeMismatchException
assertFailsWith<CodeMismatchException> {
signInResult = synchronousAuth.confirmSignIn(mfaCode.reversed())
}

// Step 5: Input the correct MFA code for validation
signInResult = synchronousAuth.confirmSignIn(mfaCode)

// Validation 3: Validate that MFA setup is done
assertEquals(AuthSignInStep.DONE, signInResult.nextStep.signInStep)
}

private fun signUpNewUser(email: String? = null): AuthSignUpResult {
val attributes = if (email == null) {
emptyList()
} else {
listOf(AuthUserAttribute(AuthUserAttributeKey.email(), email))
}
val options = AuthSignUpOptions.builder()
.userAttributes(
attributes
).build()
return synchronousAuth.signUp(userName, password, options)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ class AWSCognitoAuthPluginTOTPTests {
)
synchronousAuth.confirmSignIn(otp)
synchronousAuth.updateUserAttribute(AuthUserAttribute(AuthUserAttributeKey.phoneNumber(), "+19876543210"))
updateMFAPreference(MFAPreference.ENABLED, MFAPreference.ENABLED)
updateMFAPreference(MFAPreference.ENABLED, MFAPreference.ENABLED, MFAPreference.ENABLED)
synchronousAuth.signOut()
val signInResult = synchronousAuth.signIn(userName, password)
Assert.assertEquals(AuthSignInStep.CONTINUE_SIGN_IN_WITH_MFA_SELECTION, signInResult.nextStep.signInStep)
Expand All @@ -168,9 +168,9 @@ class AWSCognitoAuthPluginTOTPTests {
synchronousAuth.signUp(userName, password, options)
}

private fun updateMFAPreference(sms: MFAPreference, totp: MFAPreference) {
private fun updateMFAPreference(sms: MFAPreference, totp: MFAPreference, email: MFAPreference) {
val latch = CountDownLatch(1)
authPlugin.updateMFAPreference(sms, totp, { latch.countDown() }, { latch.countDown() })
authPlugin.updateMFAPreference(sms, totp, email, { latch.countDown() }, { latch.countDown() })
latch.await(5, TimeUnit.SECONDS)
}
}
Loading

0 comments on commit b852be6

Please sign in to comment.