Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -8,11 +8,23 @@ import com.auth0.android.NetworkErrorException
import com.auth0.android.dpop.DPoP
import com.auth0.android.dpop.DPoPException
import com.auth0.android.dpop.SenderConstraining
import com.auth0.android.request.*
import com.auth0.android.request.internal.*
import com.auth0.android.request.AuthenticationRequest
import com.auth0.android.request.ErrorAdapter
import com.auth0.android.request.JsonAdapter
import com.auth0.android.request.ProfileRequest
import com.auth0.android.request.PublicKeyCredentials
import com.auth0.android.request.Request
import com.auth0.android.request.SignUpRequest
import com.auth0.android.request.UserData
import com.auth0.android.request.internal.BaseAuthenticationRequest
import com.auth0.android.request.internal.BaseRequest
import com.auth0.android.request.internal.GsonAdapter
import com.auth0.android.request.internal.GsonAdapter.Companion.forMap
import com.auth0.android.request.internal.GsonAdapter.Companion.forMapOf
import com.auth0.android.request.internal.GsonProvider
import com.auth0.android.request.internal.RequestFactory
import com.auth0.android.request.internal.ResponseUtils.isNetworkError
import com.auth0.android.request.internal.validator.CustomTokenExchangeValidator
import com.auth0.android.result.Challenge
import com.auth0.android.result.Credentials
import com.auth0.android.result.DatabaseUser
Expand Down Expand Up @@ -749,13 +761,16 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
*
* @param subjectTokenType the subject token type that is associated with the existing Identity Provider. e.g. 'http://acme.com/legacy-token'
* @param subjectToken the subject token, typically obtained through the Identity Provider's SDK
* @param organization id of the organization the user belongs to
* @return a request to configure and start that will yield [Credentials]
*/
public fun customTokenExchange(
subjectTokenType: String,
subjectToken: String,
organization: String? = null
): AuthenticationRequest {
return tokenExchange(subjectTokenType, subjectToken)
return tokenExchange(subjectTokenType, subjectToken, organization)
.addValidator(CustomTokenExchangeValidator())
}

