Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,6 @@ class AWSCognitoAuthPlugin : AuthPlugin<AWSCognitoAuthService>() {
internal lateinit var useCaseFactory: AuthUseCaseFactory

private val pluginScope = CoroutineScope(Job() + Dispatchers.Default)
private val queueFacade: KotlinAuthFacadeInternal by lazy {
KotlinAuthFacadeInternal(realPlugin)
}

private val queueChannel = Channel<Job>(capacity = Channel.UNLIMITED).apply {
pluginScope.launch {
Expand Down Expand Up @@ -301,10 +298,10 @@ class AWSCognitoAuthPlugin : AuthPlugin<AWSCognitoAuthService>() {
options: AuthFetchSessionOptions,
onSuccess: Consumer<AuthSession>,
onError: Consumer<AuthException>
) = enqueue(onSuccess, onError) { queueFacade.fetchAuthSession(options) }
) = enqueue(onSuccess, onError) { useCaseFactory.fetchAuthSession().execute(options) }

override fun fetchAuthSession(onSuccess: Consumer<AuthSession>, onError: Consumer<AuthException>) =
enqueue(onSuccess, onError) { queueFacade.fetchAuthSession() }
enqueue(onSuccess, onError) { useCaseFactory.fetchAuthSession().execute() }

override fun rememberDevice(onSuccess: Action, onError: Consumer<AuthException>) =
enqueue(onSuccess, onError) { useCaseFactory.rememberDevice().execute() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ internal fun AmplifyCredential.isValid(): Boolean = when (this) {
else -> false
}

internal fun AmplifyCredential.getCognitoSession(
exception: AuthException? = null
): AWSAuthSessionBehavior<AWSCognitoUserPoolTokens> {
internal fun AmplifyCredential.getCognitoSession(exception: AuthException? = null): AWSCognitoAuthSession {
fun getCredentialsResult(
awsCredentials: CognitoCredentials,
exception: AuthException?
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,10 @@ import androidx.annotation.WorkerThread
import com.amplifyframework.AmplifyException
import com.amplifyframework.annotations.InternalAmplifyApi
import com.amplifyframework.auth.AWSCognitoAuthMetadataType
import com.amplifyframework.auth.AuthChannelEventName
import com.amplifyframework.auth.AuthException
import com.amplifyframework.auth.AuthSession
import com.amplifyframework.auth.cognito.exceptions.service.InvalidAccountTypeException
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
import com.amplifyframework.auth.options.AuthFetchSessionOptions
import com.amplifyframework.core.Amplify
import com.amplifyframework.core.Consumer
import com.amplifyframework.hub.HubChannel
import com.amplifyframework.hub.HubEvent
import com.amplifyframework.logging.Logger
import com.amplifyframework.statemachine.StateChangeListenerToken
import com.amplifyframework.statemachine.codegen.data.AmplifyCredential
import com.amplifyframework.statemachine.codegen.errors.SessionError
import com.amplifyframework.statemachine.codegen.events.AuthEvent
import com.amplifyframework.statemachine.codegen.events.AuthorizationEvent
import com.amplifyframework.statemachine.codegen.states.AuthState
import com.amplifyframework.statemachine.codegen.states.AuthorizationState
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.flow.collect
Expand Down Expand Up @@ -96,125 +76,6 @@ internal class RealAWSCognitoAuthPlugin(
authStateMachine.state.takeWhile { it !is AuthState.Configured && it !is AuthState.Error }.collect()
}

fun fetchAuthSession(onSuccess: Consumer<AuthSession>, onError: Consumer<AuthException>) {
fetchAuthSession(AuthFetchSessionOptions.defaults(), onSuccess, onError)
}

fun fetchAuthSession(
options: AuthFetchSessionOptions,
onSuccess: Consumer<AuthSession>,
onError: Consumer<AuthException>
) {
val forceRefresh = options.forceRefresh
authStateMachine.getCurrentState { authState ->
when (val authZState = authState.authZState) {
is AuthorizationState.Configured -> {
authStateMachine.send(AuthorizationEvent(AuthorizationEvent.EventType.FetchUnAuthSession))
_fetchAuthSession(onSuccess)
}
is AuthorizationState.SessionEstablished -> {
val credential = authZState.amplifyCredential
if (!credential.isValid() || forceRefresh) {
if (credential is AmplifyCredential.IdentityPoolFederated) {
authStateMachine.send(
AuthorizationEvent(
AuthorizationEvent.EventType.StartFederationToIdentityPool(
credential.federatedToken,
credential.identityId,
credential
)
)
)
} else {
authStateMachine.send(
AuthorizationEvent(AuthorizationEvent.EventType.RefreshSession(credential))
)
}
_fetchAuthSession(onSuccess)
} else {
onSuccess.accept(credential.getCognitoSession())
}
}
is AuthorizationState.Error -> {
val error = authZState.exception
if (error is SessionError) {
val amplifyCredential = error.amplifyCredential
if (amplifyCredential is AmplifyCredential.IdentityPoolFederated) {
authStateMachine.send(
AuthorizationEvent(
AuthorizationEvent.EventType.StartFederationToIdentityPool(
amplifyCredential.federatedToken,
amplifyCredential.identityId,
amplifyCredential
)
)
)
} else {
authStateMachine.send(
AuthorizationEvent(AuthorizationEvent.EventType.RefreshSession(amplifyCredential))
)
}
_fetchAuthSession(onSuccess)
} else {
onError.accept(InvalidStateException())
}
}
else -> onError.accept(InvalidStateException())
}
}
}

private fun _fetchAuthSession(onSuccess: Consumer<AuthSession>) {
val token = StateChangeListenerToken()
authStateMachine.listen(
token,
{ authState ->
when (val authZState = authState.authZState) {
is AuthorizationState.SessionEstablished -> {
authStateMachine.cancel(token)
onSuccess.accept(authZState.amplifyCredential.getCognitoSession())
}
is AuthorizationState.Error -> {
authStateMachine.cancel(token)
when (val error = authZState.exception) {
is SessionError -> {
when (val innerException = error.exception) {
is SignedOutException -> {
onSuccess.accept(error.amplifyCredential.getCognitoSession(innerException))
}
is SessionExpiredException -> {
onSuccess.accept(error.amplifyCredential.getCognitoSession(innerException))
sendHubEvent(AuthChannelEventName.SESSION_EXPIRED.toString())
}
is ServiceException -> {
onSuccess.accept(error.amplifyCredential.getCognitoSession(innerException))
}
is NotAuthorizedException -> {
onSuccess.accept(error.amplifyCredential.getCognitoSession(innerException))
}
else -> {
val errorResult = UnknownException("Fetch auth session failed.", innerException)
onSuccess.accept(error.amplifyCredential.getCognitoSession(errorResult))
}
}
}
is ConfigurationException -> {
val errorResult = InvalidAccountTypeException(error)
onSuccess.accept(AmplifyCredential.Empty.getCognitoSession(errorResult))
}
else -> {
val errorResult = UnknownException("Fetch auth session failed.", error)
onSuccess.accept(AmplifyCredential.Empty.getCognitoSession(errorResult))
}
}
}
else -> Unit
}
},
null
)
}

private fun addAuthStateChangeListener() {
authStateMachine.listen(
StateChangeListenerToken(),
Expand All @@ -240,8 +101,4 @@ internal class RealAWSCognitoAuthPlugin(
}
)
}

private fun sendHubEvent(eventName: String) {
Amplify.Hub.publish(HubChannel.AUTH, HubEvent.create(eventName))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ internal class AuthUseCaseFactory(
private val stateMachine: AuthStateMachine
) {

fun fetchAuthSession() = FetchAuthSessionUseCase(plugin)
fun fetchAuthSession() = FetchAuthSessionUseCase(stateMachine)

fun associateWebAuthnCredential() = AssociateWebAuthnCredentialUseCase(
client = authEnvironment.requireIdentityProviderClient(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,118 @@

package com.amplifyframework.auth.cognito.usecases

import com.amplifyframework.auth.AuthChannelEventName
import com.amplifyframework.auth.cognito.AWSCognitoAuthSession
import com.amplifyframework.auth.cognito.RealAWSCognitoAuthPlugin
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
import com.amplifyframework.auth.cognito.AuthStateMachine
import com.amplifyframework.auth.cognito.CognitoAuthExceptionConverter.Companion.toAuthException
import com.amplifyframework.auth.cognito.exceptions.service.InvalidAccountTypeException
import com.amplifyframework.auth.cognito.getCognitoSession
import com.amplifyframework.auth.cognito.isValid
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.options.AuthFetchSessionOptions
import com.amplifyframework.auth.plugins.core.AuthHubEventEmitter
import com.amplifyframework.statemachine.codegen.data.AmplifyCredential
import com.amplifyframework.statemachine.codegen.errors.SessionError
import com.amplifyframework.statemachine.codegen.events.AuthorizationEvent
import com.amplifyframework.statemachine.codegen.states.AuthorizationState
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onSubscription

internal class FetchAuthSessionUseCase(
private val plugin: RealAWSCognitoAuthPlugin
private val stateMachine: AuthStateMachine,
private val emitter: AuthHubEventEmitter = AuthHubEventEmitter()
) {
suspend fun execute(): AWSCognitoAuthSession {
// TODO - we should migrate the fetch auth session business logic to this class
val session = suspendCoroutine { continuation ->
plugin.fetchAuthSession(
onSuccess = { continuation.resume(it) },
onError = { continuation.resumeWithException(it) }
)
suspend fun execute(options: AuthFetchSessionOptions = AuthFetchSessionOptions.defaults()): AWSCognitoAuthSession {
val forceRefresh = options.forceRefresh
val currentState = stateMachine.getCurrentState()

return when (val authZState = currentState.authZState) {
is AuthorizationState.Configured -> {
waitForSession(AuthorizationEvent(AuthorizationEvent.EventType.FetchUnAuthSession))
}
is AuthorizationState.SessionEstablished -> {
val credential = authZState.amplifyCredential
if (credential.isValid() && !forceRefresh) {
// Return existing credential
credential.getCognitoSession()
} else {
// Refresh session
val event = getRefreshSessionEvent(credential)
waitForSession(event)
}
}
is AuthorizationState.Error -> {
when (val error = authZState.exception) {
is SessionError -> waitForSession(getRefreshSessionEvent(error.amplifyCredential))
else -> throw InvalidStateException()
}
}
else -> throw InvalidStateException()
}
return session as AWSCognitoAuthSession
}

private fun getRefreshSessionEvent(credential: AmplifyCredential): AuthorizationEvent =
if (credential is AmplifyCredential.IdentityPoolFederated) {
AuthorizationEvent(
AuthorizationEvent.EventType.StartFederationToIdentityPool(
credential.federatedToken,
credential.identityId,
credential
)
)
} else {
AuthorizationEvent(AuthorizationEvent.EventType.RefreshSession(credential))
}

private suspend fun waitForSession(event: AuthorizationEvent): AWSCognitoAuthSession = stateMachine.state
.onSubscription { stateMachine.send(event) }
.drop(1)
.mapNotNull { authState ->
when (val authZState = authState.authZState) {
is AuthorizationState.SessionEstablished -> {
authZState.amplifyCredential.getCognitoSession()
}
is AuthorizationState.Error -> {
when (val error = authZState.exception) {
is SessionError -> {
when (val innerException = error.exception) {
is SignedOutException -> {
error.amplifyCredential.getCognitoSession(innerException)
}
is SessionExpiredException -> {
emitter.sendHubEvent(AuthChannelEventName.SESSION_EXPIRED.toString())
error.amplifyCredential.getCognitoSession(innerException)
}
is ServiceException -> {
error.amplifyCredential.getCognitoSession(innerException)
}
is NotAuthorizedException -> {
error.amplifyCredential.getCognitoSession(innerException)
}
else -> {
val errorResult = innerException.toAuthException("Fetch auth session failed.")
error.amplifyCredential.getCognitoSession(errorResult)
}
}
}
is ConfigurationException -> {
val errorResult = InvalidAccountTypeException(error)
AmplifyCredential.Empty.getCognitoSession(errorResult)
}
else -> {
val errorResult = error.toAuthException("Fetch auth session failed.")
AmplifyCredential.Empty.getCognitoSession(errorResult)
}
}
}
else -> null
}
}.first()
}
Loading
Loading