Skip to content

Commit

Permalink
Added PrefillRequest and some other changes
Browse files Browse the repository at this point in the history
  • Loading branch information
lalwani committed Mar 21, 2024
1 parent 1d5f0d2 commit b2bf68a
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ import kotlinx.parcelize.Parcelize
* @see AuthContext
*/
@Parcelize
sealed class AuthType(val grantType: String) : Parcelable {
sealed class AuthType() : Parcelable {

/** The authorization code flow. */
data object AuthCode : AuthType("code")
data object AuthCode : AuthType()

/** The proof key for code exchange (PKCE) flow. This is the recommended flow for mobile apps. */
data object PKCE : AuthType("code")
data class PKCE(val grantType: String = "authorization_code") : AuthType()
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import com.uber.sdk2.auth.api.response.AuthResult
import com.uber.sdk2.auth.api.response.PARResponse
import com.uber.sdk2.auth.api.response.UberToken
import com.uber.sdk2.auth.internal.service.AuthService
import com.uber.sdk2.auth.internal.service.PrefillRequest
import com.uber.sdk2.auth.internal.sso.SsoLinkFactory

class AuthProvider(
Expand All @@ -42,13 +43,12 @@ class AuthProvider(
val ssoConfig = SsoConfigProvider.getSsoConfig(activity)
val parResponse =
authContext.prefillInfo?.let {
val response =
authService.loginParRequest(ssoConfig.clientId, "code", it, ssoConfig.scope ?: "profile")
if (response.isSuccessful && response.body() != null) {
response.body()
} else {
throw AuthException.ServerError("bad response ${response.code()}")
}
PrefillRequest.pushedAuthorizationRequest(
authService,
ssoConfig.clientId,
it,
ssoConfig.scope ?: "profile",
)
} ?: PARResponse("", "")

val queryParams: Map<String, String> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ package com.uber.sdk2.auth.internal.service

// import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory

import com.uber.sdk2.auth.api.request.PrefillInfo
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.uber.sdk2.auth.api.response.PARResponse
import com.uber.sdk2.auth.api.response.UberToken
import com.uber.sdk2.core.config.UriConfig
Expand All @@ -36,7 +37,7 @@ interface AuthService {
suspend fun loginParRequest(
@Field("client_id") clientId: String,
@Field("response_type") responseType: String,
@Field("login_hint") prefillInfo: PrefillInfo,
@Field("login_hint") loginHint: String,
@Field("scope") scope: String,
): Response<PARResponse>

Expand All @@ -53,9 +54,11 @@ interface AuthService {
companion object {
/** Creates an instance of [AuthService]. */
fun create(): AuthService {
val moshi =
Moshi.Builder().add(Base64PrefillInfoAdapter()).addLast(KotlinJsonAdapterFactory()).build()
return Retrofit.Builder()
.baseUrl(UriConfig.getAuthHost())
.addConverterFactory(MoshiConverterFactory.create())
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
.create(AuthService::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2024. Uber Technologies
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.uber.sdk2.auth.internal.service

import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.uber.sdk2.auth.api.exception.AuthException
import com.uber.sdk2.auth.api.exception.AuthException.ServerError
import com.uber.sdk2.auth.api.request.PrefillInfo
import com.uber.sdk2.auth.api.response.PARResponse
import com.uber.sdk2.auth.internal.sso.UniversalSsoLink
import java.nio.charset.StandardCharsets
import java.util.Base64

object PrefillRequest {

suspend fun pushedAuthorizationRequest(
authService: AuthService,
clientId: String,
prefillInfo: PrefillInfo,
scope: String,
): PARResponse {
val moshi =
Moshi.Builder()
.add(KotlinJsonAdapterFactory()) // Needed for Kotlin data classes
.build()
val profileHintJsonAdapter: JsonAdapter<PrefillInfo> = moshi.adapter(PrefillInfo::class.java)
val profileHintString =
String(
Base64.getEncoder()
.encode(profileHintJsonAdapter.toJson(prefillInfo).toByteArray(StandardCharsets.UTF_8))
)
val response =
authService.loginParRequest(
clientId,
UniversalSsoLink.RESPONSE_TYPE,
profileHintString,
scope,
)
if (response.isSuccessful && response.body() != null) {
return response.body() ?: throw ServerError(AuthException.EMPTY_RESPONSE)
} else {
throw ServerError("Bad response from server. code: ${response.code()}")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ internal class UniversalSsoLink(

override suspend fun execute(optionalQueryParams: Map<String, String>): String {
val uri =
UriConfig.assembleUri(ssoConfig.clientId, "code", ssoConfig.redirectUri, ssoConfig.scope)
UriConfig.assembleUri(
ssoConfig.clientId,
RESPONSE_TYPE,
ssoConfig.redirectUri,
ssoConfig.scope,
)

optionalQueryParams.entries.forEach { entry ->
uri.buildUpon().appendQueryParameter(entry.key, entry.value).build()
Expand Down Expand Up @@ -121,4 +126,9 @@ internal class UniversalSsoLink(
private fun loadCustomtab(uri: Uri) {
customTabsLauncher.launch(uri)
}

companion object {
/** The response type constant for the SSO authentication. */
internal const val RESPONSE_TYPE = "code"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2024. Uber Technologies
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.uber.sdk2.auth.internal.service

import com.uber.sdk2.auth.RobolectricTestBase
import com.uber.sdk2.auth.api.request.PrefillInfo
import com.uber.sdk2.auth.api.response.PARResponse
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Test
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import retrofit2.Response

class PrefillRequestTest : RobolectricTestBase() {
private val authService: AuthService = mock()
private val prefillInfo = PrefillInfo("email", "firstName", "lastName", "phoneNumber")

@Test
fun `test pushedAuthorizationRequest when successfulResponse should receiveRequestUri`() =
runTest {
whenever(authService.loginParRequest(any(), any(), any(), any()))
.thenReturn(Response.success(PARResponse("requestUri", "expiresIn")))
val response =
PrefillRequest.pushedAuthorizationRequest(authService, "clientId", prefillInfo, "scope")
assertNotNull(response)
assertEquals("requestUri", response.requestUri)
}
}

0 comments on commit b2bf68a

Please sign in to comment.