Skip to content

Commit

Permalink
feat(authenticator): Upgrade to Gen2 Amplify version (#148)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattcreaser authored May 1, 2024
1 parent da6dd6b commit 4c0393b
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ import com.amplifyframework.ui.authenticator.util.PasswordResetMessage
import com.amplifyframework.ui.authenticator.util.RealAuthProvider
import com.amplifyframework.ui.authenticator.util.UnableToResetPasswordMessage
import com.amplifyframework.ui.authenticator.util.UnknownErrorMessage
import com.amplifyframework.ui.authenticator.util.challengeResponse
import com.amplifyframework.ui.authenticator.util.toFieldError
import java.net.UnknownHostException
import kotlinx.coroutines.channels.BufferOverflow
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.amplifyframework.ui.authenticator.states

import com.amplifyframework.auth.MFAType
import com.amplifyframework.auth.cognito.challengeResponse
import com.amplifyframework.ui.authenticator.SignInContinueWithMfaSelectionState
import com.amplifyframework.ui.authenticator.enums.AuthenticatorInitialStep
import com.amplifyframework.ui.authenticator.enums.AuthenticatorStep
import com.amplifyframework.ui.authenticator.forms.FieldKey
import com.amplifyframework.ui.authenticator.util.challengeResponse

internal class SignInContinueWithMfaSelectionStateImpl(
override val allowedMfaTypes: Set<MFAType>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.amplifyframework.auth.MFAType
import com.amplifyframework.auth.cognito.challengeResponse
import com.amplifyframework.ui.authenticator.R
import com.amplifyframework.ui.authenticator.SignInContinueWithMfaSelectionState
import com.amplifyframework.ui.authenticator.enums.AuthenticatorStep
import com.amplifyframework.ui.authenticator.forms.FieldKey
import com.amplifyframework.ui.authenticator.util.challengeResponse
import kotlinx.coroutines.launch

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import com.amplifyframework.auth.AuthUser
import com.amplifyframework.auth.AuthUserAttribute
import com.amplifyframework.auth.AuthUserAttributeKey
import com.amplifyframework.auth.cognito.AWSCognitoAuthPlugin
import com.amplifyframework.auth.cognito.PasswordProtectionSettings
import com.amplifyframework.auth.cognito.UsernameAttribute
import com.amplifyframework.auth.cognito.VerificationMechanism as AmplifyVerificationMechanism
import com.amplifyframework.auth.options.AuthSignUpOptions
import com.amplifyframework.auth.result.AuthResetPasswordResult
import com.amplifyframework.auth.result.AuthSignInResult
Expand All @@ -44,7 +47,6 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import org.json.JSONException

/**
* An abstraction of the Amplify.Auth API that allows us to use coroutines with no exceptions
Expand Down Expand Up @@ -253,62 +255,31 @@ internal class RealAuthProvider : AuthProvider {
}

override suspend fun getConfiguration(): AuthConfigurationResult {
val authConfigJSON = getCognitoPlugin()?.getPluginConfiguration() ?: return AuthConfigurationResult.Missing
try {
val innerJSON = authConfigJSON
.getJSONObject("Auth")
.getJSONObject("Default")
val signUpAttributes = innerJSON.getJSONArray("signupAttributes")
val usernameAttributes = innerJSON.getJSONArray("usernameAttributes")
val passwordAttributes = innerJSON.getJSONObject("passwordProtectionSettings")

val signInAttributeList = List(usernameAttributes.length()) {
usernameAttributes.getString(it)
}
val containsEmail = signInAttributeList.contains("EMAIL")
val containsPhoneNumber = signInAttributeList.contains("PHONE_NUMBER")
val signInMethod = when {
containsEmail -> SignInMethod.Email
containsPhoneNumber -> SignInMethod.PhoneNumber
else -> SignInMethod.Username
}
val authConfiguration = getCognitoPlugin()?.getAuthConfiguration() ?: return AuthConfigurationResult.Missing

val passwordCriteria = authConfiguration.passwordProtectionSettings?.toPasswordCriteria()
?: return AuthConfigurationResult.Invalid(
"""
Your auth configuration does not define passwordProtectionSettings.
Authenticator needs these settings to perform client-side validation of passwords.
""".trimIndent()
)

val signUpAttributeList = List(signUpAttributes.length()) {
AuthUserAttributeKey.custom(signUpAttributes.getString(it).lowercase())
val verificationMechanisms = authConfiguration.verificationMechanisms.map {
when (it) {
AmplifyVerificationMechanism.Email -> VerificationMechanism.Email
AmplifyVerificationMechanism.PhoneNumber -> VerificationMechanism.PhoneNumber
}
}.toSet()

val passwordRequirementsJSON = passwordAttributes
.getJSONArray("passwordPolicyCharacters")
val passwordRequirements = List(passwordRequirementsJSON.length()) {
passwordRequirementsJSON.getString(it)
}
val passwordCriteria = PasswordCriteria(
length = passwordAttributes.getInt("passwordPolicyMinLength"),
requiresNumber = passwordRequirements.contains("REQUIRES_NUMBERS"),
requiresSpecial = passwordRequirements.contains("REQUIRES_SYMBOLS"),
requiresLower = passwordRequirements.contains("REQUIRES_LOWER"),
requiresUpper = passwordRequirements.contains("REQUIRES_UPPER")
)
val amplifyAuthConfiguration = AmplifyAuthConfiguration(
signInMethod = getSignInMethod(authConfiguration.usernameAttributes),
signUpAttributes = authConfiguration.signUpAttributes,
passwordCriteria = passwordCriteria,
verificationMechanisms = verificationMechanisms
)

val verificationMechanismsJson = innerJSON.getJSONArray("verificationMechanisms")
val verificationMechanisms = List(verificationMechanismsJson.length()) {
when (verificationMechanismsJson.getString(it)) {
"EMAIL" -> VerificationMechanism.Email
else -> VerificationMechanism.PhoneNumber
}
}.toSet()

return AuthConfigurationResult.Valid(
AmplifyAuthConfiguration(
signInMethod,
signUpAttributeList,
passwordCriteria,
verificationMechanisms
)
)
} catch (e: JSONException) {
return AuthConfigurationResult.Invalid(e.message ?: "Auth configuration is not valid", e)
}
return AuthConfigurationResult.Valid(amplifyAuthConfiguration)
}

private fun getCognitoPlugin(): AWSCognitoAuthPlugin? {
Expand All @@ -319,6 +290,20 @@ internal class RealAuthProvider : AuthProvider {
null
}
}

private fun getSignInMethod(attributes: List<UsernameAttribute>) = when {
attributes.contains(UsernameAttribute.Email) -> SignInMethod.Email
attributes.contains(UsernameAttribute.PhoneNumber) -> SignInMethod.PhoneNumber
else -> SignInMethod.Username
}

private fun PasswordProtectionSettings.toPasswordCriteria() = PasswordCriteria(
length = length,
requiresNumber = requiresNumber,
requiresSpecial = requiresSpecial,
requiresUpper = requiresUpper,
requiresLower = requiresLower
)
}

internal sealed interface AmplifyResult<out T : Any> {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.amplifyframework.ui.authenticator.ui

import com.amplifyframework.auth.MFAType
import com.amplifyframework.auth.cognito.challengeResponse
import com.amplifyframework.ui.authenticator.enums.AuthenticatorInitialStep
import com.amplifyframework.ui.authenticator.enums.AuthenticatorStep
import com.amplifyframework.ui.authenticator.states.SignInContinueWithMfaSelectionStateImpl
import com.amplifyframework.ui.authenticator.ui.robots.signInContinueWithMfaSelection
import com.amplifyframework.ui.authenticator.util.challengeResponse
import com.amplifyframework.ui.testing.ComposeTest
import io.mockk.mockk
import io.mockk.verify
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.isSelected
import androidx.compose.ui.test.junit4.ComposeTestRule
import com.amplifyframework.auth.MFAType
import com.amplifyframework.auth.cognito.challengeResponse
import com.amplifyframework.ui.authenticator.ui.TestTags
import com.amplifyframework.ui.authenticator.util.challengeResponse
import com.amplifyframework.ui.testing.ComposeTest

fun ComposeTest.signInContinueWithMfaSelection(func: SignInContinueWithMfaSelectionRobot.() -> Unit) =
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[versions]
agp = "8.1.4"
amplify = "2.15.0"
amplify = "2.16.0"
binary-compatibility = "0.14.0"
cameraX = "1.2.0"
compose = "1.5.4"
Expand Down
2 changes: 2 additions & 0 deletions samples/authenticator/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ android {
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Expand Down Expand Up @@ -53,6 +54,7 @@ dependencies {
// Use this to use published version of Amplify UI
implementation "com.amplifyframework.ui:authenticator:$authenticatorVersion"

coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation "com.google.accompanist:accompanist-permissions:0.28.0"
implementation 'androidx.core:core-ktx:1.9.0'
Expand Down

0 comments on commit 4c0393b

Please sign in to comment.