Skip to content

Commit ad91d8a

Browse files
authored
chore(auth): Move FetchAuthSession to usecase (#3246)
1 parent bc201d8 commit ad91d8a

16 files changed

Lines changed: 557 additions & 404 deletions

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,6 @@ class AWSCognitoAuthPlugin : AuthPlugin<AWSCognitoAuthService>() {
9292
internal lateinit var useCaseFactory: AuthUseCaseFactory
9393

9494
private val pluginScope = CoroutineScope(Job() + Dispatchers.Default)
95-
private val queueFacade: KotlinAuthFacadeInternal by lazy {
96-
KotlinAuthFacadeInternal(realPlugin)
97-
}
9895

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

306303
override fun fetchAuthSession(onSuccess: Consumer<AuthSession>, onError: Consumer<AuthException>) =
307-
enqueue(onSuccess, onError) { queueFacade.fetchAuthSession() }
304+
enqueue(onSuccess, onError) { useCaseFactory.fetchAuthSession().execute() }
308305

309306
override fun rememberDevice(onSuccess: Action, onError: Consumer<AuthException>) =
310307
enqueue(onSuccess, onError) { useCaseFactory.rememberDevice().execute() }

aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthSession.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ internal fun AmplifyCredential.isValid(): Boolean = when (this) {
6666
else -> false
6767
}
6868

69-
internal fun AmplifyCredential.getCognitoSession(
70-
exception: AuthException? = null
71-
): AWSAuthSessionBehavior<AWSCognitoUserPoolTokens> {
69+
internal fun AmplifyCredential.getCognitoSession(exception: AuthException? = null): AWSCognitoAuthSession {
7270
fun getCredentialsResult(
7371
awsCredentials: CognitoCredentials,
7472
exception: AuthException?

aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/KotlinAuthFacadeInternal.kt

Lines changed: 0 additions & 40 deletions
This file was deleted.

aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/RealAWSCognitoAuthPlugin.kt

Lines changed: 0 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,10 @@ import androidx.annotation.WorkerThread
1919
import com.amplifyframework.AmplifyException
2020
import com.amplifyframework.annotations.InternalAmplifyApi
2121
import com.amplifyframework.auth.AWSCognitoAuthMetadataType
22-
import com.amplifyframework.auth.AuthChannelEventName
23-
import com.amplifyframework.auth.AuthException
24-
import com.amplifyframework.auth.AuthSession
25-
import com.amplifyframework.auth.cognito.exceptions.service.InvalidAccountTypeException
26-
import com.amplifyframework.auth.exceptions.ConfigurationException
27-
import com.amplifyframework.auth.exceptions.InvalidStateException
28-
import com.amplifyframework.auth.exceptions.NotAuthorizedException
29-
import com.amplifyframework.auth.exceptions.ServiceException
30-
import com.amplifyframework.auth.exceptions.SessionExpiredException
31-
import com.amplifyframework.auth.exceptions.SignedOutException
32-
import com.amplifyframework.auth.exceptions.UnknownException
33-
import com.amplifyframework.auth.options.AuthFetchSessionOptions
34-
import com.amplifyframework.core.Amplify
35-
import com.amplifyframework.core.Consumer
36-
import com.amplifyframework.hub.HubChannel
37-
import com.amplifyframework.hub.HubEvent
3822
import com.amplifyframework.logging.Logger
3923
import com.amplifyframework.statemachine.StateChangeListenerToken
40-
import com.amplifyframework.statemachine.codegen.data.AmplifyCredential
41-
import com.amplifyframework.statemachine.codegen.errors.SessionError
4224
import com.amplifyframework.statemachine.codegen.events.AuthEvent
43-
import com.amplifyframework.statemachine.codegen.events.AuthorizationEvent
4425
import com.amplifyframework.statemachine.codegen.states.AuthState
45-
import com.amplifyframework.statemachine.codegen.states.AuthorizationState
4626
import java.util.concurrent.CountDownLatch
4727
import java.util.concurrent.TimeUnit
4828
import kotlinx.coroutines.flow.collect
@@ -96,125 +76,6 @@ internal class RealAWSCognitoAuthPlugin(
9676
authStateMachine.state.takeWhile { it !is AuthState.Configured && it !is AuthState.Error }.collect()
9777
}
9878

99-
fun fetchAuthSession(onSuccess: Consumer<AuthSession>, onError: Consumer<AuthException>) {
100-
fetchAuthSession(AuthFetchSessionOptions.defaults(), onSuccess, onError)
101-
}
102-
103-
fun fetchAuthSession(
104-
options: AuthFetchSessionOptions,
105-
onSuccess: Consumer<AuthSession>,
106-
onError: Consumer<AuthException>
107-
) {
108-
val forceRefresh = options.forceRefresh
109-
authStateMachine.getCurrentState { authState ->
110-
when (val authZState = authState.authZState) {
111-
is AuthorizationState.Configured -> {
112-
authStateMachine.send(AuthorizationEvent(AuthorizationEvent.EventType.FetchUnAuthSession))
113-
_fetchAuthSession(onSuccess)
114-
}
115-
is AuthorizationState.SessionEstablished -> {
116-
val credential = authZState.amplifyCredential
117-
if (!credential.isValid() || forceRefresh) {
118-
if (credential is AmplifyCredential.IdentityPoolFederated) {
119-
authStateMachine.send(
120-
AuthorizationEvent(
121-
AuthorizationEvent.EventType.StartFederationToIdentityPool(
122-
credential.federatedToken,
123-
credential.identityId,
124-
credential
125-
)
126-
)
127-
)
128-
} else {
129-
authStateMachine.send(
130-
AuthorizationEvent(AuthorizationEvent.EventType.RefreshSession(credential))
131-
)
132-
}
133-
_fetchAuthSession(onSuccess)
134-
} else {
135-
onSuccess.accept(credential.getCognitoSession())
136-
}
137-
}
138-
is AuthorizationState.Error -> {
139-
val error = authZState.exception
140-
if (error is SessionError) {
141-
val amplifyCredential = error.amplifyCredential
142-
if (amplifyCredential is AmplifyCredential.IdentityPoolFederated) {
143-
authStateMachine.send(
144-
AuthorizationEvent(
145-
AuthorizationEvent.EventType.StartFederationToIdentityPool(
146-
amplifyCredential.federatedToken,
147-
amplifyCredential.identityId,
148-
amplifyCredential
149-
)
150-
)
151-
)
152-
} else {
153-
authStateMachine.send(
154-
AuthorizationEvent(AuthorizationEvent.EventType.RefreshSession(amplifyCredential))
155-
)
156-
}
157-
_fetchAuthSession(onSuccess)
158-
} else {
159-
onError.accept(InvalidStateException())
160-
}
161-
}
162-
else -> onError.accept(InvalidStateException())
163-
}
164-
}
165-
}
166-
167-
private fun _fetchAuthSession(onSuccess: Consumer<AuthSession>) {
168-
val token = StateChangeListenerToken()
169-
authStateMachine.listen(
170-
token,
171-
{ authState ->
172-
when (val authZState = authState.authZState) {
173-
is AuthorizationState.SessionEstablished -> {
174-
authStateMachine.cancel(token)
175-
onSuccess.accept(authZState.amplifyCredential.getCognitoSession())
176-
}
177-
is AuthorizationState.Error -> {
178-
authStateMachine.cancel(token)
179-
when (val error = authZState.exception) {
180-
is SessionError -> {
181-
when (val innerException = error.exception) {
182-
is SignedOutException -> {
183-
onSuccess.accept(error.amplifyCredential.getCognitoSession(innerException))
184-
}
185-
is SessionExpiredException -> {
186-
onSuccess.accept(error.amplifyCredential.getCognitoSession(innerException))
187-
sendHubEvent(AuthChannelEventName.SESSION_EXPIRED.toString())
188-
}
189-
is ServiceException -> {
190-
onSuccess.accept(error.amplifyCredential.getCognitoSession(innerException))
191-
}
192-
is NotAuthorizedException -> {
193-
onSuccess.accept(error.amplifyCredential.getCognitoSession(innerException))
194-
}
195-
else -> {
196-
val errorResult = UnknownException("Fetch auth session failed.", innerException)
197-
onSuccess.accept(error.amplifyCredential.getCognitoSession(errorResult))
198-
}
199-
}
200-
}
201-
is ConfigurationException -> {
202-
val errorResult = InvalidAccountTypeException(error)
203-
onSuccess.accept(AmplifyCredential.Empty.getCognitoSession(errorResult))
204-
}
205-
else -> {
206-
val errorResult = UnknownException("Fetch auth session failed.", error)
207-
onSuccess.accept(AmplifyCredential.Empty.getCognitoSession(errorResult))
208-
}
209-
}
210-
}
211-
else -> Unit
212-
}
213-
},
214-
null
215-
)
216-
}
217-
21879
private fun addAuthStateChangeListener() {
21980
authStateMachine.listen(
22081
StateChangeListenerToken(),
@@ -240,8 +101,4 @@ internal class RealAWSCognitoAuthPlugin(
240101
}
241102
)
242103
}
243-
244-
private fun sendHubEvent(eventName: String) {
245-
Amplify.Hub.publish(HubChannel.AUTH, HubEvent.create(eventName))
246-
}
247104
}

aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/usecases/AuthUseCaseFactory.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ internal class AuthUseCaseFactory(
2727
private val stateMachine: AuthStateMachine
2828
) {
2929

30-
fun fetchAuthSession() = FetchAuthSessionUseCase(plugin)
30+
fun fetchAuthSession() = FetchAuthSessionUseCase(stateMachine)
3131

3232
fun associateWebAuthnCredential() = AssociateWebAuthnCredentialUseCase(
3333
client = authEnvironment.requireIdentityProviderClient(),

aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/usecases/FetchAuthSessionUseCase.kt

Lines changed: 108 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,118 @@
1515

1616
package com.amplifyframework.auth.cognito.usecases
1717

18+
import com.amplifyframework.auth.AuthChannelEventName
1819
import com.amplifyframework.auth.cognito.AWSCognitoAuthSession
19-
import com.amplifyframework.auth.cognito.RealAWSCognitoAuthPlugin
20-
import kotlin.coroutines.resume
21-
import kotlin.coroutines.resumeWithException
22-
import kotlin.coroutines.suspendCoroutine
20+
import com.amplifyframework.auth.cognito.AuthStateMachine
21+
import com.amplifyframework.auth.cognito.CognitoAuthExceptionConverter.Companion.toAuthException
22+
import com.amplifyframework.auth.cognito.exceptions.service.InvalidAccountTypeException
23+
import com.amplifyframework.auth.cognito.getCognitoSession
24+
import com.amplifyframework.auth.cognito.isValid
25+
import com.amplifyframework.auth.exceptions.ConfigurationException
26+
import com.amplifyframework.auth.exceptions.InvalidStateException
27+
import com.amplifyframework.auth.exceptions.NotAuthorizedException
28+
import com.amplifyframework.auth.exceptions.ServiceException
29+
import com.amplifyframework.auth.exceptions.SessionExpiredException
30+
import com.amplifyframework.auth.exceptions.SignedOutException
31+
import com.amplifyframework.auth.options.AuthFetchSessionOptions
32+
import com.amplifyframework.auth.plugins.core.AuthHubEventEmitter
33+
import com.amplifyframework.statemachine.codegen.data.AmplifyCredential
34+
import com.amplifyframework.statemachine.codegen.errors.SessionError
35+
import com.amplifyframework.statemachine.codegen.events.AuthorizationEvent
36+
import com.amplifyframework.statemachine.codegen.states.AuthorizationState
37+
import kotlinx.coroutines.flow.drop
38+
import kotlinx.coroutines.flow.first
39+
import kotlinx.coroutines.flow.mapNotNull
40+
import kotlinx.coroutines.flow.onSubscription
2341

2442
internal class FetchAuthSessionUseCase(
25-
private val plugin: RealAWSCognitoAuthPlugin
43+
private val stateMachine: AuthStateMachine,
44+
private val emitter: AuthHubEventEmitter = AuthHubEventEmitter()
2645
) {
27-
suspend fun execute(): AWSCognitoAuthSession {
28-
// TODO - we should migrate the fetch auth session business logic to this class
29-
val session = suspendCoroutine { continuation ->
30-
plugin.fetchAuthSession(
31-
onSuccess = { continuation.resume(it) },
32-
onError = { continuation.resumeWithException(it) }
33-
)
46+
suspend fun execute(options: AuthFetchSessionOptions = AuthFetchSessionOptions.defaults()): AWSCognitoAuthSession {
47+
val forceRefresh = options.forceRefresh
48+
val currentState = stateMachine.getCurrentState()
49+
50+
return when (val authZState = currentState.authZState) {
51+
is AuthorizationState.Configured -> {
52+
waitForSession(AuthorizationEvent(AuthorizationEvent.EventType.FetchUnAuthSession))
53+
}
54+
is AuthorizationState.SessionEstablished -> {
55+
val credential = authZState.amplifyCredential
56+
if (credential.isValid() && !forceRefresh) {
57+
// Return existing credential
58+
credential.getCognitoSession()
59+
} else {
60+
// Refresh session
61+
val event = getRefreshSessionEvent(credential)
62+
waitForSession(event)
63+
}
64+
}
65+
is AuthorizationState.Error -> {
66+
when (val error = authZState.exception) {
67+
is SessionError -> waitForSession(getRefreshSessionEvent(error.amplifyCredential))
68+
else -> throw InvalidStateException()
69+
}
70+
}
71+
else -> throw InvalidStateException()
3472
}
35-
return session as AWSCognitoAuthSession
3673
}
74+
75+
private fun getRefreshSessionEvent(credential: AmplifyCredential): AuthorizationEvent =
76+
if (credential is AmplifyCredential.IdentityPoolFederated) {
77+
AuthorizationEvent(
78+
AuthorizationEvent.EventType.StartFederationToIdentityPool(
79+
credential.federatedToken,
80+
credential.identityId,
81+
credential
82+
)
83+
)
84+
} else {
85+
AuthorizationEvent(AuthorizationEvent.EventType.RefreshSession(credential))
86+
}
87+
88+
private suspend fun waitForSession(event: AuthorizationEvent): AWSCognitoAuthSession = stateMachine.state
89+
.onSubscription { stateMachine.send(event) }
90+
.drop(1)
91+
.mapNotNull { authState ->
92+
when (val authZState = authState.authZState) {
93+
is AuthorizationState.SessionEstablished -> {
94+
authZState.amplifyCredential.getCognitoSession()
95+
}
96+
is AuthorizationState.Error -> {
97+
when (val error = authZState.exception) {
98+
is SessionError -> {
99+
when (val innerException = error.exception) {
100+
is SignedOutException -> {
101+
error.amplifyCredential.getCognitoSession(innerException)
102+
}
103+
is SessionExpiredException -> {
104+
emitter.sendHubEvent(AuthChannelEventName.SESSION_EXPIRED.toString())
105+
error.amplifyCredential.getCognitoSession(innerException)
106+
}
107+
is ServiceException -> {
108+
error.amplifyCredential.getCognitoSession(innerException)
109+
}
110+
is NotAuthorizedException -> {
111+
error.amplifyCredential.getCognitoSession(innerException)
112+
}
113+
else -> {
114+
val errorResult = innerException.toAuthException("Fetch auth session failed.")
115+
error.amplifyCredential.getCognitoSession(errorResult)
116+
}
117+
}
118+
}
119+
is ConfigurationException -> {
120+
val errorResult = InvalidAccountTypeException(error)
121+
AmplifyCredential.Empty.getCognitoSession(errorResult)
122+
}
123+
else -> {
124+
val errorResult = error.toAuthException("Fetch auth session failed.")
125+
AmplifyCredential.Empty.getCognitoSession(errorResult)
126+
}
127+
}
128+
}
129+
else -> null
130+
}
131+
}.first()
37132
}

0 commit comments

Comments
 (0)