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

SignIn code for Native Auth #1919

Merged
merged 13 commits into from
Nov 9, 2023
2 changes: 1 addition & 1 deletion common
Submodule common updated 47 files
+1 −0 common/build.gradle
+57 −0 common/src/main/java/com/microsoft/identity/common/internal/commands/SignInResendCodeCommand.kt
+57 −0 common/src/main/java/com/microsoft/identity/common/internal/commands/SignInStartCommand.kt
+57 −0 common/src/main/java/com/microsoft/identity/common/internal/commands/SignInSubmitCodeCommand.kt
+36 −0 common/src/main/java/com/microsoft/identity/common/internal/commands/SignInSubmitPasswordCommand.kt
+58 −0 common/src/main/java/com/microsoft/identity/common/internal/commands/SignInWithSLTCommand.kt
+768 −3 common/src/main/java/com/microsoft/identity/common/internal/controllers/NativeAuthMsalController.kt
+107 −0 common/src/main/java/com/microsoft/identity/common/internal/util/CommandUtil.java
+20 −0 ...n/src/test/java/com/microsoft/identity/common/internal/providers/microsoft/nativeauth/utils/ApiConstants.kt
+418 −0 ...t/java/com/microsoft/identity/common/internal/providers/microsoft/nativeauth/utils/CommandResultUtilTest.kt
+74 −0 ...crosoft/identity/common/java/commands/parameters/nativeauth/AcquireTokenNoFixedScopesCommandParameters.java
+44 −0 ...ain/com/microsoft/identity/common/java/commands/parameters/nativeauth/BaseSignInTokenCommandParameters.java
+38 −0 ...in/com/microsoft/identity/common/java/commands/parameters/nativeauth/SignInResendCodeCommandParameters.java
+38 −0 ...rc/main/com/microsoft/identity/common/java/commands/parameters/nativeauth/SignInStartCommandParameters.java
+38 −0 ...icrosoft/identity/common/java/commands/parameters/nativeauth/SignInStartUsingPasswordCommandParameters.java
+40 −0 ...in/com/microsoft/identity/common/java/commands/parameters/nativeauth/SignInSubmitCodeCommandParameters.java
+40 −0 ...om/microsoft/identity/common/java/commands/parameters/nativeauth/SignInSubmitPasswordCommandParameters.java
+41 −0 .../main/com/microsoft/identity/common/java/commands/parameters/nativeauth/SignInWithSLTCommandParameters.java
+25 −0 common4j/src/main/com/microsoft/identity/common/java/controllers/ExceptionAdapter.java
+22 −6 common4j/src/main/com/microsoft/identity/common/java/controllers/results/ICommandResult.kt
+71 −0 common4j/src/main/com/microsoft/identity/common/java/controllers/results/ResetPasswordCommandResult.kt
+65 −0 common4j/src/main/com/microsoft/identity/common/java/controllers/results/SignInCommandResult.kt
+24 −2 common4j/src/main/com/microsoft/identity/common/java/eststelemetry/PublicApiId.java
+11 −0 common4j/src/main/com/microsoft/identity/common/java/exception/ErrorStrings.java
+40 −0 common4j/src/main/com/microsoft/identity/common/java/exception/RefreshTokenNotFoundException.kt
+9 −0 common4j/src/main/com/microsoft/identity/common/java/providers/nativeauth/NativeAuthConstants.kt
+157 −2 common4j/src/main/com/microsoft/identity/common/java/providers/nativeauth/NativeAuthOAuth2Configuration.kt
+53 −1 common4j/src/main/com/microsoft/identity/common/java/providers/nativeauth/NativeAuthOAuth2Strategy.kt
+7 −1 common4j/src/main/com/microsoft/identity/common/java/providers/nativeauth/NativeAuthOAuth2StrategyFactory.kt
+145 −0 common4j/src/main/com/microsoft/identity/common/java/providers/nativeauth/NativeAuthRequestProvider.kt
+166 −0 common4j/src/main/com/microsoft/identity/common/java/providers/nativeauth/NativeAuthResponseHandler.kt
+162 −0 common4j/src/main/com/microsoft/identity/common/java/providers/nativeauth/interactors/SignInInteractor.kt
+79 −0 .../src/main/com/microsoft/identity/common/java/providers/nativeauth/requests/signin/SignInChallengeRequest.kt
+79 −0 ...j/src/main/com/microsoft/identity/common/java/providers/nativeauth/requests/signin/SignInInitiateRequest.kt
+175 −0 ...on4j/src/main/com/microsoft/identity/common/java/providers/nativeauth/requests/signin/SignInTokenRequest.kt
+2 −1 common4j/src/main/com/microsoft/identity/common/java/providers/nativeauth/responses/ApiErrorResult.kt
+170 −0 ...main/com/microsoft/identity/common/java/providers/nativeauth/responses/signin/SignInChallengeApiResponse.kt
+53 −0 ...c/main/com/microsoft/identity/common/java/providers/nativeauth/responses/signin/SignInChallengeApiResult.kt
+132 −0 .../main/com/microsoft/identity/common/java/providers/nativeauth/responses/signin/SignInInitiateApiResponse.kt
+56 −0 ...rc/main/com/microsoft/identity/common/java/providers/nativeauth/responses/signin/SignInInitiateApiResult.kt
+166 −0 ...src/main/com/microsoft/identity/common/java/providers/nativeauth/responses/signin/SignInTokenApiResponse.kt
+95 −0 ...j/src/main/com/microsoft/identity/common/java/providers/nativeauth/responses/signin/SignInTokenApiResult.kt
+154 −0 common4j/src/main/com/microsoft/identity/common/java/util/ApiErrorResponseUtil.kt
+23 −0 common4j/src/main/com/microsoft/identity/common/java/util/ArgUtils.kt
+12 −4 common4j/src/main/com/microsoft/identity/common/java/util/UrlUtil.java
+3 −0 testutils/build.gradle
+24 −2 testutils/src/main/java/com/microsoft/identity/internal/nativeauth/MockApiUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
package com.microsoft.identity.client

