Skip to content

Commit

Permalink
feat!: introduce GenerateSignInUriOptions
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoyijun committed Sep 5, 2024
1 parent 0280929 commit 952b796
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import io.logto.sdk.android.type.LogtoConfig
import io.logto.sdk.core.Core
import io.logto.sdk.core.exception.CallbackUriVerificationException
import io.logto.sdk.core.type.CodeTokenResponse
import io.logto.sdk.core.type.GenerateSignInUriOptions
import io.logto.sdk.core.type.OidcConfigResponse
import io.logto.sdk.core.util.CallbackUriUtils
import io.logto.sdk.core.util.GenerateUtils
Expand All @@ -31,14 +32,16 @@ class LogtoAuthSession(
LogtoAuthManager.handleAuthStart(this)

val signInUri = Core.generateSignInUri(
authorizationEndpoint = oidcConfig.authorizationEndpoint,
clientId = logtoConfig.appId,
redirectUri = redirectUri,
codeChallenge = GenerateUtils.generateCodeChallenge(codeVerifier),
state = state,
scopes = logtoConfig.scopes,
resources = logtoConfig.resources,
prompt = logtoConfig.prompt,
GenerateSignInUriOptions(
authorizationEndpoint = oidcConfig.authorizationEndpoint,
clientId = logtoConfig.appId,
redirectUri = redirectUri,
codeChallenge = GenerateUtils.generateCodeChallenge(codeVerifier),
state = state,
scopes = logtoConfig.scopes,
resources = logtoConfig.resources,
prompt = logtoConfig.prompt,
),
)

LogtoWebViewAuthActivity.launch(context, signInUri)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.logto.sdk.core.Core
import io.logto.sdk.core.exception.CallbackUriVerificationException
import io.logto.sdk.core.http.HttpCompletion
import io.logto.sdk.core.type.CodeTokenResponse
import io.logto.sdk.core.type.GenerateSignInUriOptions
import io.logto.sdk.core.type.OidcConfigResponse
import io.logto.sdk.core.util.CallbackUriUtils
import io.mockk.Runs
Expand Down Expand Up @@ -59,7 +60,7 @@ class LogtoAuthSessionTest {
val mockCompletion: Completion<LogtoException, CodeTokenResponse> = mockk()

every {
Core.generateSignInUri(any(), any(), any(), any(), any(), any(), any(), any())
Core.generateSignInUri(any())
} returns "testSignInUri"

val logtoAuthSession = LogtoAuthSession(
Expand Down Expand Up @@ -89,7 +90,7 @@ class LogtoAuthSessionTest {
mockkObject(LogtoAuthManager)
val mockLogtoConfig: LogtoConfig = mockk()
val invalidRedirectUri = ""
val mockCompletion : Completion<LogtoException, CodeTokenResponse> = mockk()
val mockCompletion: Completion<LogtoException, CodeTokenResponse> = mockk()
every { mockCompletion.onComplete(any(), any()) } just Runs

val logtoAuthSession = LogtoAuthSession(
Expand All @@ -114,16 +115,16 @@ class LogtoAuthSessionTest {
.isEqualTo(LogtoException.Type.INVALID_REDIRECT_URI.name)
assertThat(codeTokenResponseCapture.last()).isNull()

verify(exactly = 0){
verify(exactly = 0) {
LogtoAuthManager.handleAuthStart(logtoAuthSession)
Core.generateSignInUri(any(), any(), any(), any(), any(), any(), any(), any())
Core.generateSignInUri(any())
mockActivity.startActivity(any())
}
}

@Test
fun `handleCallbackUri should complete with expected results`() {
val mockCompletion : Completion<LogtoException, CodeTokenResponse> = mockk()
val mockCompletion: Completion<LogtoException, CodeTokenResponse> = mockk()
every { mockCompletion.onComplete(any(), any()) } just Runs

val logtoAuthSession = LogtoAuthSession(
Expand All @@ -138,7 +139,13 @@ class LogtoAuthSessionTest {
val dummyValidCallbackUri = Uri.parse("$dummyRedirectUri?code=$testCode&state=dummystate")
val mockCodeTokenResponse: CodeTokenResponse = mockk()
mockkObject(CallbackUriUtils)
every { CallbackUriUtils.verifyAndParseCodeFromCallbackUri(any(), any(), any()) } returns testCode
every {
CallbackUriUtils.verifyAndParseCodeFromCallbackUri(
any(),
any(),
any()
)
} returns testCode

every {
Core.fetchTokenByAuthorizationCode(any(), any(), any(), any(), any(), any(), any())
Expand All @@ -160,7 +167,7 @@ class LogtoAuthSessionTest {
val logtoExceptionCapture = mutableListOf<LogtoException?>()
val codeTokenResponseCapture = mutableListOf<CodeTokenResponse?>()

val mockCompletion : Completion<LogtoException, CodeTokenResponse> = mockk()
val mockCompletion: Completion<LogtoException, CodeTokenResponse> = mockk()
every { mockCompletion.onComplete(any(), any()) } just Runs

val logtoAuthSession = LogtoAuthSession(
Expand Down Expand Up @@ -199,13 +206,19 @@ class LogtoAuthSessionTest {
val logtoExceptionCapture = mutableListOf<LogtoException?>()
val codeTokenResponseCapture = mutableListOf<CodeTokenResponse?>()

val mockCompletion : Completion<LogtoException, CodeTokenResponse> = mockk()
val mockCompletion: Completion<LogtoException, CodeTokenResponse> = mockk()
every { mockCompletion.onComplete(any(), any()) } just Runs

val testCode = "testCode"
val dummyValidCallbackUri = Uri.parse("$dummyRedirectUri?code=$testCode&state=dummystate")
mockkObject(CallbackUriUtils)
every { CallbackUriUtils.verifyAndParseCodeFromCallbackUri(any(), any(), any()) } returns testCode
every {
CallbackUriUtils.verifyAndParseCodeFromCallbackUri(
any(),
any(),
any()
)
} returns testCode

val mockFetchException: Throwable = mockk()
every {
Expand Down Expand Up @@ -247,7 +260,7 @@ class LogtoAuthSessionTest {
val logtoExceptionCapture = mutableListOf<LogtoException?>()
val codeTokenResponseCapture = mutableListOf<CodeTokenResponse?>()

val mockCompletion : Completion<LogtoException, CodeTokenResponse> = mockk()
val mockCompletion: Completion<LogtoException, CodeTokenResponse> = mockk()
every { mockCompletion.onComplete(any(), any()) } just Runs

val logtoAuthSession = LogtoAuthSession(
Expand Down
29 changes: 11 additions & 18 deletions kotlin-sdk/kotlin/src/main/kotlin/io/logto/sdk/core/Core.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import io.logto.sdk.core.http.HttpEmptyCompletion
import io.logto.sdk.core.http.httpGet
import io.logto.sdk.core.http.httpPost
import io.logto.sdk.core.type.CodeTokenResponse
import io.logto.sdk.core.type.GenerateSignInUriOptions
import io.logto.sdk.core.type.OidcConfigResponse
import io.logto.sdk.core.type.RefreshTokenTokenResponse
import io.logto.sdk.core.type.UserInfoResponse
Expand All @@ -21,31 +22,23 @@ import okhttp3.FormBody
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull

object Core {
fun generateSignInUri(
authorizationEndpoint: String,
clientId: String,
redirectUri: String,
codeChallenge: String,
state: String,
scopes: List<String>?,
resources: List<String>?,
prompt: String?,
): String {
val constructedUri = authorizationEndpoint.toHttpUrlOrNull() ?: throw UriConstructionException(
fun generateSignInUri(options: GenerateSignInUriOptions): String {
val constructedUri = options.authorizationEndpoint.toHttpUrlOrNull() ?: throw UriConstructionException(
UriConstructionException.Type.INVALID_ENDPOINT,
)

return constructedUri.newBuilder().apply {
addQueryParameter(QueryKey.CLIENT_ID, clientId)
addQueryParameter(QueryKey.CODE_CHALLENGE, codeChallenge)
addQueryParameter(QueryKey.CLIENT_ID, options.clientId)
addQueryParameter(QueryKey.CODE_CHALLENGE, options.codeChallenge)
addQueryParameter(QueryKey.CODE_CHALLENGE_METHOD, CodeChallengeMethod.S256)
addQueryParameter(QueryKey.STATE, state)
addQueryParameter(QueryKey.REDIRECT_URI, redirectUri)
addQueryParameter(QueryKey.STATE, options.state)
addQueryParameter(QueryKey.REDIRECT_URI, options.redirectUri)
addQueryParameter(QueryKey.RESPONSE_TYPE, ResponseType.CODE)

val usedScopes = ScopeUtils.withDefaultScopes(scopes)
val usedScopes = ScopeUtils.withDefaultScopes(options.scopes)
addQueryParameter(QueryKey.SCOPE, usedScopes.joinToString(" "))

val usedResources = resources.orEmpty()
val usedResources = options.resources.orEmpty()
for (value in usedResources) { addQueryParameter(QueryKey.RESOURCE, value) }
if (
usedScopes.contains(UserScope.ORGANIZATIONS) &&
Expand All @@ -54,7 +47,7 @@ object Core {
addQueryParameter(QueryKey.RESOURCE, ReservedResource.ORGANIZATION)
}

addQueryParameter(QueryKey.PROMPT, prompt ?: PromptValue.CONSENT)
addQueryParameter(QueryKey.PROMPT, options.prompt ?: PromptValue.CONSENT)
}.build().toString()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.logto.sdk.core.type

class GenerateSignInUriOptions(
val authorizationEndpoint: String,
val clientId: String,
val redirectUri: String,
val codeChallenge: String,
val state: String,
val scopes: List<String>? = null,
val resources: List<String>? = null,
val prompt: String? = null,
)
Loading

0 comments on commit 952b796

Please sign in to comment.