/**
Expand Down Expand Up @@ -1043,13 +1058,17 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
*/
private fun tokenExchange(
subjectTokenType: String,
subjectToken: String
subjectToken: String,
organization: String? = null
): AuthenticationRequest {
val parameters = ParameterBuilder.newAuthenticationBuilder()
.setGrantType(ParameterBuilder.GRANT_TYPE_TOKEN_EXCHANGE)
.set(SUBJECT_TOKEN_TYPE_KEY, subjectTokenType)
.set(SUBJECT_TOKEN_KEY, subjectToken)
.asDictionary()
val parameters = ParameterBuilder.newAuthenticationBuilder().apply {
setGrantType(ParameterBuilder.GRANT_TYPE_TOKEN_EXCHANGE)
set(SUBJECT_TOKEN_TYPE_KEY, subjectTokenType)
set(SUBJECT_TOKEN_KEY, subjectToken)
organization?.let {
set(ORGANIZATION_KEY, it)
}
}.asDictionary()
return loginWithToken(parameters)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.auth0.android.request

import com.auth0.android.Auth0
import com.auth0.android.authentication.AuthenticationException
import com.auth0.android.callback.Callback
import com.auth0.android.result.Credentials

/**
Expand Down Expand Up @@ -74,4 +73,15 @@ public interface AuthenticationRequest : Request<Credentials, AuthenticationExce
* @return the current builder instance
*/
public fun withIdTokenVerificationIssuer(issuer: String): AuthenticationRequest

/**
* Adds a validator to be executed before the request is sent.
* Multiple validators can be added and will be executed in order.
*
* @param validator the validator to add
* @return itself
*/
override fun addValidator(validator: RequestValidator): AuthenticationRequest {
return this
}
}
11 changes: 11 additions & 0 deletions auth0/src/main/java/com/auth0/android/request/Request.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,15 @@ public interface Request<T, U : Auth0Exception> {
* @return itself
*/
public fun addHeader(name: String, value: String): Request<T, U>

/**
* Adds a validator to be executed before the request is sent.
* Multiple validators can be added and will be executed in order.
*
* @param validator the validator to add
* @return itself
*/
public fun addValidator(validator: RequestValidator): Request<T, U> {
return this
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.auth0.android.request

import com.auth0.android.Auth0Exception

/**
* Interface for validating request parameters before execution.
* Validators are invoked before the network request is made.
*/
public interface RequestValidator {

/**
* Validates the request options and parameters.
* @param options the request options to validate
* @throws Auth0Exception if validation fails
*/
@Throws(Auth0Exception::class)
public fun validate(options: RequestOptions)
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ public class SignUpRequest
return this
}

override fun addValidator(validator: RequestValidator): AuthenticationRequest {
authenticationRequest.addValidator(validator)
return this
}

override fun withIdTokenVerificationLeeway(leeway: Int): SignUpRequest {
authenticationRequest.withIdTokenVerificationLeeway(leeway)
return this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ import com.auth0.android.Auth0Exception
import com.auth0.android.authentication.AuthenticationException
import com.auth0.android.authentication.ParameterBuilder
import com.auth0.android.callback.Callback
import com.auth0.android.provider.*
import com.auth0.android.provider.IdTokenMissingException
import com.auth0.android.provider.IdTokenVerificationOptions
import com.auth0.android.provider.IdTokenVerifier
import com.auth0.android.provider.TokenValidationException
import com.auth0.android.provider.UnexpectedIdTokenException
import com.auth0.android.request.AuthenticationRequest
import com.auth0.android.request.Request
import com.auth0.android.request.RequestValidator
import com.auth0.android.result.Credentials
import java.util.*
import java.util.Date

internal open class BaseAuthenticationRequest(
private val request: Request<Credentials, AuthenticationException>,
Expand Down Expand Up @@ -97,6 +102,11 @@ internal open class BaseAuthenticationRequest(
return this
}

override fun addValidator(validator: RequestValidator): AuthenticationRequest {
request.addValidator(validator)
return this
}

override fun validateClaims(): AuthenticationRequest {
this.validateClaims = true
return this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.auth0.android.request.JsonAdapter
import com.auth0.android.request.NetworkingClient
import com.auth0.android.request.Request
import com.auth0.android.request.RequestOptions
import com.auth0.android.request.RequestValidator
import com.auth0.android.request.ServerResponse
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -40,6 +41,8 @@ internal open class BaseRequest<T, U : Auth0Exception>(

private val options: RequestOptions = RequestOptions(method)

private val validators = mutableListOf<RequestValidator>()

override fun addHeader(name: String, value: String): Request<T, U> {
options.headers[name] = value
return this
Expand Down Expand Up @@ -70,6 +73,11 @@ internal open class BaseRequest<T, U : Auth0Exception>(
return this
}

override fun addValidator(validator: RequestValidator): Request<T, U> {
validators.add(validator)
return this
}

/**
* Runs asynchronously and executes the network request, without blocking the current thread.
* The result is parsed into a <T> value and posted in the callback's onSuccess method or a <U>
Expand Down Expand Up @@ -126,6 +134,7 @@ internal open class BaseRequest<T, U : Auth0Exception>(
*/
@kotlin.jvm.Throws(Auth0Exception::class)
override fun execute(): T {
runClientValidation()
val response: ServerResponse
try {
if (dPoP?.shouldGenerateProof(url, options.parameters) == true) {
Expand Down Expand Up @@ -176,4 +185,10 @@ internal open class BaseRequest<T, U : Auth0Exception>(
}
}

private fun runClientValidation() {
validators.forEach { validator ->
validator.validate(options)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.auth0.android.request.internal.validator

import com.auth0.android.authentication.AuthenticationException
import com.auth0.android.request.RequestOptions
import com.auth0.android.request.RequestValidator
import java.net.URI

/**
* Client side validation for custom token exchange
*/
public class CustomTokenExchangeValidator : RequestValidator {

private val reservedNamespaces = listOf(
"http://auth0.com",
"https://auth0.com",
"http://okta.com",
"https://okta.com",
"urn:ietf",
"urn:auth0",
"urn:okta"
)

override fun validate(options: RequestOptions) {
val subjectTokenType = options.parameters["subject_token_type"] as String

if(subjectTokenType.isEmpty()){
throw AuthenticationException(
"Invalid URI", IllegalArgumentException(
"The passed URI must not be an empty String"
)
)
}

// Check if it's a reserved namespace
if (reservedNamespaces.contains(subjectTokenType)) {
throw AuthenticationException(
"Invalid URI", IllegalArgumentException(
"The passed URI is a reserved namespace and cannot be used"
)
)
}

// If it starts with http:// or https://, validate it as a URI
if (subjectTokenType.startsWith(
"http://",
ignoreCase = true
) || subjectTokenType.startsWith("https://", ignoreCase = true)
) {
runCatching {
URI(subjectTokenType)
}.onFailure { error ->
throw AuthenticationException(
"Invalid URI", IllegalArgumentException(
"The subject_token_type is not a valid URI: ${error.message}"
)
)
}
}
}
}
Loading