-
Notifications
You must be signed in to change notification settings - Fork 126
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
Conversation
msal/src/main/java/com/microsoft/identity/client/INativeAuthPublicClientApplication.kt
Show resolved
Hide resolved
msal/src/main/java/com/microsoft/identity/client/NativeAuthPublicClientApplication.kt
Show resolved
Hide resolved
msal/src/main/java/com/microsoft/identity/client/NativeAuthPublicClientApplication.kt
Outdated
Show resolved
Hide resolved
msal/src/main/java/com/microsoft/identity/client/NativeAuthPublicClientApplication.kt
Outdated
Show resolved
Hide resolved
msal/src/main/java/com/microsoft/identity/client/statemachine/results/SignInResult.kt
Outdated
Show resolved
Hide resolved
if (cacheRecords.isNullOrEmpty()) { | ||
return null | ||
} | ||
val account = AccountAdapter.adapt(cacheRecords) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like this is an accountList
as opposed to an account
, right? So let's name it appropriately
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -250,6 +283,37 @@ public static DeviceCodeFlowCommandParameters createDeviceCodeFlowWithClaimsComm | |||
return commandParameters; | |||
} | |||
|
|||
public static AcquireTokenNoFixedScopesCommandParameters createAcquireTokenNoFixedScopesCommandParameters( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
javadoc for all public methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -51,6 +82,8 @@ | |||
import java.util.List; | |||
import java.util.Map; | |||
|
|||
import androidx.annotation.Nullable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably run Optimize imports
once on all files in the PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
import com.microsoft.identity.client.statemachine.Error | ||
import com.microsoft.identity.client.statemachine.states.State | ||
|
||
interface Result { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
@@ -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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
* @param error [com.microsoft.identity.client.statemachine.Error]. | ||
*/ | ||
class UnexpectedError(override val error: Error) : | ||
Result.ErrorResult(error = error), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mentioned in another place about not having so many unnecessary duplicated classes, and instead one result or error class that can hold different error codes.
There was a problem hiding this comment.
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.
} | ||
} | ||
|
||
interface SignOutCallback : Callback<SignOutResult> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also what's inside this interface? Seems to be empty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean I don't see any curly braces...so not sure if the below methods are in this interface or on the AccountResult class or perhaps on the parent interface i.e. BaseStates?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An interface in Kotlin doesn't need a body so thats why it works.
|
||
sealed interface State | ||
|
||
abstract class BaseState(internal open val flowToken: String?) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
|
||
import com.microsoft.identity.common.java.exception.BaseException | ||
|
||
interface Callback <T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc everywhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -0,0 +1,154 @@ | |||
package com.microsoft.identity.client.nativeauth |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LICENSE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
@@ -0,0 +1,47 @@ | |||
package com.microsoft.identity.client.nativeauth |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing LICENSE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing LICENSEs, Missing Javadocs, duplicated code around classes that hold Error and result objects
@@ -266,7 +266,7 @@ class SignInPasswordRequiredState( | |||
* @param callback [com.microsoft.identity.client.statemachine.states.SignInPasswordRequiredState.SubmitPasswordCallback] to receive the result on. | |||
* @return The results of the submit password action. | |||
*/ | |||
fun submitPassword(password: String, callback: SubmitPasswordCallback) { | |||
fun submitPassword(password: CharArray, callback: SubmitPasswordCallback) { | |||
LogSession.logMethodCall(TAG, "${TAG}.submitPassword") | |||
NativeAuthPublicClientApplication.pcaScope.launch { | |||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure exactly where we need to add StringUtil.overwriteWithZero(params.password)
Every place password is passed as param? If so, then we need it in this method as well i think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe right after we get the result
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This password is coming from the calling application and it must be their responsibility to clear the password char array. As a rule, I am clearing password char arrays in the object we are creating.
null | ||
) | ||
throw MsalClientException( | ||
MsalClientException.INVALID_PARAMETER, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is INVALID_PARAMETER the right error in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the most suitable error from existing codes.
null | ||
) | ||
throw MsalClientException( | ||
MsalClientException.INVALID_PARAMETER, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is INVALID_PARAMETER the right error in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the most suitable error from existing codes.
val doesAccountExist = checkForPersistedAccount().get() | ||
if (doesAccountExist) { | ||
Logger.error( | ||
TAG, | ||
"An account is already signed in.", | ||
null | ||
) | ||
throw MsalClientException( | ||
MsalClientException.INVALID_PARAMETER, | ||
"An account is already signed in." | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw this exact code block in another method - seems like an opportunity for code sharing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved it to a common function.
|
||
package com.microsoft.identity.client.exception; | ||
|
||
public class MsalUserNotFoundException extends MsalException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
* | ||
* @param callback [com.microsoft.identity.client.statemachine.states.AccountResult.SignOutCallback] to receive the result on. | ||
*/ | ||
fun signOut(callback: SignOutCallback) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So signOut is a method on a base state..why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that you can sign out from any given state? What if the user was never even signed in to begin with?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the user does not have a signed in account then we will throw MsalClientException.NO_CURRENT_ACCOUNT error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, to me it sounds like that signOut
should only be accessible from a signedInState... is there a reason it has to stay on a base state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shahzaibj this method (as well as getAccessToken()
, and other methods) are only available in the AccountResult
state, which is practically the same as the SignInState
you mention. They're not part of BaseState
, this is just an interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason we've called it AccountResult
rather than SignedInResult
is because "account" makes more sense to us in this context: on an account object you can retrieve tokens, sign out (the act of signing out an account), etc. This was aligned with our PM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved the AccountResult
to its own file so its clear that BaseStates interface doesn't have the signOut
and getAccessToken
method.
import kotlinx.coroutines.withContext | ||
import java.io.Serializable | ||
|
||
class SignInCodeRequiredState internal constructor( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
) : BaseState(flowToken), State, Serializable { | ||
private val TAG: String = SignInCodeRequiredState::class.java.simpleName | ||
|
||
interface SubmitCodeCallback : Callback<SignInSubmitCodeResult> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
} | ||
|
||
class SignInPasswordRequiredState( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} | ||
} | ||
|
||
abstract class SignInAfterSignUpBaseState( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Javadoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
* @throws [MsalClientException] If the the account doesn't exist in the cache. | ||
* @throws [ServiceException] If the refresh token doesn't exist in the cache/is expired, or the refreshing fails. | ||
*/ | ||
fun getAccessToken(forceRefresh: Boolean = false, callback: GetAccessTokenCallback) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can get access token from a state where you never signed in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same reply as for the other comment: this method is part of AccountResult
, which is a result/state that is returned when you're signed in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved the AccountResult
to its own file so its clear that BaseStates interface doesn't have the signOut
and getAccessToken
method.
This PR includes the work for SignIn relates features of Native Auth. Mockito-kotlin has been added as dependency for test projects in common and testutils project. Powermock has been added as a dependency to testutils project. Companion PR in MSAL repo is AzureAD/microsoft-authentication-library-for-android#1919
This PR is to merge the SignIn, SIgnup and SSPR code into dev branch. This code was previously reviewed in #1897, #1919, #1949 and #1950 . A technical overview of Native Auth is available at https://dev.azure.com/IdentityDivision/DevEx/_git/AuthLibrariesApiReview?path=/%5BAndroid%5D%20Native%20authentication/technical_overview.md&version=GBsammy/native-authentication&_a=preview A companion PR in common repo is AzureAD/microsoft-authentication-library-common-for-android#2233 --------- Co-authored-by: melissaahn <[email protected]> Co-authored-by: iamgusain <[email protected]> Co-authored-by: Dome Pongmongkol <[email protected]> Co-authored-by: Sowmya Malayanur <[email protected]> Co-authored-by: Mohit <[email protected]> Co-authored-by: tanmaymanolkar1 <[email protected]> Co-authored-by: amoyixi <[email protected]> Co-authored-by: yixilin <[email protected]> Co-authored-by: fadidurah <[email protected]> Co-authored-by: Dean Xu <[email protected]> Co-authored-by: Neha Goel <[email protected]> Co-authored-by: Dome Pongmongkol <[email protected]> Co-authored-by: pedro romero vargas <[email protected]>
This PR includes the work for SignIn relates features of Native Auth
Companion PR in MSAL Common repo is AzureAD/microsoft-authentication-library-common-for-android#2207