Skip to content

Commit

Permalink
UUI-1161 Enable setting/getting custom state param in auth flow
Browse files Browse the repository at this point in the history
  • Loading branch information
pklawikowski-schibsted committed Apr 23, 2024
1 parent 7c96b62 commit 0b20c0a
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class LoggedInActivity : AppCompatActivity() {
initLogoutButton()
initProfileDataButton()
initExternalIdButton()
initGetCustomStateButton()
initSessionExchangeButtonButton()
initAccountPagesButtonButton()
initMakeAuthenticatedRequestButton()
Expand Down Expand Up @@ -81,6 +82,14 @@ class LoggedInActivity : AppCompatActivity() {
}
}

private fun initGetCustomStateButton() {
binding.customStateButton.setOnClickListener {
if (isUserLoggedIn) {
Timber.i("Custom state ${client?.getState()} ")
}
}
}

private fun initSessionExchangeButtonButton() {
binding.sessionExchangeButton.setOnClickListener {
if (isUserLoggedIn) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class MainActivity : AppCompatActivity() {

private fun initializeButtons() {
binding.loginButton.setOnClickListener {
startActivity(ExampleApp.client.getAuthenticationIntent(this))
startActivity(ExampleApp.client.getAuthenticationIntent(this, "customState"))
}
binding.manualLoginButton.setOnClickListener {
startActivity(Intent(this, ManualLoginActivity::class.java))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class ManualLoginActivity : AppCompatActivity() {

private fun initLoginButton() {
binding.loginButton.setOnClickListener {
client.launchAuth(this)
client.launchAuth(this, "customState")
}
}

Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/layout/activity_logged_in.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
android:layout_height="wrap_content"
android:text="@string/fetch_external_id_button"/>

<Button
android:id="@+id/customStateButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/get_custom_state_button"/>

<Button
android:id="@+id/sessionExchangeButton"
android:layout_width="wrap_content"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<string name="logged_in_text">You\'re logged in!</string>
<string name="fetch_profile_data_button">Fetch profile data</string>
<string name="fetch_external_id_button">Fetch external Id for TCF</string>
<string name="get_custom_state_button">Get custom state</string>
<string name="start_session_exchange_button">Start session exchange</string>
<string name="account_pages_button">Account pages</string>
<string name="logout_button">Logout</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
import java.security.MessageDigest
import java.security.spec.MGF1ParameterSpec.SHA256
import java.util.Date
import kotlin.coroutines.resume

Expand Down Expand Up @@ -100,14 +101,17 @@ class Client {
*
* Requires [AuthorizationManagementActivity.setup] to have been called before this.
*
* @param authRequest Authentication request parameters.
* @param context Context.
* @param state Optional string that overrides [state] query item of loginURL, which is otherwise a random 10 character string.
* @param authRequest Optional [AuthRequest] parameter.
*/
@JvmOverloads
fun getAuthenticationIntent(
context: Context,
authRequest: AuthRequest = AuthRequest()
state: String? = null,
authRequest: AuthRequest = AuthRequest(),
): Intent {
val loginUrl = generateLoginUrl(authRequest)
val loginUrl = generateLoginUrl(authRequest, state)
val intent: Intent = if (isCustomTabsSupported(context)) {
buildCustomTabsIntent()
.apply {
Expand All @@ -122,11 +126,13 @@ class Client {
/**
* Start auth activity manually.
*
* @param authRequest Authentication request parameters.
* @param context Context.
* @param state Optional string that overrides [state] query item of loginURL, which is otherwise a random 10 character string.
* @param authRequest Optional [AuthRequest] parameter.
*/
@JvmOverloads
fun launchAuth(context: Context, authRequest: AuthRequest = AuthRequest()) {
val loginUrl = generateLoginUrl(authRequest)
fun launchAuth(context: Context, state: String?, authRequest: AuthRequest = AuthRequest()) {
val loginUrl = generateLoginUrl(authRequest, state)
if (isCustomTabsSupported(context)) {
buildCustomTabsIntent().launchUrl(context, loginUrl)
} else {
Expand Down Expand Up @@ -161,13 +167,28 @@ class Client {
}
}

/**
* Returns state of current login session.
*
* @return State of current login session if state is saved, if not returns null.
*/
fun getState(): String? {
return stateStorage.getValue(AUTH_STATE_KEY, AuthState::class)?.state
}

private fun buildCustomTabsIntent(): CustomTabsIntent {
return CustomTabsIntent.Builder()
.build()
}

private fun generateLoginUrl(authRequest: AuthRequest): Uri {
val loginUrl = urlBuilder.loginUrl(authRequest)
/**
* Generate login URL.
*
* @param authRequest Authentication request parameters.
* @param state State.
*/
private fun generateLoginUrl(authRequest: AuthRequest, state: String?): Uri {
val loginUrl = urlBuilder.loginUrl(authRequest, state)
Timber.d("Login url: $loginUrl")
return Uri.parse(loginUrl)
}
Expand Down Expand Up @@ -211,7 +232,7 @@ class Client {
return
}

stateStorage.removeValue(AUTH_STATE_KEY)
//stateStorage.removeValue(AUTH_STATE_KEY)

if (error != null) {
val oauthError = OAuthError(error, errorDescription)
Expand Down Expand Up @@ -327,13 +348,13 @@ class Client {
context: Context,
supportFragmentManager: FragmentManager,
isCancelable: Boolean = true
) : Boolean {
): Boolean {
val internalSessionFound = hasSessionStorage(configuration.clientId)

return if (!internalSessionFound && userHasSessionOnDevice(context.applicationContext)) {
LoginPromptManager(
LoginPromptConfig(
this.getAuthenticationIntent(context),
this.getAuthenticationIntent(context, null),
isCancelable
)
).showLoginPromptIfAbsent(supportFragmentManager)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ internal class UrlBuilder(
) {
private val defaultScopeValues = setOf("openid", "offline_access")

fun loginUrl(authRequest: AuthRequest): String {
val state = Util.randomString(10)
fun loginUrl(authRequest: AuthRequest, state: String? = null): String {
val stateValue = state?.let { state } ?: Util.randomString(10)
val nonce = Util.randomString(10)
val codeVerifier = Util.randomString(60)

stateStorage.setValue(
authStateKey,
AuthState(state, nonce, codeVerifier, authRequest.mfa)
AuthState(stateValue, nonce, codeVerifier, authRequest.mfa)
)

val scopes = authRequest.extraScopeValues.union(defaultScopeValues)
Expand All @@ -30,7 +30,7 @@ internal class UrlBuilder(
"client_id" to clientConfig.clientId,
"redirect_uri" to clientConfig.redirectUri,
"response_type" to "code",
"state" to state,
"state" to stateValue,
"scope" to scopeString,
"nonce" to nonce,
"code_challenge" to codeChallenge,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,12 @@ class UrlBuilderTest {
assertNull(queryParams["prompt"])
assertEquals(MfaType.OTP.value, queryParams["acr_values"])
}

@Test
fun loginUrlShouldContainCustomStateSpecified() {
val loginUrl = getUrlBuilder().loginUrl(AuthRequest(), "customState")
val queryParams = Util.parseQueryParameters(URL(loginUrl).query)

assertEquals("customState", queryParams["state"])
}
}

0 comments on commit 0b20c0a

Please sign in to comment.