diff --git a/changelog.txt b/changelog.txt index 998bd82527..f34d25f861 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,7 @@ vNext - [MAJOR] Update proguard rules in common (#2756) - [MINOR] Add query parameter for Android Release OS Version (#2754) - [MINOR] Add client scenario to JwtRequestBody (#2755) +- [MINOR] Awaiting MFA Delegate now automatically returns the AuthMethods to be used when calling MFA Challenge (#2764) Version 22.1.0 ---------- diff --git a/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/commands/GetAuthMethodsCommand.kt b/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/commands/GetAuthMethodsCommand.kt deleted file mode 100644 index 375aecb9c5..0000000000 --- a/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/commands/GetAuthMethodsCommand.kt +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// All rights reserved. -// -// This code is licensed under the MIT License. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -package com.microsoft.identity.common.nativeauth.internal.commands - -import com.microsoft.identity.common.java.logging.LogSession -import com.microsoft.identity.common.java.logging.Logger -import com.microsoft.identity.common.java.nativeauth.commands.parameters.GetAuthMethodsCommandParameters -import com.microsoft.identity.common.java.nativeauth.controllers.results.GetAuthMethodsCommandResult -import com.microsoft.identity.common.java.nativeauth.controllers.results.MFACommandResult -import com.microsoft.identity.common.nativeauth.internal.controllers.NativeAuthMsalController - -/** - * Command class to call controllers to trigger /introspect flow. - * {@see com.microsoft.identity.common.java.controllers.CommandDispatcher}. - */ -class GetAuthMethodsCommand( - private val parameters: GetAuthMethodsCommandParameters, - private val controller: NativeAuthMsalController, - publicApiId: String -) : BaseNativeAuthCommand( - parameters, - controller, - publicApiId -) { - - companion object { - private val TAG = GetAuthMethodsCommand::class.java.simpleName - } - - /** - * The execution part of the command, to be run on the background thread. - * It calls the getAuthMethods method of the native auth MSAL controller with the given parameters. - */ - override fun execute(): GetAuthMethodsCommandResult { - LogSession.logMethodCall( - tag = TAG, - correlationId = parameters.getCorrelationId(), - methodName = "${TAG}.execute" - ) - val result = controller.getAuthMethods( - parameters = parameters - ) - - Logger.infoWithObject( - TAG, - parameters.getCorrelationId(), - "Returning result: ", - result - ) - return result - } -} diff --git a/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/commands/MFAChallengeCommand.kt b/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/commands/MFAChallengeCommand.kt index 8fb1b5666c..cb1df3d87b 100644 --- a/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/commands/MFAChallengeCommand.kt +++ b/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/commands/MFAChallengeCommand.kt @@ -24,7 +24,7 @@ package com.microsoft.identity.common.nativeauth.internal.commands import com.microsoft.identity.common.java.logging.LogSession import com.microsoft.identity.common.java.logging.Logger -import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFADefaultChallengeCommandParameters +import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFAChallengeAuthMethodCommandParameters import com.microsoft.identity.common.java.nativeauth.controllers.results.MFAChallengeCommandResult import com.microsoft.identity.common.nativeauth.internal.controllers.NativeAuthMsalController @@ -33,7 +33,7 @@ import com.microsoft.identity.common.nativeauth.internal.controllers.NativeAuthM * {@see com.microsoft.identity.common.java.controllers.CommandDispatcher}. */ class MFAChallengeCommand( - private val parameters: MFADefaultChallengeCommandParameters, + private val parameters: MFAChallengeAuthMethodCommandParameters, private val controller: NativeAuthMsalController, publicApiId: String ) : BaseNativeAuthCommand( diff --git a/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/controllers/NativeAuthMsalController.kt b/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/controllers/NativeAuthMsalController.kt index d0e093c1da..475bcac368 100644 --- a/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/controllers/NativeAuthMsalController.kt +++ b/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/controllers/NativeAuthMsalController.kt @@ -42,11 +42,9 @@ import com.microsoft.identity.common.java.logging.LogSession import com.microsoft.identity.common.java.logging.Logger import com.microsoft.identity.common.java.nativeauth.commands.parameters.BaseNativeAuthCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.BaseSignInTokenCommandParameters -import com.microsoft.identity.common.java.nativeauth.commands.parameters.GetAuthMethodsCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.JITChallengeAuthMethodCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.JITContinueCommandParameters -import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFADefaultChallengeCommandParameters -import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFASelectedDefaultChallengeCommandParameters +import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFAChallengeAuthMethodCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFASubmitChallengeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordResendCodeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordStartCommandParameters @@ -62,7 +60,6 @@ import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpS import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpSubmitCodeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpSubmitPasswordCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpSubmitUserAttributesCommandParameters -import com.microsoft.identity.common.java.nativeauth.controllers.results.GetAuthMethodsCommandResult import com.microsoft.identity.common.java.nativeauth.controllers.results.INativeAuthCommandResult import com.microsoft.identity.common.java.nativeauth.controllers.results.JITChallengeAuthMethodCommandResult import com.microsoft.identity.common.java.nativeauth.controllers.results.JITCommandResult @@ -405,6 +402,7 @@ class NativeAuthMsalController : BaseNativeAuthController() { } is SignInTokenApiResult.UnknownError, is SignInTokenApiResult.InvalidAuthenticationType, is SignInTokenApiResult.InvalidCredentials, is SignInTokenApiResult.UserNotFound, + // This will change once SMS MFA is supported is SignInTokenApiResult.MFARequired, is SignInTokenApiResult.JITRequired -> { Logger.warnWithObject( TAG, @@ -445,7 +443,7 @@ class NativeAuthMsalController : BaseNativeAuthController() { try { val oAuth2Strategy = createOAuth2Strategy(parameters) - val result = performSignInDefaultChallengeCall( + val result = performSignInChallengeCall( oAuth2Strategy = oAuth2Strategy, continuationToken = parameters.continuationToken, correlationId = parameters.correlationId @@ -479,7 +477,7 @@ class NativeAuthMsalController : BaseNativeAuthController() { redirectReason = result.redirectReason ) } - is SignInChallengeApiResult.IntrospectRequired, is SignInChallengeApiResult.UnknownError -> { + is SignInChallengeApiResult.UnknownError -> { Logger.warnWithObject( TAG, "Unexpected result: ", @@ -548,7 +546,7 @@ class NativeAuthMsalController : BaseNativeAuthController() { } } - fun signInChallenge(parameters: MFADefaultChallengeCommandParameters): MFAChallengeCommandResult { + fun signInChallenge(parameters: MFAChallengeAuthMethodCommandParameters): MFAChallengeCommandResult { LogSession.logMethodCall( tag = TAG, correlationId = parameters.getCorrelationId(), @@ -558,30 +556,13 @@ class NativeAuthMsalController : BaseNativeAuthController() { try { val oAuth2Strategy = createOAuth2Strategy(parameters) - val isSelectedChallenge = (parameters is MFASelectedDefaultChallengeCommandParameters) - - val result = if (isSelectedChallenge) { - performSignInSelectedChallengeCall( + val result = performSignInSelectedAuthMethodCall( oAuth2Strategy = oAuth2Strategy, continuationToken = parameters.continuationToken, correlationId = parameters.correlationId, - challengeId = (parameters as MFASelectedDefaultChallengeCommandParameters).authMethodId + authMethodId = parameters.authMethodId ) - } else { - performSignInDefaultChallengeCall( - oAuth2Strategy = oAuth2Strategy, - continuationToken = parameters.continuationToken, - correlationId = parameters.correlationId - ) - } return when (result) { - is SignInChallengeApiResult.IntrospectRequired -> { - return performIntrospectCall( - oAuth2Strategy = oAuth2Strategy, - continuationToken = parameters.continuationToken, - correlationId = parameters.correlationId - ).toMFAChallengeCommandResult() - } is SignInChallengeApiResult.OOBRequired -> { MFACommandResult.VerificationRequired( correlationId = result.correlationId, @@ -635,60 +616,6 @@ class NativeAuthMsalController : BaseNativeAuthController() { } } - fun getAuthMethods(parameters: GetAuthMethodsCommandParameters): GetAuthMethodsCommandResult { - LogSession.logMethodCall( - tag = TAG, - correlationId = parameters.getCorrelationId(), - methodName = "${TAG}.getAuthMethods()" - ) - - try { - val oAuth2Strategy = createOAuth2Strategy(parameters) - - val result = performIntrospectCall( - oAuth2Strategy = oAuth2Strategy, - continuationToken = parameters.continuationToken, - correlationId = parameters.correlationId - ) - return when (result) { - is SignInIntrospectApiResult.Success -> { - MFACommandResult.SelectionRequired( - correlationId = result.correlationId, - continuationToken = result.continuationToken, - authMethods = result.methods - ) - } - is SignInIntrospectApiResult.Redirect -> { - INativeAuthCommandResult.Redirect( - correlationId = result.correlationId, - redirectReason = result.redirectReason - ) - } - is SignInIntrospectApiResult.UnknownError -> { - Logger.warnWithObject( - TAG, - "Unexpected result: ", - result - ) - INativeAuthCommandResult.APIError( - error = result.error, - errorDescription = result.errorDescription, - errorCodes = result.errorCodes, - correlationId = result.correlationId - ) - } - } - } catch (e: Exception) { - Logger.error( - TAG, - parameters.correlationId, - "Exception thrown in getAuthMethods()", - e - ) - throw e - } - } - /** * Send the challenge to the authentication method in order to register it as strong authentication method (JIT). */ @@ -789,9 +716,9 @@ class NativeAuthMsalController : BaseNativeAuthController() { val oAuth2Strategy = createOAuth2Strategy(parameters) val signUpStartApiResult = performSignUpStartUsingPasswordRequest( - oAuth2Strategy = oAuth2Strategy, - parameters - ) + oAuth2Strategy = oAuth2Strategy, + parameters + ) return when (signUpStartApiResult) { is SignUpStartApiResult.Success -> { performSignUpChallengeCall( @@ -1723,7 +1650,10 @@ class NativeAuthMsalController : BaseNativeAuthController() { ) } - private fun performSignInDefaultChallengeCall( + + + + private fun performSignInChallengeCall( oAuth2Strategy: NativeAuthOAuth2Strategy, continuationToken: String, correlationId: String @@ -1739,21 +1669,21 @@ class NativeAuthMsalController : BaseNativeAuthController() { ) } - private fun performSignInSelectedChallengeCall( + private fun performSignInSelectedAuthMethodCall( oAuth2Strategy: NativeAuthOAuth2Strategy, continuationToken: String, correlationId: String, - challengeId: String + authMethodId: String ): SignInChallengeApiResult { LogSession.logMethodCall( tag = TAG, correlationId = correlationId, - methodName = "${TAG}.performSignInSelectedChallengeCall" + methodName = "${TAG}.performSignInSelectedAuthMethodCall" ) return oAuth2Strategy.performSignInSelectedChallenge( continuationToken = continuationToken, correlationId = correlationId, - challengeId = challengeId + challengeId = authMethodId ) } @@ -2409,6 +2339,37 @@ class NativeAuthMsalController : BaseNativeAuthController() { } } + private fun SignInIntrospectApiResult.toSignInStartCommandResult(): SignInStartCommandResult { + return when (this) { + is SignInIntrospectApiResult.Success -> { + SignInCommandResult.MFARequired( + correlationId = this.correlationId, + continuationToken = this.continuationToken, + authMethods = this.methods + ) + } + is SignInIntrospectApiResult.Redirect -> { + INativeAuthCommandResult.Redirect( + correlationId = this.correlationId, + redirectReason = this.redirectReason + ) + } + is SignInIntrospectApiResult.UnknownError -> { + Logger.warnWithObject( + com.microsoft.identity.common.nativeauth.internal.controllers.NativeAuthMsalController.TAG, + "Unexpected result: ", + this + ) + INativeAuthCommandResult.APIError( + error = this.error, + errorDescription = this.errorDescription, + errorCodes = this.errorCodes, + correlationId = this.correlationId + ) + } + } + } + private fun JITIntrospectApiResult.toSignInStartCommandResult(): SignInStartCommandResult { return when (this) { is JITIntrospectApiResult.Success -> { @@ -2461,14 +2422,12 @@ class NativeAuthMsalController : BaseNativeAuthController() { ) } is SignInTokenApiResult.MFARequired -> { - SignInCommandResult.MFARequired( - error = this.error, - errorDescription = this.errorDescription, + // when MFA is required, we retrieve the list of auth methods available + performIntrospectCall( + oAuth2Strategy = oAuth2Strategy, continuationToken = this.continuationToken, - subError = this.subError, - errorCodes = this.errorCodes, correlationId = this.correlationId - ) + ).toSignInStartCommandResult() } is SignInTokenApiResult.JITRequired -> { // when a registration of a new strong authentication method is required, we retrieve the list of auth methods available @@ -2526,14 +2485,12 @@ class NativeAuthMsalController : BaseNativeAuthController() { ) } is SignInTokenApiResult.MFARequired -> { - SignInCommandResult.MFARequired( - error = this.error, - errorDescription = this.errorDescription, + // when MFA is required, we retrieve the list of auth methods available + performIntrospectCall( + oAuth2Strategy = oAuth2Strategy, continuationToken = this.continuationToken, - subError = this.subError, - errorCodes = this.errorCodes, correlationId = this.correlationId - ) + ).toSignInStartCommandResult() as SignInSubmitPasswordCommandResult } is SignInTokenApiResult.JITRequired -> { // when a registration of a new strong authentication method is required, we retrieve the list of auth methods available @@ -2569,38 +2526,6 @@ class NativeAuthMsalController : BaseNativeAuthController() { } } - private fun SignInIntrospectApiResult.toMFAChallengeCommandResult(): MFAChallengeCommandResult { - return when (this) { - is SignInIntrospectApiResult.Redirect -> { - INativeAuthCommandResult.Redirect( - correlationId = this.correlationId, - redirectReason = this.redirectReason - ) - } - is SignInIntrospectApiResult.Success -> { - MFACommandResult.SelectionRequired( - correlationId = this.correlationId, - continuationToken = this.continuationToken, - authMethods = this.methods - ) - } - is SignInIntrospectApiResult.UnknownError -> { - Logger.warnWithObject( - TAG, - this.correlationId, - "Unexpected result: ", - this - ) - INativeAuthCommandResult.APIError( - error = this.error, - errorDescription = this.errorDescription, - errorCodes = this.errorCodes, - correlationId = this.correlationId - ) - } - } - } - @VisibleForTesting fun processSignInInitiateApiResult( initiateApiResult: SignInInitiateApiResult, @@ -2616,7 +2541,7 @@ class NativeAuthMsalController : BaseNativeAuthController() { ) } is SignInInitiateApiResult.Success -> { - val signInChallengeResult = performSignInDefaultChallengeCall( + val signInChallengeResult = performSignInChallengeCall( oAuth2Strategy = oAuth2Strategy, continuationToken = initiateApiResult.continuationToken, correlationId = initiateApiResult.correlationId @@ -2707,14 +2632,6 @@ class NativeAuthMsalController : BaseNativeAuthController() { redirectReason = result.redirectReason ) } - is SignInChallengeApiResult.IntrospectRequired -> { - INativeAuthCommandResult.APIError( - error = result.error, - errorDescription = result.errorDescription, - errorCodes = result.errorCodes, - correlationId = result.correlationId - ) - } is SignInChallengeApiResult.UnknownError -> { Logger.warnWithObject( TAG, @@ -2743,4 +2660,4 @@ class NativeAuthMsalController : BaseNativeAuthController() { .authority .createOAuth2Strategy(strategyParameters) } -} +} \ No newline at end of file diff --git a/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/util/CommandUtil.java b/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/util/CommandUtil.java index 43daf0bacf..4a149427b3 100644 --- a/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/util/CommandUtil.java +++ b/common/src/main/java/com/microsoft/identity/common/nativeauth/internal/util/CommandUtil.java @@ -94,12 +94,13 @@ public static SignInSubmitCodeCommandParameters createSignInSubmitCodeCommandPar return parameters.toBuilder() .scopes(defaultScopes) .correlationId(parameters.getCorrelationId()) + .isMFAGrantType(parameters.getIsMFAGrantType()) .build(); } /** * Adds scopes to [SignInSubmitPasswordCommandParameters] object and returns a new - * [SignInSubmitCodeCommandParameters] object. + * [SignInSubmitPasswordCommandParameters] object. * @param parameters input command parameter * @param correlationId correlationId to be used in the request * @param defaultScopes scopes to be added @@ -306,6 +307,7 @@ public static SignInSubmitCodeCommandParameters createSignInSubmitCodeCommandPar .correlationId(parameters.getCorrelationId()) .challengeType(parameters.getChallengeType()) .claimsRequestJson(parameters.claimsRequestJson) + .isMFAGrantType(true) .build(); return commandParameters; diff --git a/common/src/test/java/com/microsoft/identity/common/internal/providers/microsoft/nativeauth/integration/SignInOAuthStrategyTest.kt b/common/src/test/java/com/microsoft/identity/common/internal/providers/microsoft/nativeauth/integration/SignInOAuthStrategyTest.kt index 463765dcb2..27e2015cb6 100644 --- a/common/src/test/java/com/microsoft/identity/common/internal/providers/microsoft/nativeauth/integration/SignInOAuthStrategyTest.kt +++ b/common/src/test/java/com/microsoft/identity/common/internal/providers/microsoft/nativeauth/integration/SignInOAuthStrategyTest.kt @@ -23,14 +23,12 @@ package com.microsoft.identity.common.internal.providers.microsoft.nativeauth.integration import android.os.Build -import com.microsoft.identity.common.nativeauth.ApiConstants +import com.microsoft.identity.common.java.interfaces.PlatformComponents +import com.microsoft.identity.common.java.logging.DiagnosticContext import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInStartCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInSubmitCodeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInSubmitPasswordCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInWithContinuationTokenCommandParameters -import com.microsoft.identity.common.java.interfaces.PlatformComponents -import com.microsoft.identity.common.java.logging.DiagnosticContext -import com.microsoft.identity.common.java.net.UrlConnectionHttpClient import com.microsoft.identity.common.java.nativeauth.providers.NativeAuthOAuth2Configuration import com.microsoft.identity.common.java.nativeauth.providers.NativeAuthOAuth2Strategy import com.microsoft.identity.common.java.nativeauth.providers.NativeAuthRequestProvider @@ -43,7 +41,9 @@ import com.microsoft.identity.common.java.nativeauth.providers.responses.signin. import com.microsoft.identity.common.java.nativeauth.providers.responses.signin.SignInInitiateApiResult import com.microsoft.identity.common.java.nativeauth.providers.responses.signin.SignInIntrospectApiResult import com.microsoft.identity.common.java.nativeauth.providers.responses.signin.SignInTokenApiResult +import com.microsoft.identity.common.java.net.UrlConnectionHttpClient import com.microsoft.identity.common.java.providers.oauth2.OAuth2StrategyParameters +import com.microsoft.identity.common.nativeauth.ApiConstants import com.microsoft.identity.common.nativeauth.MockApiEndpoint import com.microsoft.identity.common.nativeauth.MockApiResponseType import com.microsoft.identity.common.nativeauth.MockApiUtils @@ -220,6 +220,7 @@ class SignInOAuthStrategyTest { every { parameters.getCode() } returns OOB every { parameters.getContinuationToken() } returns CONTINUATION_TOKEN every { parameters.correlationId } returns correlationId + every { parameters.getIsMFAGrantType() } returns false val signInChallengeResult = nativeAuthOAuth2Strategy.performOOBTokenRequest( parameters = parameters @@ -243,6 +244,7 @@ class SignInOAuthStrategyTest { every { parameters.getCode() } returns OOB every { parameters.getContinuationToken() } returns CONTINUATION_TOKEN every { parameters.correlationId } returns correlationId + every { parameters.getIsMFAGrantType() } returns false val signInChallengeResult = nativeAuthOAuth2Strategy.performOOBTokenRequest( parameters = parameters @@ -344,22 +346,6 @@ class SignInOAuthStrategyTest { Assert.assertTrue(signInChallengeResult is SignInChallengeApiResult.PasswordRequired) } - @Test - fun testPerformSignInDefaultChallengeWithIntrospectRequired() { - val correlationId = UUID.randomUUID().toString() - - MockApiUtils.configureMockApi( - endpointType = MockApiEndpoint.SignInChallenge, - correlationId = correlationId, - responseType = MockApiResponseType.INTROSPECT_REQUIRED - ) - val signInChallengeResult = nativeAuthOAuth2Strategy.performSignInDefaultChallenge( - continuationToken = CONTINUATION_TOKEN, - correlationId = correlationId - ) - Assert.assertTrue(signInChallengeResult is SignInChallengeApiResult.IntrospectRequired) - } - @Test fun testPerformSignInDefaultChallengeWithRedirectSuccess() { val correlationId = UUID.randomUUID().toString() diff --git a/common/src/test/java/com/microsoft/identity/common/nativeauth/internal/controllers/NativeAuthControllerTest.kt b/common/src/test/java/com/microsoft/identity/common/nativeauth/internal/controllers/NativeAuthControllerTest.kt index 5a460bf5d8..bbbffaaf4e 100644 --- a/common/src/test/java/com/microsoft/identity/common/nativeauth/internal/controllers/NativeAuthControllerTest.kt +++ b/common/src/test/java/com/microsoft/identity/common/nativeauth/internal/controllers/NativeAuthControllerTest.kt @@ -36,10 +36,9 @@ import com.microsoft.identity.common.java.dto.AccountRecord import com.microsoft.identity.common.java.interfaces.IPlatformComponents import com.microsoft.identity.common.java.nativeauth.BuildValues import com.microsoft.identity.common.java.nativeauth.authorities.NativeAuthCIAMAuthority -import com.microsoft.identity.common.java.nativeauth.commands.parameters.GetAuthMethodsCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.JITChallengeAuthMethodCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.JITContinueCommandParameters -import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFADefaultChallengeCommandParameters +import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFAChallengeAuthMethodCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.MFASubmitChallengeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordResendCodeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordStartCommandParameters @@ -105,6 +104,7 @@ class NativeAuthControllerTest { private val newPassword = "newPassword".toCharArray() private val clientId = "079af063-4ea7-4dcd-91ff-2b24f54621ea" private val authorityUrl = "https://msidlabciam1.ciamlogin.com/msidlabciam1.onmicrosoft.com" + private val authMethodId = "590f21a2-34fe-43fb-becc-4442dd19ce5c" private val userAttributes = mapOf("city" to "dublin") private lateinit var platformComponents: IPlatformComponents @@ -538,41 +538,57 @@ class NativeAuthControllerTest { // region sign in MFA @Test - fun `testMFAChallenge challenge returns introspect_required and introspect returns success should return SelectionRequiredResult`() { + fun `testsignInWithPasswordReturnMFARequired`() { val correlationId = UUID.randomUUID().toString() MockApiUtils.configureMockApi( endpointType = MockApiEndpoint.SignInChallenge, correlationId = correlationId, - responseType = MockApiResponseType.INTROSPECT_REQUIRED + responseType = MockApiResponseType.CHALLENGE_TYPE_REDIRECT ) + + val parameters = createMFAChallengeCommandParameters(correlationId, authMethodId) + val result = controller.signInChallenge(parameters) + assert(result is INativeAuthCommandResult.Redirect) + } + + @Test + fun testSubmitPasswordReturnMFARequiredIntrospectRedirect_checkResult() { + val correlationId = UUID.randomUUID().toString() + MockApiUtils.configureMockApi( + endpointType = MockApiEndpoint.SignInToken, + correlationId = correlationId, + responseType = MockApiResponseType.MFA_REQUIRED + ) + MockApiUtils.configureMockApi( endpointType = MockApiEndpoint.Introspect, correlationId = correlationId, - responseType = MockApiResponseType.INTROSPECT_SUCCESS + responseType = MockApiResponseType.CHALLENGE_TYPE_REDIRECT ) - val parameters = createMFAChallengeCommandParameters(correlationId) - val result = controller.signInChallenge(parameters) - assert(result is MFACommandResult.SelectionRequired) + val signInParameters = createSignInSubmitPasswordCommandParameters(correlationId) + val signInResult = controller.signInSubmitPassword(signInParameters) + assert(signInResult is INativeAuthCommandResult.Redirect) } @Test - fun `testMFAChallenge challenge returns introspect_required and introspect returns redirect should return RedirectResult`() { + fun testSubmitPasswordReturnMFARequiredIntrospectSuccess_checkAuthMethods() { val correlationId = UUID.randomUUID().toString() MockApiUtils.configureMockApi( - endpointType = MockApiEndpoint.SignInChallenge, + endpointType = MockApiEndpoint.SignInToken, correlationId = correlationId, - responseType = MockApiResponseType.INTROSPECT_REQUIRED + responseType = MockApiResponseType.MFA_REQUIRED ) + MockApiUtils.configureMockApi( endpointType = MockApiEndpoint.Introspect, correlationId = correlationId, - responseType = MockApiResponseType.CHALLENGE_TYPE_REDIRECT + responseType = MockApiResponseType.INTROSPECT_SUCCESS ) - val parameters = createMFAChallengeCommandParameters(correlationId) - val result = controller.signInChallenge(parameters) - assert(result is INativeAuthCommandResult.Redirect) + val signInParameters = createSignInSubmitPasswordCommandParameters(correlationId) + val signInResult = controller.signInSubmitPassword(signInParameters) as SignInCommandResult.MFARequired + assert(signInResult.authMethods.filter { it.challengeChannel == "email" }.count() == 1) } @Test @@ -584,7 +600,7 @@ class NativeAuthControllerTest { responseType = MockApiResponseType.CHALLENGE_TYPE_REDIRECT ) - val parameters = createMFAChallengeCommandParameters(correlationId) + val parameters = createMFAChallengeCommandParameters(correlationId, authMethodId) val result = controller.signInChallenge(parameters) assert(result is INativeAuthCommandResult.Redirect) } @@ -598,7 +614,7 @@ class NativeAuthControllerTest { responseType = MockApiResponseType.CHALLENGE_TYPE_OOB ) - val parameters = createMFAChallengeCommandParameters(correlationId) + val parameters = createMFAChallengeCommandParameters(correlationId, authMethodId) val result = controller.signInChallenge(parameters) assert(result is MFACommandResult.VerificationRequired) } @@ -612,27 +628,22 @@ class NativeAuthControllerTest { responseType = MockApiResponseType.CHALLENGE_TYPE_PASSWORD ) - val parameters = createMFAChallengeCommandParameters(correlationId) + val parameters = createMFAChallengeCommandParameters(correlationId, authMethodId) val result = controller.signInChallenge(parameters) assert(result is INativeAuthCommandResult.APIError) } @Test - fun testMFAChallengeWithInvalidIntrospectResponseShouldReturnAPIError() { + fun testMFAChallengeExpiredTokenShouldReturnAPIError() { val correlationId = UUID.randomUUID().toString() MockApiUtils.configureMockApi( endpointType = MockApiEndpoint.SignInChallenge, correlationId = correlationId, - responseType = MockApiResponseType.INTROSPECT_REQUIRED - ) - MockApiUtils.configureMockApi( - endpointType = MockApiEndpoint.Introspect, - correlationId = correlationId, responseType = MockApiResponseType.EXPIRED_TOKEN ) - val parameters = createMFAChallengeCommandParameters(correlationId) + val parameters = createMFAChallengeCommandParameters(correlationId, authMethodId) val result = controller.signInChallenge(parameters) assert(result is INativeAuthCommandResult.APIError) } @@ -692,48 +703,6 @@ class NativeAuthControllerTest { val result = controller.signInSubmitChallenge(parameters) assert(result is INativeAuthCommandResult.APIError) } - - @Test - fun testMFAGetAuthMethodsSuccess() { - val correlationId = UUID.randomUUID().toString() - MockApiUtils.configureMockApi( - endpointType = MockApiEndpoint.Introspect, - correlationId = correlationId, - responseType = MockApiResponseType.INTROSPECT_SUCCESS - ) - - val parameters = createGetAuthMethodsCommandParameters(correlationId) - val result = controller.getAuthMethods(parameters) - assert(result is MFACommandResult.SelectionRequired) - } - - @Test - fun testMFAGetAuthMethodsWithRedirectResponseShouldReturnRedirect() { - val correlationId = UUID.randomUUID().toString() - MockApiUtils.configureMockApi( - endpointType = MockApiEndpoint.Introspect, - correlationId = correlationId, - responseType = MockApiResponseType.CHALLENGE_TYPE_REDIRECT - ) - - val parameters = createGetAuthMethodsCommandParameters(correlationId) - val result = controller.getAuthMethods(parameters) - assert(result is INativeAuthCommandResult.Redirect) - } - - @Test - fun testMFAGetAuthMethodsWithInvalidResponseShouldReturnAPIError() { - val correlationId = UUID.randomUUID().toString() - MockApiUtils.configureMockApi( - endpointType = MockApiEndpoint.Introspect, - correlationId = correlationId, - responseType = MockApiResponseType.EXPIRED_TOKEN - ) - - val parameters = createGetAuthMethodsCommandParameters(correlationId) - val result = controller.getAuthMethods(parameters) - assert(result is INativeAuthCommandResult.APIError) - } // endregion // region Sign out @@ -1637,7 +1606,7 @@ class NativeAuthControllerTest { .build() } - private fun createSignInSubmitCodeCommandParameters(correlationId: String): SignInSubmitCodeCommandParameters { + private fun createSignInSubmitCodeCommandParameters(correlationId: String, isMFAGrantYpe: Boolean = false): SignInSubmitCodeCommandParameters { val authenticationScheme = AuthenticationSchemeFactory.createScheme( AndroidPlatformComponentsFactory.createFromContext(context), null @@ -1653,6 +1622,7 @@ class NativeAuthControllerTest { .oAuth2TokenCache(createCache()) .sdkType(SdkType.MSAL) .correlationId(correlationId) + .isMFAGrantType(isMFAGrantYpe) .requiredBrokerProtocolVersion(BrokerProtocolVersionUtil.MSAL_TO_BROKER_PROTOCOL_COMPRESSION_CHANGES_MINIMUM_VERSION) .build() } @@ -1692,14 +1662,15 @@ class NativeAuthControllerTest { } private fun createMFAChallengeCommandParameters( - correlationId: String - ): MFADefaultChallengeCommandParameters { + correlationId: String, + authMethodId: String + ): MFAChallengeAuthMethodCommandParameters { val authenticationScheme = AuthenticationSchemeFactory.createScheme( AndroidPlatformComponentsFactory.createFromContext(context), null ) - return MFADefaultChallengeCommandParameters.builder() + return MFAChallengeAuthMethodCommandParameters.builder() .clientId(clientId) .oAuth2TokenCache(createCache()) .requiredBrokerProtocolVersion(BrokerProtocolVersionUtil.MSAL_TO_BROKER_PROTOCOL_COMPRESSION_CHANGES_MINIMUM_VERSION) @@ -1710,6 +1681,7 @@ class NativeAuthControllerTest { .platformComponents(platformComponents) .scopes(scopes) .correlationId(correlationId) + .authMethodId(authMethodId) .build(); } @@ -1736,26 +1708,6 @@ class NativeAuthControllerTest { .build(); } - private fun createGetAuthMethodsCommandParameters( - correlationId: String, - ): GetAuthMethodsCommandParameters { - val authenticationScheme = AuthenticationSchemeFactory.createScheme( - AndroidPlatformComponentsFactory.createFromContext(context), - null - ) - - return GetAuthMethodsCommandParameters.builder() - .clientId(clientId) - .oAuth2TokenCache(createCache()) - .requiredBrokerProtocolVersion(BrokerProtocolVersionUtil.MSAL_TO_BROKER_PROTOCOL_COMPRESSION_CHANGES_MINIMUM_VERSION) - .sdkType(SdkType.MSAL) - .authority(NativeAuthCIAMAuthority.getAuthorityFromAuthorityUrl(authorityUrl, clientId)) - .continuationToken(continuationToken) - .platformComponents(platformComponents) - .correlationId(correlationId) - .build(); - } - private fun createSsprStartCommandParameters(correlationId: String): ResetPasswordStartCommandParameters { return ResetPasswordStartCommandParameters.builder() .username(username) diff --git a/common/src/test/java/com/microsoft/identity/common/nativeauth/internal/util/CommandUtilTest.kt b/common/src/test/java/com/microsoft/identity/common/nativeauth/internal/util/CommandUtilTest.kt index 9106ae07bf..8df9573c8f 100644 --- a/common/src/test/java/com/microsoft/identity/common/nativeauth/internal/util/CommandUtilTest.kt +++ b/common/src/test/java/com/microsoft/identity/common/nativeauth/internal/util/CommandUtilTest.kt @@ -6,6 +6,8 @@ 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 com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInSubmitCodeCommandParameters +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -56,7 +58,7 @@ class CommandUtilTest { } @Test - fun testCreateSignInSubmitCodeCommandParameters_containsCorrectInfo() { + fun testCreateSignInSubmitCodeFromMFACommandParameters_containsCorrectInfo() { val mfaSubmitChallengeParams = MFASubmitChallengeCommandParameters.builder() .claimsRequestJson("claimsRequestJson") .clientId("clientId") @@ -76,5 +78,34 @@ class CommandUtilTest { assert(submitCodeParams.getChallengeType()?.equals(mfaSubmitChallengeParams.getChallengeType()) == true) assert(submitCodeParams.getCode() == mfaSubmitChallengeParams.getChallenge()) assert(submitCodeParams.redirectUri?.equals(mfaSubmitChallengeParams.redirectUri) == true) + assertTrue(submitCodeParams.getIsMFAGrantType()) } + + @Test + fun testCreateSignInSubmitCodeWithScopesCommandParameters_containsCorrectInfo() { + val signInSubmitCodeCommandParameters = SignInSubmitCodeCommandParameters.builder() + .claimsRequestJson("claimsRequestJson") + .clientId("clientId") + .challengeType(arrayListOf("OOB")) + .redirectUri("redirectUri") + .platformComponents(platformComponents) + .continuationToken("continuationToken") + .correlationId(UUID.randomUUID().toString()) + .isMFAGrantType(false) + .code("123456") + .build() + val scopes = listOf("email", "profile") + val submitCodeParams = CommandUtil.createSignInSubmitCodeCommandParametersWithScopes(signInSubmitCodeCommandParameters, scopes) + + assert(submitCodeParams.getContinuationToken().contentEquals(signInSubmitCodeCommandParameters.getContinuationToken())) + assert(submitCodeParams.correlationId?.contentEquals(signInSubmitCodeCommandParameters.correlationId) == true) + assert(submitCodeParams.getClaimsRequestJson().contentEquals(signInSubmitCodeCommandParameters.getClaimsRequestJson())) + assert(submitCodeParams.clientId?.contentEquals(signInSubmitCodeCommandParameters.clientId) == true) + assert(submitCodeParams.getChallengeType()?.equals(signInSubmitCodeCommandParameters.getChallengeType()) == true) + assert(submitCodeParams.redirectUri?.equals(signInSubmitCodeCommandParameters.redirectUri) == true) + assert(submitCodeParams.isMFAGrantType == signInSubmitCodeCommandParameters.getIsMFAGrantType()) + assert(submitCodeParams.scopes.equals(scopes)) + assert(submitCodeParams.getCode() == signInSubmitCodeCommandParameters.getCode()) + } + } \ No newline at end of file diff --git a/common4j/src/main/com/microsoft/identity/common/java/eststelemetry/PublicApiId.java b/common4j/src/main/com/microsoft/identity/common/java/eststelemetry/PublicApiId.java index ef862f3284..d3bb0ed47e 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/eststelemetry/PublicApiId.java +++ b/common4j/src/main/com/microsoft/identity/common/java/eststelemetry/PublicApiId.java @@ -159,8 +159,6 @@ public final class PublicApiId { public static final String NATIVE_AUTH_SIGN_UP_SUBMIT_CODE = "235"; public static final String NATIVE_AUTH_ACCOUNT_SIGN_OUT = "240"; public static final String NATIVE_AUTH_ACCOUNT_GET_ACCESS_TOKEN = "250"; - public static final String NATIVE_AUTH_MFA_DEFAULT_CHALLENGE = "251"; - public static final String NATIVE_AUTH_GET_AUTH_METHODS = "252"; public static final String NATIVE_AUTH_MFA_SELECTED_CHALLENGE = "253"; public static final String NATIVE_AUTH_MFA_SUBMIT_CHALLENGE = "254"; public static final String NATIVE_AUTH_JIT_CHALLENGE_AUTH_METHOD = "255"; diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/GetAuthMethodsCommandParameters.java b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/GetAuthMethodsCommandParameters.java deleted file mode 100644 index 686561b6e7..0000000000 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/GetAuthMethodsCommandParameters.java +++ /dev/null @@ -1,64 +0,0 @@ -//Copyright (c) Microsoft Corporation. -//All rights reserved. -// -//This code is licensed under the MIT License. -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files(the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions : -// -//The above copyright notice and this permission notice shall be included in -//all copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -//THE SOFTWARE. -package com.microsoft.identity.common.java.nativeauth.commands.parameters; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NonNull; -import lombok.experimental.SuperBuilder; - -/** - * CommandParameters for calling /introspect as part of MFA flows. - * extends from {@link BaseSignInTokenCommandParameters} - */ -@Getter -@EqualsAndHashCode(callSuper = true) -@SuppressFBWarnings("EI_EXPOSE_REP2") //Suppresses spotbugs warning on the builder class -@SuperBuilder(toBuilder = true) -public class GetAuthMethodsCommandParameters extends BaseNativeAuthCommandParameters { - private static final String TAG = GetAuthMethodsCommandParameters.class.getSimpleName(); - - /** - * The continuation token obtained from the previous API call. - */ - @NonNull - public final String continuationToken; - - @NonNull - @Override - public String toUnsanitizedString() { - return "GetAuthMethodsCommandParameters(authority=" + authority + ", challengeType=" + challengeType + ")"; - } - - @Override - public boolean containsPii() { - return !toString().equals(toUnsanitizedString()); - } - - @NonNull - @Override - public String toString() { - return toUnsanitizedString(); - } -} diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/MFADefaultChallengeCommandParameters.java b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/MFAChallengeAuthMethodCommandParameters.java similarity index 78% rename from common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/MFADefaultChallengeCommandParameters.java rename to common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/MFAChallengeAuthMethodCommandParameters.java index 5d4f3c4b74..ceb86c7e41 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/MFADefaultChallengeCommandParameters.java +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/MFAChallengeAuthMethodCommandParameters.java @@ -22,8 +22,6 @@ //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; @@ -31,15 +29,15 @@ import lombok.experimental.SuperBuilder; /** - * CommandParameters for calling /challenge as part of MFA flows. + * CommandParameters for calling /challenge with auth method ID as part of MFA flows. * extends from {@link BaseSignInTokenCommandParameters} */ @Getter @EqualsAndHashCode(callSuper = true) @SuppressFBWarnings("EI_EXPOSE_REP2") //Suppresses spotbugs warning on the builder class @SuperBuilder(toBuilder = true) -public class MFADefaultChallengeCommandParameters extends BaseSignInTokenCommandParameters { - private static final String TAG = MFADefaultChallengeCommandParameters.class.getSimpleName(); +public class MFAChallengeAuthMethodCommandParameters extends BaseSignInTokenCommandParameters { + private static final String TAG = MFAChallengeAuthMethodCommandParameters.class.getSimpleName(); /** * The continuation token obtained from the token endpoint. @@ -47,10 +45,17 @@ public class MFADefaultChallengeCommandParameters extends BaseSignInTokenCommand @NonNull public final String continuationToken; + + /** + * The ID of the auth method that should be challenged. + */ + @NonNull + public final String authMethodId; + @NonNull @Override public String toUnsanitizedString() { - return "MFADefaultChallengeCommandParameters(authority=" + authority + ", challengeType=" + challengeType + ")"; + return "MFAChallengeAuthMethodCommandParameters(authority=" + authority + ", challengeType=" + challengeType + ", authMethodId=" + authMethodId + ")"; } @Override diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/MFASelectedDefaultChallengeCommandParameters.java b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/MFASelectedDefaultChallengeCommandParameters.java deleted file mode 100644 index 634eab77ed..0000000000 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/MFASelectedDefaultChallengeCommandParameters.java +++ /dev/null @@ -1,64 +0,0 @@ -//Copyright (c) Microsoft Corporation. -//All rights reserved. -// -//This code is licensed under the MIT License. -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files(the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions : -// -//The above copyright notice and this permission notice shall be included in -//all copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -//THE SOFTWARE. -package com.microsoft.identity.common.java.nativeauth.commands.parameters; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NonNull; -import lombok.experimental.SuperBuilder; - -/** - * CommandParameters for calling /challenge as part of MFA flows. - * extends from {@link BaseSignInTokenCommandParameters} - */ -@Getter -@EqualsAndHashCode(callSuper = true) -@SuppressFBWarnings("EI_EXPOSE_REP2") //Suppresses spotbugs warning on the builder class -@SuperBuilder(toBuilder = true) -public class MFASelectedDefaultChallengeCommandParameters extends MFADefaultChallengeCommandParameters { - private static final String TAG = MFASelectedDefaultChallengeCommandParameters.class.getSimpleName(); - - /** - * The ID of the auth method that should be challenged. - */ - @NonNull - public final String authMethodId; - - @NonNull - @Override - public String toUnsanitizedString() { - return "MFASelectedChallengeCommandParameters(authority=" + authority + ", challengeType=" + challengeType + ", authMethodId=" + authMethodId + ")"; - } - - @Override - public boolean containsPii() { - return !toString().equals(toUnsanitizedString()); - } - - @NonNull - @Override - public String toString() { - return toUnsanitizedString(); - } -} diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/SignInSubmitCodeCommandParameters.java b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/SignInSubmitCodeCommandParameters.java index 18d2f39a8d..f270f795f5 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/SignInSubmitCodeCommandParameters.java +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/commands/parameters/SignInSubmitCodeCommandParameters.java @@ -39,6 +39,12 @@ public class SignInSubmitCodeCommandParameters extends BaseSignInTokenCommandParameters { private static final String TAG = SignInSubmitCodeCommandParameters.class.getSimpleName(); + /** + * Identifies if MFA grant type is required. + */ + @NonNull + public final Boolean isMFAGrantType; + /** * The one-time password used for authentication. */ diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/controllers/results/MFACommandResult.kt b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/controllers/results/MFACommandResult.kt index 8f4a08f478..3462140fe1 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/controllers/results/MFACommandResult.kt +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/controllers/results/MFACommandResult.kt @@ -22,9 +22,6 @@ // THE SOFTWARE. package com.microsoft.identity.common.java.nativeauth.controllers.results -import com.microsoft.identity.common.java.nativeauth.providers.responses.signin.AuthenticationMethodApiResult -import com.microsoft.identity.common.java.nativeauth.util.toUnsanitizedString - sealed interface GetAuthMethodsCommandResult: INativeAuthCommandResult sealed interface MFAChallengeCommandResult: INativeAuthCommandResult sealed interface MFASubmitChallengeCommandResult: INativeAuthCommandResult @@ -45,14 +42,4 @@ interface MFACommandResult { override fun toString(): String = "VerificationRequired(correlationId=$correlationId, codeLength=$codeLength, challengeChannel=$challengeChannel)" } - - data class SelectionRequired( - override val correlationId: String, - val continuationToken: String, - val authMethods: List - ) : GetAuthMethodsCommandResult, MFAChallengeCommandResult { - override fun toUnsanitizedString(): String = "SelectionRequired(correlationId=$correlationId, authMethods=${authMethods.toUnsanitizedString()})" - - override fun toString(): String = "SelectionRequired(correlationId=$correlationId, authMethods=${authMethods})" - } } diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/controllers/results/SignInCommandResult.kt b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/controllers/results/SignInCommandResult.kt index f50ba14585..7238eb4f52 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/controllers/results/SignInCommandResult.kt +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/controllers/results/SignInCommandResult.kt @@ -121,13 +121,10 @@ interface SignInCommandResult { data class MFARequired( override val correlationId: String, val continuationToken: String, - val error: String, - val errorDescription: String, - val errorCodes: List, - val subError: String + val authMethods: List ) : SignInStartCommandResult, SignInSubmitPasswordCommandResult { - override fun toUnsanitizedString(): String = "MFARequired(correlationId=$correlationId, error=$error, errorDescription=$errorDescription, errorCodes=$errorCodes, subError=$subError)" + override fun toUnsanitizedString(): String = "MFARequired(correlationId=$correlationId, authMethods=${authMethods.toUnsanitizedString()})" - override fun toString(): String = "MFARequired(correlationId=$correlationId)" + override fun toString(): String = "MFARequired(correlationId=$correlationId, authMethods=${authMethods})" } } diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthConstants.kt b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthConstants.kt index 4b2a5282cf..0124420018 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthConstants.kt +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthConstants.kt @@ -48,6 +48,8 @@ object NativeAuthConstants { const val PASSWORD = "password" //Authentication is done by presenting an Out of band token const val OOB = "oob" + // Authentication is done by presenting a MFA Out of band token + const val MFA_OOB = "mfa_oob" //Authentication is done by presenting a continuation token const val CONTINUATION_TOKEN = "continuation_token" //Authentication must be performed by following the redirect url diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthRequestProvider.kt b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthRequestProvider.kt index f0f586f887..3a6353b460 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthRequestProvider.kt +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthRequestProvider.kt @@ -28,6 +28,7 @@ import com.microsoft.identity.common.java.logging.LibraryInfoHelper import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordStartCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordSubmitCodeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordSubmitNewPasswordCommandParameters +import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInStartCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInSubmitCodeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInSubmitPasswordCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInWithContinuationTokenCommandParameters @@ -35,11 +36,9 @@ import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpS import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpSubmitCodeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpSubmitPasswordCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpSubmitUserAttributesCommandParameters -import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignInStartCommandParameters import com.microsoft.identity.common.java.nativeauth.providers.requests.jit.JITChallengeRequest import com.microsoft.identity.common.java.nativeauth.providers.requests.jit.JITContinueRequest import com.microsoft.identity.common.java.nativeauth.providers.requests.jit.JITIntrospectRequest -import com.microsoft.identity.common.java.net.HttpConstants import com.microsoft.identity.common.java.nativeauth.providers.requests.resetpassword.ResetPasswordChallengeRequest import com.microsoft.identity.common.java.nativeauth.providers.requests.resetpassword.ResetPasswordContinueRequest import com.microsoft.identity.common.java.nativeauth.providers.requests.resetpassword.ResetPasswordPollCompletionRequest @@ -52,6 +51,7 @@ import com.microsoft.identity.common.java.nativeauth.providers.requests.signin.S import com.microsoft.identity.common.java.nativeauth.providers.requests.signup.SignUpChallengeRequest import com.microsoft.identity.common.java.nativeauth.providers.requests.signup.SignUpContinueRequest import com.microsoft.identity.common.java.nativeauth.providers.requests.signup.SignUpStartRequest +import com.microsoft.identity.common.java.net.HttpConstants import com.microsoft.identity.common.java.platform.Device import java.util.TreeMap @@ -170,7 +170,8 @@ class NativeAuthRequestProvider(private val config: NativeAuthOAuth2Configuratio challengeType = config.challengeType, requestUrl = signInTokenEndpoint, headers = getRequestHeaders(commandParameters.getCorrelationId()), - claimsRequestJson = commandParameters.claimsRequestJson + claimsRequestJson = commandParameters.claimsRequestJson, + isMFAGrantType = commandParameters.isMFAGrantType ) } diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/requests/signin/SignInTokenRequest.kt b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/requests/signin/SignInTokenRequest.kt index e1e3145b7d..7d4691328e 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/requests/signin/SignInTokenRequest.kt +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/requests/signin/SignInTokenRequest.kt @@ -57,7 +57,8 @@ data class SignInTokenRequest private constructor( challengeType: String? = null, requestUrl: String, headers: Map, - claimsRequestJson: String? + claimsRequestJson: String?, + isMFAGrantType: Boolean ): SignInTokenRequest { // Check for empty Strings and empty Maps ArgUtils.validateNonNullArg(oob, "oob") @@ -67,13 +68,12 @@ data class SignInTokenRequest private constructor( ArgUtils.validateNonNullArg(requestUrl, "requestUrl") ArgUtils.validateNonNullArg(headers, "headers") - return SignInTokenRequest( parameters = NativeAuthRequestSignInTokenRequestParameters( oob = oob, continuationToken = continuationToken, clientId = clientId, - grantType = NativeAuthConstants.GrantType.OOB, + grantType = if (isMFAGrantType) NativeAuthConstants.GrantType.MFA_OOB else NativeAuthConstants.GrantType.OOB, challengeType = challengeType, scope = scopes?.joinToString(" "), claimsRequestJson = claimsRequestJson diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/signin/SignInChallengeApiResponse.kt b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/signin/SignInChallengeApiResponse.kt index 4caf90d0de..5b0a4a79cc 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/signin/SignInChallengeApiResponse.kt +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/signin/SignInChallengeApiResponse.kt @@ -26,8 +26,6 @@ import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName import com.microsoft.identity.common.java.nativeauth.providers.INativeAuthApiResponse import com.microsoft.identity.common.java.nativeauth.providers.responses.ApiErrorResult -import com.microsoft.identity.common.java.nativeauth.util.isIntrospectRequired -import com.microsoft.identity.common.java.nativeauth.util.isInvalidRequest import com.microsoft.identity.common.java.nativeauth.util.isOOB import com.microsoft.identity.common.java.nativeauth.util.isPassword import com.microsoft.identity.common.java.nativeauth.util.isRedirect @@ -77,28 +75,14 @@ class SignInChallengeApiResponse( // Handle 400 errors HttpURLConnection.HTTP_BAD_REQUEST -> { - when { - error.isInvalidRequest() && subError.isIntrospectRequired() -> { - SignInChallengeApiResult.IntrospectRequired( - error = error.orEmpty(), - subError = subError.orEmpty(), - errorDescription = errorDescription.orEmpty(), - errorCodes = errorCodes.orEmpty(), - correlationId = correlationId - ) - } - else -> { - SignInChallengeApiResult.UnknownError( - error = error.orEmpty(), - subError = subError.orEmpty(), - errorDescription = errorDescription.orEmpty(), - errorCodes = errorCodes.orEmpty(), - correlationId = correlationId - ) - } - } + SignInChallengeApiResult.UnknownError( + error = error.orEmpty(), + subError = subError.orEmpty(), + errorDescription = errorDescription.orEmpty(), + errorCodes = errorCodes.orEmpty(), + correlationId = correlationId + ) } - // Handle success and redirect HttpURLConnection.HTTP_OK -> { return when { diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/signin/SignInChallengeApiResult.kt b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/signin/SignInChallengeApiResult.kt index fa7a752a48..eb85468223 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/signin/SignInChallengeApiResult.kt +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/responses/signin/SignInChallengeApiResult.kt @@ -41,26 +41,6 @@ sealed interface SignInChallengeApiResult: ApiResult { override fun toString(): String = toUnsanitizedString() } - data class IntrospectRequired( - override val correlationId: String, - override val error: String, - override val subError: String, - override val errorDescription: String, - override val errorCodes: List, - ) : ApiErrorResult( - error = error, - subError = subError, - errorDescription = errorDescription, - errorCodes = errorCodes, - correlationId = correlationId - ), SignInChallengeApiResult { - override fun toUnsanitizedString(): String { - return "IntrospectRequired(correlationId=$correlationId)" - } - - override fun toString(): String = toUnsanitizedString() - } - data class OOBRequired( override val correlationId: String, val continuationToken: String, diff --git a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/util/ApiErrorResponseUtil.kt b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/util/ApiErrorResponseUtil.kt index 5e190025c0..be99c20a97 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/nativeauth/util/ApiErrorResponseUtil.kt +++ b/common4j/src/main/com/microsoft/identity/common/java/nativeauth/util/ApiErrorResponseUtil.kt @@ -26,10 +26,6 @@ internal fun String?.isRedirect(): Boolean { return this.contentEquals(other = "redirect", ignoreCase = true) } -internal fun String?.isIntrospectRequired(): Boolean { - return this.contentEquals(other = "introspect_required", ignoreCase = true) -} - internal fun String?.isOOB(): Boolean { return this.contentEquals(other = "oob", ignoreCase = true) } diff --git a/common4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthRequestProviderTest.kt b/common4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthRequestProviderTest.kt index 4070774e58..5ba493435d 100644 --- a/common4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthRequestProviderTest.kt +++ b/common4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthRequestProviderTest.kt @@ -23,6 +23,8 @@ package com.microsoft.identity.common.java.nativeauth.providers import com.microsoft.identity.common.java.AuthenticationConstants +import com.microsoft.identity.common.java.exception.ClientException +import com.microsoft.identity.common.java.interfaces.PlatformComponents import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordStartCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordSubmitCodeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.ResetPasswordSubmitNewPasswordCommandParameters @@ -34,8 +36,6 @@ import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpS import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpSubmitCodeCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpSubmitPasswordCommandParameters import com.microsoft.identity.common.java.nativeauth.commands.parameters.SignUpSubmitUserAttributesCommandParameters -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.java.util.ObjectMapper @@ -847,6 +847,7 @@ class NativeAuthRequestProviderTest { .code(emptyString) .continuationToken(continuationToken) .correlationId(correlationId) + .isMFAGrantType(false) .build() nativeAuthRequestProvider.createOOBTokenRequest( @@ -862,12 +863,14 @@ class NativeAuthRequestProviderTest { .correlationId(correlationId) .code("code") .claimsRequestJson("claims") + .isMFAGrantType(false) .build() val request = nativeAuthRequestProvider.createOOBTokenRequest( commandParameters = commandParameters ) assertEquals(request.parameters.oob, commandParameters.code) + assertEquals(request.parameters.grantType, NativeAuthConstants.GrantType.OOB) assertEquals(request.parameters.claimsRequestJson, commandParameters.claimsRequestJson) assertEquals(request.parameters.continuationToken, commandParameters.continuationToken) assertEquals(request.parameters.challengeType, mockConfig.challengeType) diff --git a/common4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthResponseHandlerTest.kt b/common4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthResponseHandlerTest.kt index fda900cfc8..d3fad0078f 100644 --- a/common4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthResponseHandlerTest.kt +++ b/common4j/src/test/com/microsoft/identity/common/java/nativeauth/providers/NativeAuthResponseHandlerTest.kt @@ -2754,31 +2754,6 @@ class NativeAuthResponseHandlerTest { assertEquals(tenantMisconfiguration, apiResult.errorDescription) } - @Test - fun testSignInChallengeApiResponseIntrospectRequired() { - val response = SignInChallengeApiResponse( - statusCode = errorStatusCode, - challengeType = null, - redirectReason = null, - continuationToken = null, - error = invalidRequestError, - subError = introspectRequiredSubError, - errorCodes = null, - errorDescription = null, - errorUri = null, - bindingMethod = null, - challengeTargetLabel = null, - challengeChannel = null, - codeLength = null, - interval = null, - correlationId = correlationId - ) - - val apiResult = response.toResult() - assertTrue(apiResult is SignInChallengeApiResult.IntrospectRequired) - assertEquals(correlationId, (apiResult as SignInChallengeApiResult.IntrospectRequired).correlationId) - } - @Test fun testSignInChallengeApiResponseChallengeTypeOobSuccess() { val response = SignInChallengeApiResponse( diff --git a/common4j/src/testFixtures/java/com/microsoft/identity/common/nativeauth/MockApiResponseType.kt b/common4j/src/testFixtures/java/com/microsoft/identity/common/nativeauth/MockApiResponseType.kt index 90f89952de..5b13b4051d 100644 --- a/common4j/src/testFixtures/java/com/microsoft/identity/common/nativeauth/MockApiResponseType.kt +++ b/common4j/src/testFixtures/java/com/microsoft/identity/common/nativeauth/MockApiResponseType.kt @@ -37,7 +37,6 @@ enum class MockApiResponseType(val stringValue: String) { CREDENTIAL_REQUIRED("CredentialRequired"), EXPIRED_TOKEN("ExpiredToken"), INITIATE_SUCCESS("InitiateSuccess"), - INTROSPECT_REQUIRED("IntrospectRequired"), INTROSPECT_SUCCESS("IntrospectSuccess"), INVALID_AUTHENTICATION_METHOD("InvalidAuthMethodForUser"), INVALID_CLIENT("InvalidClient"),