import com.microsoft.identity.client.exception.MsalException
import com.microsoft.identity.client.statemachine.results.SignInResult
import com.microsoft.identity.client.statemachine.results.SignInUsingPasswordResult
import com.microsoft.identity.client.statemachine.states.AccountResult

/**
* INativeAuthPublicClientApplication provides top level interface that is used by dpp developers
* INativeAuthPublicClientApplication provides top level interface that is used by app developers
* to use Native Auth methods.
*/
interface INativeAuthPublicClientApplication : IPublicClientApplication {
fadidurah marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -43,4 +46,16 @@ interface INativeAuthPublicClientApplication : IPublicClientApplication {
*/
fun onError(exception: MsalException)
}

suspend fun getCurrentAccount(): AccountResult?

fun getCurrentAccount(callback: NativeAuthPublicClientApplication.GetCurrentAccountCallback)

suspend fun signIn(username: String, scopes: List<String>? = null): SignInResult

fun signIn(username: String, scopes: List<String>? = null, callback: NativeAuthPublicClientApplication.SignInCallback)

suspend fun signInUsingPassword(username: String, password: String, scopes: List<String>? = null): SignInUsingPasswordResult

fun signInUsingPassword(username: String, password: String, scopes: List<String>? = null, callback: NativeAuthPublicClientApplication.SignInUsingPasswordCallback)
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class NativeAuthPublicClientApplicationConfiguration :
Serializable {
companion object {
private val TAG = NativeAuthPublicClientApplicationConfiguration::class.java.simpleName
private val VALID_CHALLENGE_TYPES = listOf(NativeAuthConstants.GrantType.PASSWORD,
NativeAuthConstants.GrantType.OOB, NativeAuthConstants.GrantType.REDIRECT)
private val VALID_CHALLENGE_TYPES = listOf(NativeAuthConstants.ChallengeType.PASSWORD,
NativeAuthConstants.ChallengeType.OOB, NativeAuthConstants.ChallengeType.REDIRECT)
}

private object NativeAuthSerializedNames {
Expand All @@ -57,7 +57,7 @@ class NativeAuthPublicClientApplicationConfiguration :
}

//List of challenge types supported by the client.
//For a complete list of challenge types see [NativeAuthConstants.GrantType]
//For a complete list of challenge types see [NativeAuthConstants.ChallengeType]
@SerializedName(NativeAuthSerializedNames.CHALLENGE_TYPES)
private var challengeTypes: List<String>? = null

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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.client.exception;

public class MsalUserNotFoundException extends MsalException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Javadoc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps you can simply leverage MsalServiceException with a new error code for user_not_found?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file has been removed.

private final static String USER_NOT_FOUND_ERROR_CODE = "user_not_found";

public MsalUserNotFoundException() {
super(USER_NOT_FOUND_ERROR_CODE, "No user found in cache");
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ sealed class Error(
/**
* GeneralError is a base class for all errors present in the Native Auth.
*/
sealed class GeneralError(
open var error: String? = null,
open val errorMessage: String? = "An unexpected error happened",
open val correlationId: String,
open val errorCodes: List<Int>? = null,
open var exception: Exception? = null
)

class GeneralError(
override var error: String? = null,
override val errorMessage: String? = "An unexpected error happened",
override val correlationId: String,
val details: List<Map<String, String>>? = null,
override val errorCodes: List<Int>? = null,
override var exception: Exception? = null
) : Error(errorMessage = errorMessage, error = error, correlationId = correlationId, exception = exception)

/**
* BrowserRequiredError occurs when authentication cannot be performed via means of Native Auth and
Expand All @@ -51,7 +51,7 @@ class BrowserRequiredError(
override var error: String? = null,
override val errorMessage: String = "The client's authentication capabilities are insufficient. Please redirect to the browser to complete authentication",
override val correlationId: String
) : GeneralError(errorMessage = errorMessage, error = error, correlationId = correlationId)
) : Error(errorMessage = errorMessage, error = error, correlationId = correlationId)

/**
* IncorrectCodeError occurs when the user has provided incorrect code for out of band authentication.
Expand All @@ -61,7 +61,7 @@ class IncorrectCodeError(
override val errorMessage: String,
override val correlationId: String,
override val errorCodes: List<Int>? = null
) : GeneralError(errorMessage = errorMessage, error = error, correlationId = correlationId, errorCodes = errorCodes)
) : Error(errorMessage = errorMessage, error = error, correlationId = correlationId, errorCodes = errorCodes)

/**
* UserNotFoundError occurs when the user could not be located in the given the username. The authentication
Expand All @@ -72,7 +72,7 @@ class UserNotFoundError(
override val errorMessage: String,
override val correlationId: String,
override val errorCodes: List<Int>? = null
) : GeneralError(errorMessage = errorMessage, error = error, correlationId = correlationId, errorCodes = errorCodes)
) : Error(errorMessage = errorMessage, error = error, correlationId = correlationId, errorCodes = errorCodes)

/**
* PasswordIncorrectError occurs when the user has provided incorrect password for signin.
Expand All @@ -82,7 +82,7 @@ class PasswordIncorrectError(
override val errorMessage: String,
override val correlationId: String,
override val errorCodes: List<Int>
) : GeneralError(errorMessage = errorMessage, error = error, correlationId = correlationId, errorCodes = errorCodes)
) : Error(errorMessage = errorMessage, error = error, correlationId = correlationId, errorCodes = errorCodes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are there so many identical classes?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can easily write one Error class and then use different Strings or enums to represent different error codes within that Error object

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will discuss it with the team but won't be able to make changes as part of this PR as it will be significant refactoring.


/**
* UserAlreadyExistsError has used a username to create an exists for which there is a pre-existing
Expand All @@ -92,7 +92,7 @@ class UserAlreadyExistsError(
override var error: String? = null,
override val errorMessage: String,
override val correlationId: String
) : GeneralError(errorMessage = errorMessage, error = error, correlationId = correlationId)
) : Error(errorMessage = errorMessage, error = error, correlationId = correlationId)

/**
* InvalidPasswordError is seen in Signup process when a user provides a password that does not
Expand All @@ -102,7 +102,7 @@ class InvalidPasswordError(
override var error: String? = null,
override val errorMessage: String,
override val correlationId: String
) : GeneralError(errorMessage = errorMessage, error = error, correlationId = correlationId)
) : Error(errorMessage = errorMessage, error = error, correlationId = correlationId)

/**
* InvalidPasswordError is seen in Signup process when a user provides a email address that is not
Expand All @@ -112,7 +112,7 @@ class InvalidEmailError(
override var error: String? = null,
override val errorMessage: String,
override val correlationId: String
) : GeneralError(errorMessage = errorMessage, error = error, correlationId = correlationId)
) : Error(errorMessage = errorMessage, error = error, correlationId = correlationId)

/**
* InvalidAttributesError is seen in Signup process when a user provides attributes that are not
Expand All @@ -122,4 +122,4 @@ class InvalidAttributesError(
override var error: String? = null,
override val errorMessage: String,
override val correlationId: String
) : GeneralError(errorMessage = errorMessage, error = error, correlationId = correlationId)
) : Error(errorMessage = errorMessage, error = error, correlationId = correlationId)
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// ktlint-disable filename

// 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.client.statemachine.results

import com.microsoft.identity.client.statemachine.Error
import com.microsoft.identity.client.statemachine.states.State

interface Result {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Javadoc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

open class SuccessResult(open val nextState: State) : Result
open class ErrorResult(open val error: Error) : Result
open class CompleteResult(open val resultValue: Any? = null) : Result
open class CompleteWithNextStateResult(override val resultValue: Any? = null, open val nextState: State?) : CompleteResult(resultValue = resultValue)

fun isSuccess(): Boolean = this is SuccessResult
fun isError(): Boolean = this is ErrorResult
fun isComplete(): Boolean = this is CompleteResult
}

/**
* Sign out: removes account from cache. Does not perform single sign-out.
*/
sealed interface SignOutResult : Result {
/**
* CompleteResult Result, which indicates the sign out flow completed successfully.
* i.e. the user account has been removed from persistence.
*/
object Complete :
Result.CompleteResult(resultValue = null),
SignOutResult

/**
* UnexpectedError ErrorResult, which indicates that an unexpected error occurred during sign out.
*
* @param error [com.microsoft.identity.client.statemachine.Error]
*/
class UnexpectedError(override val error: Error) :
Result.ErrorResult(error = error),
SignOutResult
}
Loading