From f142fb7d131b75e07bec7c980a9ce47eec939f1c Mon Sep 17 00:00:00 2001 From: gpanshu <91897496+gpanshu@users.noreply.github.com> Date: Tue, 25 Jul 2023 10:23:56 -0500 Subject: [PATCH 1/2] fix(auth): Fix for sending session expired when an invalid grant exception is received (#2524) --- .../auth/cognito/AuthEnvironment.kt | 5 ++-- .../auth/cognito/RealAWSCognitoAuthPlugin.kt | 10 ++++++- .../actions/FetchAuthSessionCognitoActions.kt | 3 +- .../service/InvalidGrantException.kt | 6 ++-- .../cognito/helpers/HostedUIHttpHelper.kt | 19 +++++++----- .../FetchAuthSessionTestCaseGenerator.kt | 29 +++++++++++++++++-- ...s_successfully_returned_after_refresh.json | 1 - 7 files changed, 55 insertions(+), 18 deletions(-) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AuthEnvironment.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AuthEnvironment.kt index 027e9c8099..7d9edf65a4 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AuthEnvironment.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AuthEnvironment.kt @@ -103,12 +103,13 @@ internal class AuthEnvironment internal constructor( } suspend fun getDeviceMetadata(username: String): DeviceMetadata.Metadata? { - val deviceCredentials = + var deviceCredentials = credentialStoreClient.loadCredentials(CredentialType.Device(username)) as? AmplifyCredential.DeviceData if (deviceCredentials == null) { logger.warn("loadCredentials returned unexpected AmplifyCredential Type.") + deviceCredentials = AmplifyCredential.DeviceData(DeviceMetadata.Empty) } - return (deviceCredentials as AmplifyCredential.DeviceData).deviceMetadata as? DeviceMetadata.Metadata + return deviceCredentials.deviceMetadata as? DeviceMetadata.Metadata } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt index 03ade983a5..2077df0fbf 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt @@ -81,6 +81,8 @@ import com.amplifyframework.auth.cognito.result.RevokeTokenError import com.amplifyframework.auth.cognito.usecases.ResetPasswordUseCase import com.amplifyframework.auth.exceptions.ConfigurationException import com.amplifyframework.auth.exceptions.InvalidStateException +import com.amplifyframework.auth.exceptions.NotAuthorizedException +import com.amplifyframework.auth.exceptions.ServiceException import com.amplifyframework.auth.exceptions.SessionExpiredException import com.amplifyframework.auth.exceptions.SignedOutException import com.amplifyframework.auth.exceptions.UnknownException @@ -1053,9 +1055,15 @@ internal class RealAWSCognitoAuthPlugin( onSuccess.accept(AmplifyCredential.Empty.getCognitoSession(error.exception)) sendHubEvent(AuthChannelEventName.SESSION_EXPIRED.toString()) } + is ServiceException -> { + onSuccess.accept(AmplifyCredential.Empty.getCognitoSession(error.exception)) + } + is NotAuthorizedException -> { + onSuccess.accept(AmplifyCredential.Empty.getCognitoSession(error.exception)) + } else -> { val errorResult = UnknownException("Fetch auth session failed.", error) - onSuccess.accept(error.amplifyCredential.getCognitoSession(errorResult)) + onSuccess.accept(AmplifyCredential.Empty.getCognitoSession(errorResult)) } } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt index 15aa86de6c..75d2eb8a12 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt @@ -33,6 +33,7 @@ import com.amplifyframework.statemachine.codegen.actions.FetchAuthSessionActions import com.amplifyframework.statemachine.codegen.data.AWSCredentials import com.amplifyframework.statemachine.codegen.data.AmplifyCredential import com.amplifyframework.statemachine.codegen.data.CognitoUserPoolTokens +import com.amplifyframework.statemachine.codegen.data.DeviceMetadata import com.amplifyframework.statemachine.codegen.data.LoginsMapProvider import com.amplifyframework.statemachine.codegen.data.SignedInData import com.amplifyframework.statemachine.codegen.events.AuthorizationEvent @@ -62,7 +63,7 @@ internal object FetchAuthSessionCognitoActions : FetchAuthSessionActions { secretHash?.let { authParameters[KEY_SECRET_HASH] = it } val encodedContextData = getUserContextData(username) - val deviceMetadata = getDeviceMetadata(username) + val deviceMetadata: DeviceMetadata.Metadata? = getDeviceMetadata(username) deviceMetadata?.let { authParameters[KEY_DEVICE_KEY] = it.deviceKey } val pinpointEndpointId = getPinpointEndpointId() diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/exceptions/service/InvalidGrantException.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/exceptions/service/InvalidGrantException.kt index eb10ba169a..38a7330757 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/exceptions/service/InvalidGrantException.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/exceptions/service/InvalidGrantException.kt @@ -14,11 +14,11 @@ */ package com.amplifyframework.auth.cognito.exceptions.service -import com.amplifyframework.auth.exceptions.ServiceException +import com.amplifyframework.auth.AuthException /** * Could not perform the action because the token was unable to be parsed * @param message Explains the reason for the exception */ -open class InvalidGrantException(message: String) : - ServiceException(message, TODO_RECOVERY_SUGGESTION) +open class InvalidGrantException(message: String, description: String?) : + AuthException(message, description ?: TODO_RECOVERY_SUGGESTION) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/HostedUIHttpHelper.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/HostedUIHttpHelper.kt index e6a6309895..7b23b75707 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/HostedUIHttpHelper.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/HostedUIHttpHelper.kt @@ -20,6 +20,7 @@ import com.amplifyframework.AmplifyException import com.amplifyframework.auth.cognito.exceptions.service.InvalidGrantException import com.amplifyframework.auth.cognito.exceptions.service.ParseTokenException import com.amplifyframework.auth.exceptions.ServiceException +import com.amplifyframework.auth.exceptions.SessionExpiredException import com.amplifyframework.statemachine.codegen.data.CognitoUserPoolTokens import java.io.BufferedReader import java.io.DataOutputStream @@ -66,6 +67,7 @@ internal object HostedUIHttpHelper { connection.errorStream } val responseString = responseStream.bufferedReader().use(BufferedReader::readText) + return parseTokenResponse(responseString) } else { throw ServiceException( @@ -86,7 +88,7 @@ internal object HostedUIHttpHelper { response.error?.let { if (it == "invalid_grant") { - throw InvalidGrantException(it) + throw SessionExpiredException(it, cause = InvalidGrantException(it, response.errorDescription)) } else { throw ServiceException(it, AmplifyException.TODO_RECOVERY_SUGGESTION) } @@ -99,11 +101,13 @@ internal object HostedUIHttpHelper { expiration = response.expiration ) } catch (e: Exception) { - throw ServiceException( - message = e.message ?: "An unknown service error has occurred", - recoverySuggestion = AmplifyException.TODO_RECOVERY_SUGGESTION, - cause = e - ) + if (e !is SessionExpiredException && e !is ServiceException) { + throw ServiceException( + message = e.message ?: "An unknown service error has occurred", + recoverySuggestion = AmplifyException.TODO_RECOVERY_SUGGESTION, + cause = e + ) + } else throw e } } } @@ -114,7 +118,8 @@ internal class FetchTokenResponse( @SerialName("id_token") val idToken: String? = null, @SerialName("refresh_token") val refreshToken: String? = null, @SerialName("expires_in") private val expiresIn: Int? = null, - @SerialName("error") val error: String? = null + @SerialName("error") val error: String? = null, + @SerialName("error_description") val errorDescription: String? = null ) { val expiration = expiresIn?.let { Instant.now().plus(it.seconds).epochSeconds } } diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt index 387bc06560..14b0ab3d9e 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/testcasegenerators/FetchAuthSessionTestCaseGenerator.kt @@ -50,6 +50,27 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { ).toJsonElement() ) + private val mockedIdentityIdResponse = MockResponse( + CognitoType.CognitoIdentity, + "getId", + ResponseType.Success, + mapOf("identityId" to "someIdentityId").toJsonElement() + ) + + private val mockedAWSCredentialsResponse = MockResponse( + CognitoType.CognitoIdentity, + "getCredentialsForIdentity", + ResponseType.Success, + mapOf( + "credentials" to mapOf( + "accessKeyId" to "someAccessKey", + "secretKey" to "someSecretKey", + "sessionToken" to AuthStateJsonGenerator.dummyToken, + "expiration" to 2342134 + ) + ).toJsonElement() + ) + private val expectedSuccess = AWSCognitoAuthSession( isSignedIn = true, identityIdResult = AuthSessionResult.success("someIdentityId"), @@ -94,15 +115,17 @@ object FetchAuthSessionTestCaseGenerator : SerializableProvider { private val refreshSuccessCase: FeatureTestCase = baseCase.copy( description = "AuthSession object is successfully returned after refresh", - preConditions = baseCase.preConditions.copy( + preConditions = PreConditions( + "authconfiguration.json", + "SignedIn_SessionEstablished.json", mockedResponses = listOf(mockedInitiateAuthResponse) ), api = API( name = AuthAPI.fetchAuthSession, params = JsonObject(emptyMap()), - options = mapOf("forceRefresh" to true).toJsonElement(), + JsonObject(emptyMap()) ), - validations = baseCase.validations + validations = listOf(apiReturnValidation) ) private val identityPoolCase: FeatureTestCase = baseCase.copy( diff --git a/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchAuthSession/AuthSession_object_is_successfully_returned_after_refresh.json b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchAuthSession/AuthSession_object_is_successfully_returned_after_refresh.json index 35efc15978..111b384960 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchAuthSession/AuthSession_object_is_successfully_returned_after_refresh.json +++ b/aws-auth-cognito/src/test/resources/feature-test/testsuites/fetchAuthSession/AuthSession_object_is_successfully_returned_after_refresh.json @@ -24,7 +24,6 @@ "params": { }, "options": { - "forceRefresh": true } }, "validations": [ From ce2bf64ea881bbcc3206d4c5657521452cac41f0 Mon Sep 17 00:00:00 2001 From: gpanshu <91897496+gpanshu@users.noreply.github.com> Date: Tue, 25 Jul 2023 12:06:34 -0500 Subject: [PATCH 2/2] chore(auth): Remove dead code that is no longer being used (#2529) --- .../auth/cognito/actions/SignInChallengeCognitoActions.kt | 8 -------- .../codegen/actions/SignInChallengeActions.kt | 4 ---- 2 files changed, 12 deletions(-) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt index 29598544fd..7935491647 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInChallengeCognitoActions.kt @@ -86,14 +86,6 @@ internal object SignInChallengeCognitoActions : SignInChallengeActions { dispatcher.send(evt) } - override fun resetToWaitingForAnswer( - event: SignInChallengeEvent.EventType.ThrowError, - challenge: AuthChallenge - ): Action = Action("ResetToWaitingForAnswer") { id, dispatcher -> - logger.verbose("$id Starting execution") - dispatcher.send(SignInChallengeEvent(SignInChallengeEvent.EventType.WaitForAnswer(challenge))) - } - private fun getChallengeResponseKey(challengeName: String): String? { return when (ChallengeNameType.fromValue(challengeName)) { is ChallengeNameType.SmsMfa -> "SMS_MFA_CODE" diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/actions/SignInChallengeActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/actions/SignInChallengeActions.kt index e9af419d36..dc98ca35f0 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/actions/SignInChallengeActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/actions/SignInChallengeActions.kt @@ -24,8 +24,4 @@ internal interface SignInChallengeActions { event: SignInChallengeEvent.EventType.VerifyChallengeAnswer, challenge: AuthChallenge ): Action - fun resetToWaitingForAnswer( - event: SignInChallengeEvent.EventType.ThrowError, - challenge: AuthChallenge - ): Action }