Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native auth: Add support for claims request, AB#3117218, Fixes AB#3117218 #2572

Merged
merged 6 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
vNext
----------
- [MINOR] Add support for OneBox Environment (#2559)
- [MINOR] Add support for claims requests for native authentication (#2572)

Version 19.0.0
----------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class NativeAuthMsalController : BaseNativeAuthController() {
"Parameters has password"
)
val mergedScopes = addDefaultScopes(parameters.scopes)
var parametersWithScopes = CommandUtil.createSignInStartCommandParametersWithScopes(
val parametersWithScopes = CommandUtil.createSignInStartCommandParametersWithScopes(
parameters,
mergedScopes
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public static SignInSubmitPasswordCommandParameters createSignInSubmitPasswordCo
.password(parameters.getPassword())
.scopes(parameters.getScopes())
.correlationId(correlationId)
.claimsRequestJson(parameters.getClaimsRequestJson())
.challengeType(parameters.getChallengeType())
.build();

Expand Down Expand Up @@ -189,6 +190,7 @@ public static SignInSubmitCodeCommandParameters createSignInSubmitCodeCommandPar
.scopes(parameters.getScopes())
.correlationId(parameters.getCorrelationId())
.challengeType(parameters.getChallengeType())
.claimsRequestJson(parameters.claimsRequestJson)
.build();

return commandParameters;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.microsoft.identity.common.nativeauth.internal.util

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.microsoft.identity.common.components.AndroidPlatformComponentsFactory
import com.microsoft.identity.common.java.interfaces.IPlatformComponents
import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFASubmitChallengeCommandParameters
import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInStartCommandParameters
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.MockitoAnnotations
import org.robolectric.RobolectricTestRunner
import java.util.UUID

/**
* Tests for [CommandUtil].
*/
@RunWith(RobolectricTestRunner::class)
class CommandUtilTest {

private lateinit var platformComponents: IPlatformComponents
private lateinit var context: Context

@Before
fun setup() {
MockitoAnnotations.initMocks(this)
context = ApplicationProvider.getApplicationContext()
platformComponents = AndroidPlatformComponentsFactory.createFromContext(
context
)
}

@Test
fun testCreateSignInSubmitPasswordCommandParameters_containsCorrectInfo() {
val correlationId = UUID.randomUUID().toString()
val continuationToken = "continuation"
val signInStartParams = SignInStartCommandParameters.builder()
.password("test".toCharArray())
.claimsRequestJson("claimsRequestJson")
.clientId("clientId")
.challengeType(arrayListOf("OOB"))
.redirectUri("redirectUri")
.username("username")
.platformComponents(platformComponents)
.build()
val submitPasswordParams = CommandUtil.createSignInSubmitPasswordCommandParameters(signInStartParams, correlationId, continuationToken)

assert(submitPasswordParams.getPassword().contentEquals(signInStartParams.getPassword()))
assert(submitPasswordParams.getContinuationToken().contentEquals(continuationToken))
assert(submitPasswordParams.correlationId?.contentEquals(correlationId) == true)
assert(submitPasswordParams.getClaimsRequestJson().contentEquals(signInStartParams.getClaimsRequestJson()))
assert(submitPasswordParams.clientId?.contentEquals(signInStartParams.clientId) == true)
assert(submitPasswordParams.getChallengeType()?.equals(signInStartParams.getChallengeType()) == true)
assert(submitPasswordParams.redirectUri?.equals(signInStartParams.redirectUri) == true)
}

@Test
fun testCreateSignInSubmitCodeCommandParameters_containsCorrectInfo() {
val mfaSubmitChallengeParams = MFASubmitChallengeCommandParameters.builder()
.claimsRequestJson("claimsRequestJson")
.clientId("clientId")
.challengeType(arrayListOf("OOB"))
.redirectUri("redirectUri")
.platformComponents(platformComponents)
.challenge("123456")
.continuationToken("continuationToken")
.correlationId(UUID.randomUUID().toString())
.build()
val submitCodeParams = CommandUtil.createSignInSubmitCodeCommandParameters(mfaSubmitChallengeParams)

assert(submitCodeParams.getContinuationToken().contentEquals(mfaSubmitChallengeParams.getContinuationToken()))
assert(submitCodeParams.correlationId?.contentEquals(mfaSubmitChallengeParams.correlationId) == true)
assert(submitCodeParams.getClaimsRequestJson().contentEquals(mfaSubmitChallengeParams.getClaimsRequestJson()))
assert(submitCodeParams.clientId?.contentEquals(mfaSubmitChallengeParams.clientId) == true)
assert(submitCodeParams.getChallengeType()?.equals(mfaSubmitChallengeParams.getChallengeType()) == true)
assert(submitCodeParams.getCode() == mfaSubmitChallengeParams.getChallenge())
assert(submitCodeParams.redirectUri?.equals(mfaSubmitChallengeParams.redirectUri) == true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import lombok.experimental.SuperBuilder;

/**
* BaseSignInTokenCommandParameters is the base class for parameters for all all Native Auth sign in related commands.
* BaseSignInTokenCommandParameters is the base class for parameters for all Native Auth sign in related commands.
*/
@Getter
@EqualsAndHashCode(callSuper = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
//THE SOFTWARE.
package com.microsoft.identity.common.java.nativeauth.commands.parameters;

import javax.annotation.Nullable;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.EqualsAndHashCode;
import lombok.Getter;
Expand All @@ -45,6 +47,12 @@ public class MFADefaultChallengeCommandParameters extends BaseSignInTokenCommand
@NonNull
public final String continuationToken;

/**
* Claims to send to the token endpoint.
*/
@Nullable
public final String claimsRequestJson;

@NonNull
@Override
public String toUnsanitizedString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
// THE SOFTWARE.
package com.microsoft.identity.common.java.nativeauth.commands.parameters;

import javax.annotation.Nullable;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
Expand Down Expand Up @@ -49,6 +51,12 @@ public class MFASubmitChallengeCommandParameters extends BaseSignInTokenCommandP
@NonNull
public final String continuationToken;

/**
* Claims to send to the token endpoint.
*/
@Nullable
public final String claimsRequestJson;

@NonNull
@Override
public String toUnsanitizedString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ public class SignInStartCommandParameters extends BaseSignInTokenCommandParamete
@Nullable
public final char[] password;

/**
* Claims to send to the token endpoint.
*/
@Nullable
public final String claimsRequestJson;

@NonNull
@Override
public String toUnsanitizedString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
// THE SOFTWARE.
package com.microsoft.identity.common.java.nativeauth.commands.parameters;

import javax.annotation.Nullable;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
Expand Down Expand Up @@ -49,6 +51,12 @@ public class SignInSubmitCodeCommandParameters extends BaseSignInTokenCommandPar
@NonNull
public final String continuationToken;

/**
* Claims to send to the token endpoint.
*/
@Nullable
public final String claimsRequestJson;

@NonNull
@Override
public String toUnsanitizedString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
// THE SOFTWARE.
package com.microsoft.identity.common.java.nativeauth.commands.parameters;

import javax.annotation.Nullable;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.EqualsAndHashCode;
import lombok.Getter;
Expand Down Expand Up @@ -51,6 +53,12 @@ public class SignInSubmitPasswordCommandParameters extends BaseSignInTokenComman
@NonNull
public final String continuationToken;

/**
* Claims to send to the token endpoint.
*/
@Nullable
public final String claimsRequestJson;

@NonNull
@Override
public String toUnsanitizedString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ class NativeAuthRequestProvider(private val config: NativeAuthOAuth2Configuratio
clientId = config.clientId,
challengeType = config.challengeType,
requestUrl = signInTokenEndpoint,
headers = getRequestHeaders(commandParameters.getCorrelationId())
headers = getRequestHeaders(commandParameters.getCorrelationId()),
claimsRequestJson = commandParameters.claimsRequestJson
)
}

Expand Down Expand Up @@ -198,7 +199,8 @@ class NativeAuthRequestProvider(private val config: NativeAuthOAuth2Configuratio
clientId = config.clientId,
challengeType = config.challengeType,
requestUrl = signInTokenEndpoint,
headers = getRequestHeaders(commandParameters.getCorrelationId())
headers = getRequestHeaders(commandParameters.getCorrelationId()),
claimsRequestJson = commandParameters.claimsRequestJson
)
}
//endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ data class SignInTokenRequest private constructor(
scopes: List<String>? = null,
challengeType: String? = null,
requestUrl: String,
headers: Map<String, String?>
headers: Map<String, String?>,
claimsRequestJson: String?
): SignInTokenRequest {
// Check for empty Strings and empty Maps
ArgUtils.validateNonNullArg(oob, "oob")
Expand All @@ -74,7 +75,8 @@ data class SignInTokenRequest private constructor(
clientId = clientId,
grantType = NativeAuthConstants.GrantType.OOB,
challengeType = challengeType,
scope = scopes?.joinToString(" ")
scope = scopes?.joinToString(" "),
claimsRequestJson = claimsRequestJson
),
requestUrl = URL(requestUrl),
headers = headers,
Expand All @@ -96,7 +98,8 @@ data class SignInTokenRequest private constructor(
scopes: List<String>? = null,
challengeType: String? = null,
requestUrl: String,
headers: Map<String, String?>
headers: Map<String, String?>,
claimsRequestJson: String?
): SignInTokenRequest {
// Check for empty Strings and empty Maps
ArgUtils.validateNonNullArg(password, "password")
Expand All @@ -106,15 +109,15 @@ data class SignInTokenRequest private constructor(
ArgUtils.validateNonNullArg(requestUrl, "requestUrl")
ArgUtils.validateNonNullArg(headers, "headers")


return SignInTokenRequest(
parameters = NativeAuthRequestSignInTokenRequestParameters(
password = password,
continuationToken = continuationToken,
clientId = clientId,
grantType = NativeAuthConstants.GrantType.PASSWORD,
challengeType = challengeType,
scope = scopes?.joinToString(" ")
scope = scopes?.joinToString(" "),
claimsRequestJson = claimsRequestJson
),
requestUrl = URL(requestUrl),
headers = headers,
Expand Down Expand Up @@ -153,7 +156,8 @@ data class SignInTokenRequest private constructor(
username = username,
grantType = NativeAuthConstants.GrantType.CONTINUATION_TOKEN,
challengeType = challengeType,
scope = scopes?.joinToString(" ")
scope = scopes?.joinToString(" "),
claimsRequestJson = null
),
requestUrl = URL(requestUrl),
headers = headers
Expand All @@ -175,7 +179,8 @@ data class SignInTokenRequest private constructor(
@SerializedName("grant_type") val grantType: String,
@SerializedName("continuation_token") val continuationToken: String? = null,
@SerializedName("scope") val scope: String?,
@SerializedName("challenge_type") val challengeType: String?
@SerializedName("challenge_type") val challengeType: String?,
@SerializedName("claims") val claimsRequestJson: String?
) : NativeAuthRequestParameters() {
override fun toUnsanitizedString(): String = "NativeAuthRequestSignInTokenRequestParameters(nca=$nca, clientInfo=$clientInfo, clientId=$clientId, grantType=$grantType, scope=$scope, challengeType=$challengeType)"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpS
import com.microsoft.identity.common.java.exception.ClientException
import com.microsoft.identity.common.java.interfaces.PlatformComponents
import com.microsoft.identity.common.java.nativeauth.providers.requests.NativeAuthRequest.Companion.toJsonString
import com.microsoft.identity.common.java.nativeauth.providers.requests.signin.SignInTokenRequest
import com.microsoft.identity.common.nativeauth.ApiConstants
import io.mockk.every
import io.mockk.mockk
Expand Down Expand Up @@ -778,6 +779,69 @@ class NativeAuthRequestProviderTest {
)
}

@Test
fun testSignInTokenOOBShouldContainsCorrectParams() {
val commandParameters = SignInSubmitCodeCommandParameters.builder()
.platformComponents(mock<PlatformComponents>())
.continuationToken(continuationToken)
.correlationId(correlationId)
.code("code")
.claimsRequestJson("claims")
.build()

val request = nativeAuthRequestProvider.createOOBTokenRequest(
commandParameters = commandParameters
)
assertEquals(request.parameters.oob, commandParameters.code)
assertEquals(request.parameters.claimsRequestJson, commandParameters.claimsRequestJson)
assertEquals(request.parameters.continuationToken, commandParameters.continuationToken)
assertEquals(request.parameters.challengeType, mockConfig.challengeType)
assertNull(request.parameters.scope)
}

@Test
fun testSignInTokenPasswordShouldContainsCorrectParams() {
val commandParameters = SignInSubmitPasswordCommandParameters.builder()
.platformComponents(mock<PlatformComponents>())
.continuationToken(continuationToken)
.correlationId(correlationId)
.password("pwd".toCharArray())
.claimsRequestJson("claims")
.build()

val request = nativeAuthRequestProvider.createPasswordTokenRequest(
commandParameters
)
assertEquals(request.parameters.password, commandParameters.password)
assertEquals(request.parameters.claimsRequestJson, commandParameters.claimsRequestJson)
assertEquals(request.parameters.continuationToken, commandParameters.continuationToken)
assertEquals(request.parameters.challengeType, mockConfig.challengeType)
assertNull(request.parameters.scope)
}

@Test
fun testSignInTokenContinuationShouldContainsCorrectParams() {
val scopes = arrayListOf("OOB", "PASSWORD")
val headers = mapOf("key" to "value")
val request = SignInTokenRequest.createContinuationTokenRequest(
continuationToken,
clientId,
username,
scopes,
challengeType,
ApiConstants.MockApi.signInTokenRequestUrl.toString(),
headers
)
assertNull(request.parameters.password)
assertNull(request.parameters.claimsRequestJson)
assertEquals(request.parameters.scope, "OOB PASSWORD")
assertEquals(request.parameters.continuationToken, continuationToken)
assertEquals(request.parameters.challengeType, challengeType)
assertEquals(request.parameters.username, username)
assertEquals(request.parameters.clientId, clientId)
assertEquals(request.headers, headers)
}

@Test(expected = ClientException::class)
fun testPasswordTokenRequestWithEmptyPasswordShouldThrowException() {
val commandParameters = SignInSubmitPasswordCommandParameters.builder()
Expand Down
Loading