diff --git a/CODEOWNERS b/CODEOWNERS index 498de8c8d5..74920c2bc4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -15,7 +15,6 @@ msal/src/main/java/com/microsoft/identity/nativeauth/ @AzureAD/NativeAuthTeam msal/src/test/java/com/microsoft/identity/nativeauth/ @AzureAD/NativeAuthTeam msal/src/test/java/com/microsoft/identity/client/e2e/tests/network/nativeauth/ @AzureAD/NativeAuthTeam msal/src/androidTest/java/com/microsoft/identity/nativeauth/ @AzureAD/NativeAuthTeam -msal/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth @AzureAD/NativeAuthTeam # If you are interested in reviewing or getting notified of changes in a particular area # Please add your alias against that specific path below diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/Constants.java b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/Constants.java index 6f88c3b995..ada7561404 100644 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/Constants.java +++ b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/Constants.java @@ -129,12 +129,4 @@ public enum AuthScheme { BEARER, POP } - - /** - * Constants used in native auth flows. - */ - public static final String STATE = "state"; - public static final String CODE_LENGTH = "code_length"; - public static final String SENT_TO = "sent_to"; - public static final String CHANNEL = "channel"; } diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/MainActivity.java b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/MainActivity.java index e3444fcda5..2ce4e39c8f 100644 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/MainActivity.java +++ b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/MainActivity.java @@ -225,11 +225,6 @@ public boolean onNavigationItemSelected(final MenuItem item) { return false; } fragment = new AcquireTokenFragment(); - } else if (menuItemId == R.id.nav_native) { - if (getCurrentFragment() instanceof NativeAuthFragment) { - return false; - } - fragment = new NativeAuthFragment(); } else if (menuItemId == R.id.nav_result) { if (getCurrentFragment() instanceof ResultFragment) { return false; diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/NativeAuthFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/NativeAuthFragment.kt deleted file mode 100644 index b4dc9be6b4..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/NativeAuthFragment.kt +++ /dev/null @@ -1,79 +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.client.testapp - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment -import com.google.android.material.bottomnavigation.BottomNavigationView -import com.microsoft.identity.client.testapp.nativeauth.AuthClient -import com.microsoft.identity.client.testapp.nativeauth.EmailAttributeSignUpFragment -import com.microsoft.identity.client.testapp.nativeauth.EmailPasswordSignInSignUpFragment -import com.microsoft.identity.client.testapp.nativeauth.EmailSignInSignUpFragment -import com.microsoft.identity.client.testapp.nativeauth.PasswordResetFragment - -/** - * Fragment used for starting various native auth flows. - */ -class NativeAuthFragment : Fragment() { - companion object { - private val TAG = NativeAuthFragment::class.java.simpleName - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - val view = inflater.inflate(R.layout.fragment_native, container, false) - - AuthClient.initialize(requireContext()) - - val emailSignInSignUpFragment = EmailSignInSignUpFragment() - val emailPasswordSignInSignUpFragment = EmailPasswordSignInSignUpFragment() - val emailAttributeSignUpFragment = EmailAttributeSignUpFragment() - val passwordResetFragment = PasswordResetFragment() - - val bottomNavigationView = view.findViewById(R.id.bottom_navigation_view) - - setFragment(emailSignInSignUpFragment, R.string.title_email_oob_sisu) - - bottomNavigationView.setOnNavigationItemSelectedListener { - when (it.itemId) { - R.id.email_oob_sisu -> setFragment(emailSignInSignUpFragment, R.string.title_email_oob_sisu) - R.id.email_password_sisu -> setFragment(emailPasswordSignInSignUpFragment, R.string.title_email_password_sisu) - R.id.email_attribute_sisu -> setFragment(emailAttributeSignUpFragment, R.string.title_email_attribute_oob_sisu) - R.id.email_oob_sspr -> setFragment(passwordResetFragment, R.string.title_email_oob_sspr) - } - true - } - - return view - } - - private fun setFragment(fragment: Fragment, title: Int) { - (this.context as AppCompatActivity).supportFragmentManager.beginTransaction().apply { - replace(R.id.scenario_fragment, fragment) - commit() - } - } -} \ No newline at end of file diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/AuthClient.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/AuthClient.kt deleted file mode 100644 index e648f91e77..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/AuthClient.kt +++ /dev/null @@ -1,47 +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.client.testapp.nativeauth - -import android.app.Application -import android.content.Context -import com.microsoft.identity.client.PublicClientApplication -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.nativeauth.INativeAuthPublicClientApplication - -/** - * Utility for managing MSAL SDK instance INativeAuthPublicClientApplication. - */ -object AuthClient : Application() { - private lateinit var authClient: INativeAuthPublicClientApplication - - fun getAuthClient(): INativeAuthPublicClientApplication { - return authClient - } - - fun initialize(context: Context) { - authClient = PublicClientApplication.createNativeAuthPublicClientApplication( - context, - R.raw.msal_config_native - ) - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/EmailAttributeSignUpFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/EmailAttributeSignUpFragment.kt deleted file mode 100644 index 951607dc9c..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/EmailAttributeSignUpFragment.kt +++ /dev/null @@ -1,304 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentEmailAttributeBinding -import com.microsoft.identity.nativeauth.INativeAuthPublicClientApplication -import com.microsoft.identity.nativeauth.UserAttributes -import com.microsoft.identity.nativeauth.statemachine.errors.GetAccessTokenError -import com.microsoft.identity.nativeauth.statemachine.results.GetAccessTokenResult -import com.microsoft.identity.nativeauth.statemachine.results.GetAccountResult -import com.microsoft.identity.nativeauth.statemachine.results.SignInResult -import com.microsoft.identity.nativeauth.statemachine.results.SignOutResult -import com.microsoft.identity.nativeauth.statemachine.results.SignUpResult -import com.microsoft.identity.nativeauth.statemachine.states.AccountState -import com.microsoft.identity.nativeauth.statemachine.states.SignInContinuationState -import com.microsoft.identity.nativeauth.statemachine.states.SignUpCodeRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for the email, password and user attributes sign up flow. - */ -class EmailAttributeSignUpFragment : Fragment() { - private lateinit var authClient: INativeAuthPublicClientApplication - private var _binding: FragmentEmailAttributeBinding? = null - private val binding get() = _binding!! - - companion object { - private enum class STATUS { SignedIn, SignedOut } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = FragmentEmailAttributeBinding.inflate(inflater, container, false) - val view = binding.root - - authClient = AuthClient.getAuthClient() - - init() - - return view - } - - override fun onResume() { - super.onResume() - getStateAndUpdateUI() - } - - private fun init() { - initializeButtonListeners() - } - - private fun initializeButtonListeners() { - binding.signUp.setOnClickListener { - signUp() - } - - binding.signOut.setOnClickListener { - signOut() - } - } - - private fun getStateAndUpdateUI() { - CoroutineScope(Dispatchers.Main).launch { - val accountResult = authClient.getCurrentAccount() - when (accountResult) { - is GetAccountResult.AccountFound -> { - displaySignedInState(accountResult.resultValue) - } - is GetAccountResult.NoAccountFound -> { - displaySignedOutState() - } - } - } - } - private fun signUp() { - CoroutineScope(Dispatchers.Main).launch { - try { - val email = binding.emailText.text.toString() - var password: CharArray? = null - if (binding.passwordText.length() > 0) { - password = CharArray(binding.passwordText.length()) - } - binding.passwordText.text?.getChars(0, binding.passwordText.length(), password, 0) - - val attributes = UserAttributes.Builder() - - val attr1Key = binding.attr1KeyText.text.toString() - if (attr1Key.isNotBlank()) { - val attr1Value = binding.attr1ValueText.toString() - attributes - .customAttribute(attr1Key, attr1Value) - } - - val attr2Key = binding.attr2KeyText.text.toString() - if (attr2Key.isNotBlank()) { - val attr2Value = binding.attr2ValueText.toString() - attributes - .customAttribute(attr2Key, attr2Value) - } - - val actionResult = authClient.signUp( - username = email, - password = password, - attributes = attributes.build() - ) - - password?.fill('0') - - when (actionResult) { - is SignUpResult.CodeRequired -> { - navigateToSignUp( - nextState = actionResult.nextState, - codeLength = actionResult.codeLength, - sentTo = actionResult.sentTo, - channel = actionResult.channel - ) - } - is SignUpResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_up_successful_message), - Toast.LENGTH_SHORT - ).show() - signInAfterSignUp( - nextState = actionResult.nextState - ) - } - else -> { - displayDialog("Unexpected result", actionResult.toString()) - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - - private suspend fun signInAfterSignUp(nextState: SignInContinuationState) { - val currentState = nextState - val actionResult = currentState.signIn() - when (actionResult) { - is SignInResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_in_successful_message), - Toast.LENGTH_SHORT - ).show() - displaySignedInState(accountState = actionResult.resultValue) - } - else -> { - displayDialog( "Unexpected result", actionResult.toString()) - } - } - } - private fun signOut() { - CoroutineScope(Dispatchers.Main).launch { - val getAccountResult = authClient.getCurrentAccount() - if (getAccountResult is GetAccountResult.AccountFound) { - val signOutResult = getAccountResult.resultValue.signOut() - if (signOutResult is SignOutResult.Complete) { - Toast.makeText( - requireContext(), - getString(R.string.sign_out_successful_message), - Toast.LENGTH_SHORT - ).show() - displaySignedOutState() - } else { - displayDialog( "Unexpected result", signOutResult.toString()) - } - } - } - } - private fun displaySignedInState(accountState: AccountState) { - emptyFields() - updateUI(STATUS.SignedIn) - displayAccount(accountState) - } - - private fun displaySignedOutState() { - emptyFields() - updateUI(STATUS.SignedOut) - emptyResults() - } - - private fun updateUI(status: STATUS) { - when (status) { - STATUS.SignedIn -> { - binding.signUp.isEnabled = false - binding.signOut.isEnabled = true - } - STATUS.SignedOut -> { - binding.signUp.isEnabled = true - binding.signOut.isEnabled = false - } - } - } - - private fun emptyFields() { - binding.emailText.setText("") - binding.passwordText.setText("") - binding.attr1KeyText.setText("") - binding.attr1ValueText.setText("") - binding.attr2KeyText.setText("") - binding.attr2ValueText.setText("") - } - - private fun emptyResults() { - binding.resultAccessToken.text = "" - binding.resultIdToken.text = "" - } - - private fun displayAccount(accountState: AccountState) { - CoroutineScope(Dispatchers.Main).launch { - try { - val accessTokenResult = accountState.getAccessToken() - when (accessTokenResult) { - is GetAccessTokenResult.Complete -> { - binding.resultAccessToken.text = - getString(R.string.result_access_token_text) + accessTokenResult.resultValue.accessToken - - val idToken = accountState.getIdToken() - binding.resultIdToken.text = - getString(R.string.result_id_token_text) + idToken - } - - is GetAccessTokenError -> { - displayDialog( - getString(R.string.msal_exception_title), - accessTokenResult.exception?.message.toString() - ) - } - } - } catch (exception: Exception) { - displayDialog( - getString(R.string.msal_exception_title), - exception.message.toString() - ) - } - } - } - private fun displayDialog(error: String?, message: String?) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(error) - .setMessage(message) - val alertDialog = builder.create() - alertDialog.show() - } - private fun navigateToSignUp( - nextState: SignUpCodeRequiredState, - codeLength: Int, - sentTo: String, - channel: String - ) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, nextState) - bundle.putInt(Constants.CODE_LENGTH, codeLength) - bundle.putString(Constants.SENT_TO, sentTo) - bundle.putString(Constants.CHANNEL, channel) - val fragment = SignUpCodeFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/EmailPasswordSignInSignUpFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/EmailPasswordSignInSignUpFragment.kt deleted file mode 100644 index f6f02492c6..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/EmailPasswordSignInSignUpFragment.kt +++ /dev/null @@ -1,356 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import com.microsoft.identity.client.Account -import com.microsoft.identity.client.AcquireTokenParameters -import com.microsoft.identity.client.AuthenticationCallback -import com.microsoft.identity.client.IAuthenticationResult -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentEmailPasswordBinding -import com.microsoft.identity.nativeauth.INativeAuthPublicClientApplication -import com.microsoft.identity.nativeauth.statemachine.errors.SignInError -import com.microsoft.identity.nativeauth.statemachine.results.GetAccessTokenResult -import com.microsoft.identity.nativeauth.statemachine.results.GetAccountResult -import com.microsoft.identity.nativeauth.statemachine.results.SignInResult -import com.microsoft.identity.nativeauth.statemachine.results.SignOutResult -import com.microsoft.identity.nativeauth.statemachine.results.SignUpResult -import com.microsoft.identity.nativeauth.statemachine.states.AccountState -import com.microsoft.identity.nativeauth.statemachine.states.SignInContinuationState -import com.microsoft.identity.nativeauth.statemachine.states.SignUpCodeRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for the email and password sign up and sign in flow. - */ -class EmailPasswordSignInSignUpFragment : Fragment() { - - private lateinit var authClient: INativeAuthPublicClientApplication - private var _binding: FragmentEmailPasswordBinding? = null - private val binding get() = _binding!! - - companion object { - private enum class STATUS { SignedIn, SignedOut } - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = FragmentEmailPasswordBinding.inflate(inflater, container, false) - val view = binding.root - - authClient = AuthClient.getAuthClient() - - init() - - return view - } - - override fun onResume() { - super.onResume() - getStateAndUpdateUI() - } - - private fun init() { - initializeButtonListeners() - } - - private fun initializeButtonListeners() { - binding.signIn.setOnClickListener { - signIn() - } - - binding.signUp.setOnClickListener { - signUp() - } - - binding.signOut.setOnClickListener { - signOut() - } - } - private fun getStateAndUpdateUI() { - CoroutineScope(Dispatchers.Main).launch { - val accountResult = authClient.getCurrentAccount() - when (accountResult) { - is GetAccountResult.AccountFound -> { - displaySignedInState(accountResult.resultValue) - } - is GetAccountResult.NoAccountFound -> { - displaySignedOutState() - } - } - } - } - private fun signIn() { - CoroutineScope(Dispatchers.Main).launch { - try { - val email = binding.emailText.text.toString() - val password = CharArray(binding.passwordText.length()); - binding.passwordText.text?.getChars(0, binding.passwordText.length(), password, 0); - - val actionResult = authClient.signIn( - username = email, - password = password, - scopes = listOf("User.Read") - ) - - password.fill('0'); - - when (actionResult) { - is SignInResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_in_successful_message), - Toast.LENGTH_SHORT - ).show() - displaySignedInState(accountState = actionResult.resultValue) - } - is SignInError -> { - if (actionResult.isBrowserRequired()) { - Toast.makeText(requireContext(), actionResult.errorMessage, Toast.LENGTH_SHORT).show() - - authClient.acquireToken( - AcquireTokenParameters( - AcquireTokenParameters.Builder() - .startAuthorizationFromActivity(requireActivity()) - .withScopes(mutableListOf("profile", "openid", "email")) - .withCallback(getAuthInteractiveCallback()) - ) - ) - } - else { - displayDialog("Unexpected result", actionResult.errorMessage) - } - } - else -> { - displayDialog( "Unexpected result", actionResult.toString()) - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - - private fun signUp() { - CoroutineScope(Dispatchers.Main).launch { - try { - val email = binding.emailText.text.toString() - val password = CharArray(binding.passwordText.length()); - binding.passwordText.text?.getChars(0, binding.passwordText.length(), password, 0); - - val actionResult = authClient.signUp( - username = email, - password = password - ) - - password.fill('0') - - when (actionResult) { - is SignUpResult.CodeRequired -> { - navigateToSignUp( - nextState = actionResult.nextState, - codeLength = actionResult.codeLength, - sentTo = actionResult.sentTo, - channel = actionResult.channel - ) - } - is SignUpResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_up_successful_message), - Toast.LENGTH_SHORT - ).show() - signInAfterSignUp( - nextState = actionResult.nextState - ) - } - else -> { - displayDialog("Unexpected result", actionResult.toString()) - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - - private suspend fun signInAfterSignUp(nextState: SignInContinuationState) { - val currentState = nextState - val actionResult = currentState.signIn() - when (actionResult) { - is SignInResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_in_successful_message), - Toast.LENGTH_SHORT - ).show() - displaySignedInState(accountState = actionResult.resultValue) - } - else -> { - displayDialog("Unexpected result", actionResult.toString()) - } - } - } - private fun signOut() { - CoroutineScope(Dispatchers.Main).launch { - val getAccountResult = authClient.getCurrentAccount() - if (getAccountResult is GetAccountResult.AccountFound) { - val signOutResult = getAccountResult.resultValue.signOut() - if (signOutResult is SignOutResult.Complete) { - Toast.makeText( - requireContext(), - getString(R.string.sign_out_successful_message), - Toast.LENGTH_SHORT - ).show() - displaySignedOutState() - } else { - displayDialog("Unexpected result", signOutResult.toString()) - } - } - } - } - private fun displaySignedInState(accountState: AccountState) { - emptyFields() - updateUI(STATUS.SignedIn) - displayAccount(accountState) - } - - private fun displaySignedOutState() { - emptyFields() - updateUI(STATUS.SignedOut) - emptyResults() - } - private fun updateUI(status: STATUS) { - when (status) { - STATUS.SignedIn -> { - binding.signIn.isEnabled = false - binding.signUp.isEnabled = false - binding.signOut.isEnabled = true - } - STATUS.SignedOut -> { - binding.signIn.isEnabled = true - binding.signUp.isEnabled = true - binding.signOut.isEnabled = false - } - } - } - - private fun emptyFields() { - binding.emailText.setText("") - binding.passwordText.setText("") - } - - private fun emptyResults() { - binding.resultAccessToken.text = "" - binding.resultIdToken.text = "" - } - - private fun displayAccount(accountState: AccountState) { - CoroutineScope(Dispatchers.Main).launch { - val accessTokenState = accountState.getAccessToken() - if (accessTokenState is GetAccessTokenResult.Complete) { - val accessToken = accessTokenState.resultValue.accessToken - binding.resultAccessToken.text = - getString(R.string.result_access_token_text) + accessToken - - val idToken = accountState.getIdToken() - binding.resultIdToken.text = getString(R.string.result_id_token_text) + idToken - } - } - } - - private fun displayDialog(error: String? = null, message: String?) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(error) - .setMessage(message) - val alertDialog = builder.create() - alertDialog.show() - } - - /** - * Callback used for interactive request. - * If succeeds we use the access token to call the Microsoft Graph. - * Does not check cache. - */ - private fun getAuthInteractiveCallback(): AuthenticationCallback { - return object : AuthenticationCallback { - - override fun onSuccess(authenticationResult: IAuthenticationResult) { - /* Successfully got a token, use it to call a protected resource - MSGraph */ - - val accountResult = authenticationResult.account as Account - - /* Update account */ - emptyFields() - updateUI(STATUS.SignedIn) - val idToken = accountResult.idToken - binding.resultIdToken.text = - getString(R.string.result_id_token_text) + idToken - - Toast.makeText(requireContext(), getString(R.string.sign_in_successful_message), Toast.LENGTH_SHORT).show() - } - - override fun onError(exception: MsalException) { - /* Failed to acquireToken */ - displayDialog(getString(R.string.msal_exception_title), exception.errorCode) - } - - override fun onCancel() { - /* User canceled the authentication */ - } - } - } - - private fun navigateToSignUp( - nextState: SignUpCodeRequiredState, - codeLength: Int, - sentTo: String, - channel: String - ) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, nextState) - bundle.putInt(Constants.CODE_LENGTH, codeLength) - bundle.putString(Constants.SENT_TO, sentTo) - bundle.putString(Constants.CHANNEL, channel) - val fragment = SignUpCodeFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/EmailSignInSignUpFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/EmailSignInSignUpFragment.kt deleted file mode 100644 index 0a7b7d4bd4..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/EmailSignInSignUpFragment.kt +++ /dev/null @@ -1,365 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import com.microsoft.identity.client.Account -import com.microsoft.identity.client.AcquireTokenParameters -import com.microsoft.identity.client.AuthenticationCallback -import com.microsoft.identity.client.IAuthenticationResult -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentEmailSisuBinding -import com.microsoft.identity.nativeauth.INativeAuthPublicClientApplication -import com.microsoft.identity.nativeauth.statemachine.errors.SignInError -import com.microsoft.identity.nativeauth.statemachine.results.GetAccessTokenResult -import com.microsoft.identity.nativeauth.statemachine.results.GetAccountResult -import com.microsoft.identity.nativeauth.statemachine.results.SignInResult -import com.microsoft.identity.nativeauth.statemachine.results.SignOutResult -import com.microsoft.identity.nativeauth.statemachine.results.SignUpResult -import com.microsoft.identity.nativeauth.statemachine.states.AccountState -import com.microsoft.identity.nativeauth.statemachine.states.SignInCodeRequiredState -import com.microsoft.identity.nativeauth.statemachine.states.SignInContinuationState -import com.microsoft.identity.nativeauth.statemachine.states.SignUpCodeRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for the email sign up and sign in flow. - */ -class EmailSignInSignUpFragment : Fragment() { - private lateinit var authClient: INativeAuthPublicClientApplication - private var _binding: FragmentEmailSisuBinding? = null - private val binding get() = _binding!! - - companion object { - private enum class STATUS { SignedIn, SignedOut } - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = FragmentEmailSisuBinding.inflate(inflater, container, false) - val view = binding.root - - authClient = AuthClient.getAuthClient() - - init() - - return view - } - - override fun onResume() { - super.onResume() - getStateAndUpdateUI() - } - - private fun init() { - initializeButtonListeners() - } - - private fun initializeButtonListeners() { - binding.signIn.setOnClickListener { - signIn() - } - - binding.signUp.setOnClickListener { - signUp() - } - - binding.signOut.setOnClickListener { - signOut() - } - } - private fun getStateAndUpdateUI() { - CoroutineScope(Dispatchers.Main).launch { - val accountResult = authClient.getCurrentAccount() - when (accountResult) { - is GetAccountResult.AccountFound -> { - displaySignedInState(accountResult.resultValue) - } - is GetAccountResult.NoAccountFound -> { - displaySignedOutState() - } - } - } - } - private fun signIn() { - CoroutineScope(Dispatchers.Main).launch { - try { - val email = binding.emailText.text.toString() - - val actionResult = authClient.signIn( - username = email, - scopes = listOf("User.Read") - ) - - when (actionResult) { - is SignInResult.CodeRequired -> { - navigateToSignIn( - signInstate = actionResult.nextState, - codeLength = actionResult.codeLength, - sentTo = actionResult.sentTo, - channel = actionResult.channel - ) - } - is SignInError -> { - if (actionResult.isBrowserRequired()) { - Toast.makeText(requireContext(), actionResult.errorMessage, Toast.LENGTH_SHORT).show() - - authClient.acquireToken( - AcquireTokenParameters( - AcquireTokenParameters.Builder() - .startAuthorizationFromActivity(requireActivity()) - .withScopes(mutableListOf("profile", "openid", "email")) - .withCallback(getAuthInteractiveCallback()) - ) - ) - } - else { - displayDialog("Unexpected result", actionResult.errorMessage) - } - } - else -> { - displayDialog(getString(R.string.msal_exception_title), "Unexpected result: $actionResult") - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - - private fun signUp() { - CoroutineScope(Dispatchers.Main).launch { - try { - val email = binding.emailText.text.toString() - - val actionResult = authClient.signUp( - username = email - ) - - when (actionResult) { - is SignUpResult.CodeRequired -> { - navigateToSignUp( - nextState = actionResult.nextState, - codeLength = actionResult.codeLength, - sentTo = actionResult.sentTo, - channel = actionResult.channel - ) - } - is SignUpResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_up_successful_message), - Toast.LENGTH_SHORT - ).show() - signInAfterSignUp( - nextState = actionResult.nextState - ) - } - else -> { - displayDialog( "Unexpected result", actionResult.toString()) - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - - private suspend fun signInAfterSignUp(nextState: SignInContinuationState) { - val currentState = nextState - val actionResult = currentState.signIn() - when (actionResult) { - is SignInResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_in_successful_message), - Toast.LENGTH_SHORT - ).show() - displaySignedInState(accountState = actionResult.resultValue) - } - else -> { - displayDialog(getString(R.string.msal_exception_title), "Unexpected result: $actionResult") - } - } - } - private fun signOut() { - CoroutineScope(Dispatchers.Main).launch { - val getAccountResult = authClient.getCurrentAccount() - if (getAccountResult is GetAccountResult.AccountFound) { - val signOutResult = getAccountResult.resultValue.signOut() - if (signOutResult is SignOutResult.Complete) { - Toast.makeText( - requireContext(), - getString(R.string.sign_out_successful_message), - Toast.LENGTH_SHORT - ).show() - displaySignedOutState() - } else { - displayDialog(getString(R.string.msal_exception_title), "Unexpected result: $signOutResult") - } - } - } - } - private fun displaySignedInState(accountState: AccountState) { - emptyFields() - updateUI(STATUS.SignedIn) - displayAccount(accountState) - } - - private fun displaySignedOutState() { - emptyFields() - updateUI(STATUS.SignedOut) - emptyResults() - } - - private fun updateUI(status: STATUS) { - when (status) { - STATUS.SignedIn -> { - binding.signIn.isEnabled = false - binding.signUp.isEnabled = false - binding.signOut.isEnabled = true - } - STATUS.SignedOut -> { - binding.signIn.isEnabled = true - binding.signUp.isEnabled = true - binding.signOut.isEnabled = false - } - } - } - - private fun emptyFields() { - binding.emailText.setText(/* text = */ "") - } - - private fun emptyResults() { - binding.resultAccessToken.text = "" - binding.resultIdToken.text = "" - } - private fun displayAccount(accountState: AccountState) { - CoroutineScope(Dispatchers.Main).launch { - val accessTokenState = accountState.getAccessToken() - if (accessTokenState is GetAccessTokenResult.Complete) { - val accessToken = accessTokenState.resultValue.accessToken - binding.resultAccessToken.text = - getString(R.string.result_access_token_text) + accessToken - - val idToken = accountState.getIdToken() - binding.resultIdToken.text = getString(R.string.result_id_token_text) + idToken - } - } - } - private fun displayDialog(error: String? = null, message: String?) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(error) - .setMessage(message) - val alertDialog = builder.create() - alertDialog.show() - } - - private fun navigateToSignIn( - signInstate: SignInCodeRequiredState, - codeLength: Int, - sentTo: String, - channel: String - ) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, signInstate) - bundle.putInt(Constants.CODE_LENGTH, codeLength) - bundle.putString(Constants.SENT_TO, sentTo) - bundle.putString(Constants.CHANNEL, channel) - val fragment = SignInCodeFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } - - private fun navigateToSignUp( - nextState: SignUpCodeRequiredState, - codeLength: Int, - sentTo: String, - channel: String - ) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, nextState) - bundle.putInt(Constants.CODE_LENGTH, codeLength) - bundle.putString(Constants.SENT_TO, sentTo) - bundle.putString(Constants.CHANNEL, channel) - val fragment = SignUpCodeFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } - - /** - * Callback used for interactive request. - * If succeeds we use the access token to call the Microsoft Graph. - * Does not check cache. - */ - private fun getAuthInteractiveCallback(): AuthenticationCallback { - return object : AuthenticationCallback { - - override fun onSuccess(authenticationResult: IAuthenticationResult) { - /* Successfully got a token, use it to call a protected resource - MSGraph */ - - val accountResult = authenticationResult.account as Account - - /* Update account */ - emptyFields() - updateUI(STATUS.SignedIn) - val idToken = accountResult.idToken - binding.resultIdToken.text = - getString(R.string.result_id_token_text) + idToken - - Toast.makeText(requireContext(), getString(R.string.sign_in_successful_message), Toast.LENGTH_SHORT).show() - } - - override fun onError(exception: MsalException) { - /* Failed to acquireToken */ - displayDialog(getString(R.string.msal_exception_title), exception.errorCode) - } - - override fun onCancel() { - /* User canceled the authentication */ - } - } - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/PasswordResetCodeFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/PasswordResetCodeFragment.kt deleted file mode 100644 index f4804a7c74..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/PasswordResetCodeFragment.kt +++ /dev/null @@ -1,144 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentCodeBinding -import com.microsoft.identity.nativeauth.statemachine.results.ResetPasswordResendCodeResult -import com.microsoft.identity.nativeauth.statemachine.results.ResetPasswordSubmitCodeResult -import com.microsoft.identity.nativeauth.statemachine.states.ResetPasswordCodeRequiredState -import com.microsoft.identity.nativeauth.statemachine.states.ResetPasswordPasswordRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for managing the code step in the reset password flow. - */ -class PasswordResetCodeFragment : Fragment() { - private lateinit var currentState: ResetPasswordCodeRequiredState - private var _binding: FragmentCodeBinding? = null - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = FragmentCodeBinding.inflate(inflater, container, false) - val view = binding.root - - val bundle = this.arguments - currentState = bundle!!.getSerializable(Constants.STATE) as ResetPasswordCodeRequiredState - - init() - - return view - } - - private fun init() { - initializeButtonListeners() - } - - private fun initializeButtonListeners() { - binding.verifyCode.setOnClickListener { - submitCode() - } - - binding.resendCodeText.setOnClickListener { - resendCode() - } - } - - private fun submitCode() { - CoroutineScope(Dispatchers.Main).launch { - try { - val code = binding.codeText.text.toString() - - val actionResult = currentState.submitCode(code) - - when (actionResult) { - is ResetPasswordSubmitCodeResult.PasswordRequired -> { - navigateToResetPasswordPasswordFragment( - nextState = actionResult.nextState - ) - } - else -> { - displayDialog(getString(R.string.msal_exception_title), "Unexpected result: $actionResult") - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - - private fun resendCode() { - clearCode() - - CoroutineScope(Dispatchers.Main).launch { - val actionResult = currentState.resendCode() - - when (actionResult) { - is ResetPasswordResendCodeResult.Success -> { - currentState = actionResult.nextState - Toast.makeText(requireContext(), getString(R.string.resend_code_message), Toast.LENGTH_LONG).show() - } - else -> { - displayDialog(getString(R.string.msal_exception_title), "Unexpected result: $actionResult") - } - } - } - } - - private fun clearCode() { - binding.codeText.text?.clear() - } - - private fun displayDialog(error: String?, message: String?) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(error) - .setMessage(message) - val alertDialog = builder.create() - alertDialog.show() - } - - private fun navigateToResetPasswordPasswordFragment(nextState: ResetPasswordPasswordRequiredState) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, nextState) - val fragment = PasswordResetNewPasswordFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/PasswordResetFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/PasswordResetFragment.kt deleted file mode 100644 index bdf502552c..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/PasswordResetFragment.kt +++ /dev/null @@ -1,209 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentEmailSsprBinding -import com.microsoft.identity.nativeauth.INativeAuthPublicClientApplication -import com.microsoft.identity.nativeauth.statemachine.results.GetAccessTokenResult -import com.microsoft.identity.nativeauth.statemachine.results.GetAccountResult -import com.microsoft.identity.nativeauth.statemachine.results.ResetPasswordStartResult -import com.microsoft.identity.nativeauth.statemachine.results.SignOutResult -import com.microsoft.identity.nativeauth.statemachine.states.AccountState -import com.microsoft.identity.nativeauth.statemachine.states.ResetPasswordCodeRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for initiating the reset password flow. - */ -class PasswordResetFragment : Fragment() { - private lateinit var authClient: INativeAuthPublicClientApplication - private var _binding: FragmentEmailSsprBinding? = null - private val binding get() = _binding!! - - companion object { - private enum class STATUS { SignedIn, SignedOut } - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = FragmentEmailSsprBinding.inflate(inflater, container, false) - val view = binding.root - - authClient = AuthClient.getAuthClient() - - init() - - return view - } - - override fun onResume() { - super.onResume() - getStateAndUpdateUI() - } - - private fun init() { - initializeButtonListeners() - } - - private fun initializeButtonListeners() { - binding.forgetPassword.setOnClickListener { - forgetPassword() - } - - binding.signOut.setOnClickListener { - signOut() - } - } - private fun getStateAndUpdateUI() { - CoroutineScope(Dispatchers.Main).launch { - val accountResult = authClient.getCurrentAccount() - when (accountResult) { - is GetAccountResult.AccountFound -> { - displaySignedInState(accountResult.resultValue) - } - is GetAccountResult.NoAccountFound -> { - displaySignedOutState() - } - } - } - } - private fun forgetPassword() { - CoroutineScope(Dispatchers.Main).launch { - try { - val email = binding.emailText.text.toString() - - val actionResult = authClient.resetPassword( - username = email - ) - when (actionResult) { - is ResetPasswordStartResult.CodeRequired -> { - navigateToResetPasswordCodeFragment( - nextState = actionResult.nextState - ) - } - else -> { - displayDialog(getString(R.string.msal_exception_title), "Unexpected result: $actionResult") - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - - private fun signOut() { - CoroutineScope(Dispatchers.Main).launch { - val getAccountResult = authClient.getCurrentAccount() - if (getAccountResult is GetAccountResult.AccountFound) { - val signOutResult = getAccountResult.resultValue.signOut() - if (signOutResult is SignOutResult.Complete) { - Toast.makeText( - requireContext(), - getString(R.string.sign_out_successful_message), - Toast.LENGTH_SHORT - ).show() - displaySignedOutState() - } else { - displayDialog("Unexpected result", signOutResult.toString()) - } - } - } - } - private fun displaySignedInState(accountState: AccountState) { - emptyFields() - updateUI(STATUS.SignedIn) - displayAccount(accountState) - } - private fun displaySignedOutState() { - emptyFields() - updateUI(STATUS.SignedOut) - emptyResults() - } - - private fun updateUI(status: STATUS) { - when (status) { - STATUS.SignedIn -> { - binding.forgetPassword.isEnabled = false - binding.signOut.isEnabled = true - } - STATUS.SignedOut -> { - binding.forgetPassword.isEnabled = true - binding.signOut.isEnabled = false - } - } - } - - private fun emptyFields() { - binding.emailText.setText("") - } - - private fun emptyResults() { - binding.resultAccessToken.text = "" - binding.resultIdToken.text = "" - } - - private fun displayAccount(accountState: AccountState) { - CoroutineScope(Dispatchers.Main).launch { - val accessTokenState = accountState.getAccessToken() - if (accessTokenState is GetAccessTokenResult.Complete) { - val accessToken = accessTokenState.resultValue.accessToken - binding.resultAccessToken.text = - getString(R.string.result_access_token_text) + accessToken - - val idToken = accountState.getIdToken() - binding.resultIdToken.text = getString(R.string.result_id_token_text) + idToken - } - } - } - private fun displayDialog(error: String?, message: String?) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(error) - .setMessage(message) - val alertDialog = builder.create() - alertDialog.show() - } - private fun navigateToResetPasswordCodeFragment(nextState: ResetPasswordCodeRequiredState) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, nextState) - val fragment = PasswordResetCodeFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/PasswordResetNewPasswordFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/PasswordResetNewPasswordFragment.kt deleted file mode 100644 index 69a5f95700..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/PasswordResetNewPasswordFragment.kt +++ /dev/null @@ -1,115 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentPasswordBinding -import com.microsoft.identity.nativeauth.statemachine.results.ResetPasswordResult -import com.microsoft.identity.nativeauth.statemachine.states.ResetPasswordPasswordRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for setting the new password in the reset password flow. - */ -class PasswordResetNewPasswordFragment : Fragment() { - private lateinit var currentState: ResetPasswordPasswordRequiredState - private var _binding: FragmentPasswordBinding? = null - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = FragmentPasswordBinding.inflate(inflater, container, false) - val view = binding.root - - val bundle = this.arguments - currentState = bundle!!.getSerializable(Constants.STATE) as ResetPasswordPasswordRequiredState - - init() - - return view - } - - private fun init() { - initializeButtonListener() - } - - private fun initializeButtonListener() { - binding.submitPassword.setOnClickListener { - resetPassword() - } - } - - private fun resetPassword() { - CoroutineScope(Dispatchers.Main).launch { - try { - val password = CharArray(binding.passwordText.length()); - binding.passwordText.text?.getChars(0, binding.passwordText.length(), password, 0); - - val actionResult = currentState.submitPassword(password) - - password.fill('0') - - when (actionResult) { - is ResetPasswordResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.password_reset_success_message), - Toast.LENGTH_LONG - ).show() - finish() - } - else -> { - displayDialog(getString(R.string.msal_exception_title),"Unexpected result: $actionResult") - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - - private fun displayDialog(error: String?, message: String?) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(error) - .setMessage(message) - val alertDialog = builder.create() - alertDialog.show() - } - private fun finish() { - val fragmentManager = requireActivity().supportFragmentManager - val name: String? = fragmentManager.getBackStackEntryAt(0).name - fragmentManager.popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE) - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignInCodeFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignInCodeFragment.kt deleted file mode 100644 index 63dfdd2ec9..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignInCodeFragment.kt +++ /dev/null @@ -1,141 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentCodeBinding -import com.microsoft.identity.nativeauth.statemachine.results.SignInResendCodeResult -import com.microsoft.identity.nativeauth.statemachine.results.SignInResult -import com.microsoft.identity.nativeauth.statemachine.states.SignInCodeRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for managing the code step in the sign in flow. - */ -class SignInCodeFragment : Fragment() { - private lateinit var currentState: SignInCodeRequiredState - private var codeLength: Int? = null - private var sentTo: String? = null - private var channel: String? = null - private var _binding: FragmentCodeBinding? = null - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = FragmentCodeBinding.inflate(inflater, container, false) - - val bundle = this.arguments - currentState = (bundle?.getParcelable(Constants.STATE) as? SignInCodeRequiredState)!! - codeLength = bundle.getInt(Constants.CODE_LENGTH) - sentTo = bundle.getString(Constants.SENT_TO) - channel = bundle.getString(Constants.CHANNEL) - - init() - - return binding.root - } - - private fun init() { - initializeButtonListeners() - binding.codeHint.text = "Code sent to ${sentTo}, by ${channel}, with length ${codeLength}}" - } - - private fun initializeButtonListeners() { - binding.verifyCode.setOnClickListener { - verifyCode() - } - - binding.resendCodeText.setOnClickListener { - resendCode() - } - } - - private fun verifyCode() { - CoroutineScope(Dispatchers.Main).launch { - try { - val emailCode = binding.codeText.text.toString() - - val actionResult = currentState.submitCode(emailCode) - - when (actionResult) { - is SignInResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_in_successful_message), - Toast.LENGTH_SHORT - ).show() - finish() - } - else -> { - displayDialog(getString(R.string.msal_exception_title),"Unexpected result: $actionResult") - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - - private fun resendCode() { - clearCode() - - CoroutineScope(Dispatchers.Main).launch { - val actionResult = currentState.resendCode() - - when (actionResult) { - is SignInResendCodeResult.Success -> { - currentState = actionResult.nextState - Toast.makeText(requireContext(), getString(R.string.resend_code_message), Toast.LENGTH_LONG).show() - } - else -> { - displayDialog(getString(R.string.msal_exception_title),"Unexpected result: $actionResult") - } - } - } - } - - private fun clearCode() { - binding.codeText.text?.clear() - } - private fun displayDialog(error: String?, message: String?) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(error) - .setMessage(message) - val alertDialog = builder.create() - alertDialog.show() - } - private fun finish() { - requireActivity().supportFragmentManager.popBackStackImmediate() - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignUpAttributesFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignUpAttributesFragment.kt deleted file mode 100644 index 9ff0748ac1..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignUpAttributesFragment.kt +++ /dev/null @@ -1,159 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentAttributeBinding -import com.microsoft.identity.nativeauth.UserAttributes -import com.microsoft.identity.nativeauth.statemachine.results.SignInResult -import com.microsoft.identity.nativeauth.statemachine.results.SignUpResult -import com.microsoft.identity.nativeauth.statemachine.states.SignInContinuationState -import com.microsoft.identity.nativeauth.statemachine.states.SignUpAttributesRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for submitting attributes in the sign up flow. This Fragment is used in a scenario - * where attributes are submitted after setting the code and/or password. - */ -class SignUpAttributesFragment : Fragment() { - private lateinit var currentState: SignUpAttributesRequiredState - private var _binding: FragmentAttributeBinding? = null - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = FragmentAttributeBinding.inflate(inflater, container, false) - - val bundle = this.arguments - currentState = (bundle?.getParcelable(Constants.STATE) as? SignUpAttributesRequiredState)!! - - init() - - return binding.root - } - - private fun init() { - initializeButtonListeners() - } - - private fun initializeButtonListeners() { - binding.submitAttributes.setOnClickListener { - create() - } - } - - private fun create() { - CoroutineScope(Dispatchers.Main).launch { - try { - val attributes = UserAttributes.Builder() - - val attr1Key = binding.attr1KeyText.text.toString() - val attr1Value = binding.attr1ValueText.text.toString() - attributes.customAttribute(attr1Key, attr1Value) - - val attr2Key = binding.attr2KeyText.text.toString() - val attr2Value = binding.attr2ValueText.text.toString() - attributes.customAttribute(attr2Key, attr2Value) - - val actionResult = currentState.submitAttributes(attributes.build()) - - when (actionResult) { - is SignUpResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_up_successful_message), - Toast.LENGTH_SHORT - ).show() - signInAfterSignUp(actionResult.nextState) - } - is SignUpResult.AttributesRequired -> { - navigateToAttributes( - nextState = actionResult.nextState - ) - } - else -> { - displayDialog(getString(R.string.msal_exception_title),"Unexpected result: $actionResult") - } - } - } catch (exception: MsalException) { - displayDialog(getString(R.string.msal_exception_title), exception.message.toString()) - } - } - } - private fun displayDialog(error: String?, message: String?) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(error) - .setMessage(message) - val alertDialog = builder.create() - alertDialog.show() - } - - private fun navigateToAttributes(nextState: SignUpAttributesRequiredState) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, nextState) - val fragment = SignUpAttributesFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } - private suspend fun signInAfterSignUp(nextState: SignInContinuationState) { - val currentState = nextState - val actionResult = currentState.signIn(null) - when (actionResult) { - is SignInResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_in_successful_message), - Toast.LENGTH_SHORT - ).show() - finish() - } - else -> { - displayDialog(getString(R.string.msal_exception_title),"Unexpected result: $actionResult") - } - } - } - - private fun finish() { - val fragmentManager = requireActivity().supportFragmentManager - val name: String? = fragmentManager.getBackStackEntryAt(0).name - fragmentManager.popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE) - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignUpCodeFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignUpCodeFragment.kt deleted file mode 100644 index 0f694aee7d..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignUpCodeFragment.kt +++ /dev/null @@ -1,218 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentCodeBinding -import com.microsoft.identity.nativeauth.statemachine.errors.SubmitCodeError -import com.microsoft.identity.nativeauth.statemachine.results.SignInResult -import com.microsoft.identity.nativeauth.statemachine.results.SignUpResendCodeResult -import com.microsoft.identity.nativeauth.statemachine.results.SignUpResult -import com.microsoft.identity.nativeauth.statemachine.states.SignInCodeRequiredState -import com.microsoft.identity.nativeauth.statemachine.states.SignInContinuationState -import com.microsoft.identity.nativeauth.statemachine.states.SignUpAttributesRequiredState -import com.microsoft.identity.nativeauth.statemachine.states.SignUpCodeRequiredState -import com.microsoft.identity.nativeauth.statemachine.states.SignUpPasswordRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for managing the code step in the sign up flow. - */ -class SignUpCodeFragment : Fragment() { - private lateinit var currentState: SignUpCodeRequiredState - private var codeLength: Int? = null - private var sentTo: String? = null - private var channel: String? = null - private var _binding: FragmentCodeBinding? = null - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = FragmentCodeBinding.inflate(inflater, container, false) - - val bundle = this.arguments - currentState = (bundle?.getParcelable(Constants.STATE) as? SignUpCodeRequiredState)!! - codeLength = bundle.getInt(Constants.CODE_LENGTH) - sentTo = bundle.getString(Constants.SENT_TO) - channel = bundle.getString(Constants.CHANNEL) - - init() - - return binding.root - } - - private fun init() { - initializeButtonListeners() - binding.codeHint.text = "Code sent to ${sentTo}, by ${channel}, with length ${codeLength}}" - } - - private fun initializeButtonListeners() { - binding.verifyCode.setOnClickListener { - verifyCode() - } - - binding.resendCodeText.setOnClickListener { - resendCode() - } - } - - private fun verifyCode() { - CoroutineScope(Dispatchers.Main).launch { - try { - val oobCode = binding.codeText.text.toString() - - val actionResult = currentState.submitCode(oobCode) - - when (actionResult) { - is SignUpResult.Complete -> { - Toast.makeText(requireContext(), getString(R.string.sign_up_successful_message), Toast.LENGTH_SHORT).show() - signInAfterSignUp( - nextState = actionResult.nextState - ) - } - is SubmitCodeError -> { - if (actionResult.isInvalidCode()) { - Toast.makeText( - requireContext(), - actionResult.errorMessage, - Toast.LENGTH_SHORT - ).show() - clearCode() - } else { - displayError("Unexpected result: $actionResult") - } - } - is SignUpResult.AttributesRequired -> { - navigateToAttributes( - nextState = actionResult.nextState - ) - } - is SignUpResult.PasswordRequired -> { - navigateToPassword( - nextState = actionResult.nextState - ) - } - else -> { - displayError("Unexpected result: $actionResult") - } - } - } catch (exception: MsalException) { - displayError(exception.message.toString()) - } - } - } - - private suspend fun signInAfterSignUp(nextState: SignInContinuationState) { - val currentState = nextState - val actionResult = currentState.signIn(null) - when (actionResult) { - is SignInResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_in_successful_message), - Toast.LENGTH_SHORT - ).show() - finish() - } - else -> { - displayError("Unexpected result: $actionResult") - } - } - } - - private fun resendCode() { - clearCode() - - CoroutineScope(Dispatchers.Main).launch { - try { - val actionResult = currentState.resendCode() - - when (actionResult) { - is SignUpResendCodeResult.Success -> { - currentState = actionResult.nextState - Toast.makeText(requireContext(), getString(R.string.resend_code_message), Toast.LENGTH_LONG).show() - } - else -> { - displayError("Unexpected result: $actionResult") - } - } - } catch (exception: MsalException) { - displayError(exception.message.toString()) - } - } - } - - private fun clearCode() { - binding.codeText.text?.clear() - } - - private fun displayError(errorMsg: String) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(getString(R.string.msal_exception_title)) - .setMessage(errorMsg) - val alertDialog = builder.create() - alertDialog.show() - } - - private fun finish() { - requireActivity().supportFragmentManager.popBackStackImmediate() - } - - private fun navigateToAttributes(nextState: SignUpAttributesRequiredState) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, nextState) - val fragment = SignUpAttributesFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } - - private fun navigateToPassword(nextState: SignUpPasswordRequiredState) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, nextState) - val fragment = SignUpPasswordFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } -} diff --git a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignUpPasswordFragment.kt b/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignUpPasswordFragment.kt deleted file mode 100644 index 5c87a65f63..0000000000 --- a/testapps/testapp/src/main/java/com/microsoft/identity/client/testapp/nativeauth/SignUpPasswordFragment.kt +++ /dev/null @@ -1,154 +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.client.testapp.nativeauth - -import android.app.AlertDialog -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import com.microsoft.identity.client.exception.MsalException -import com.microsoft.identity.client.testapp.Constants -import com.microsoft.identity.client.testapp.R -import com.microsoft.identity.client.testapp.databinding.FragmentPasswordBinding -import com.microsoft.identity.nativeauth.statemachine.results.SignInResult -import com.microsoft.identity.nativeauth.statemachine.results.SignUpResult -import com.microsoft.identity.nativeauth.statemachine.states.SignInContinuationState -import com.microsoft.identity.nativeauth.statemachine.states.SignUpAttributesRequiredState -import com.microsoft.identity.nativeauth.statemachine.states.SignUpPasswordRequiredState -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch - -/** - * Fragment used for managing the password in the sign up flow. - */ -class SignUpPasswordFragment : Fragment() { - private lateinit var currentState: SignUpPasswordRequiredState - private var _binding: FragmentPasswordBinding? = null - private val binding get() = _binding!! - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = FragmentPasswordBinding.inflate(inflater, container, false) - - val bundle = this.arguments - currentState = (bundle?.getParcelable(Constants.STATE) as? SignUpPasswordRequiredState)!! - - init() - - return binding.root - } - - private fun init() { - initializeButtonListeners() - } - - private fun initializeButtonListeners() { - binding.submitPassword.setOnClickListener { - submitPassword() - } - } - - private fun submitPassword() { - CoroutineScope(Dispatchers.Main).launch { - try { - val password = CharArray(binding.passwordText.length()); - binding.passwordText.text?.getChars(0, binding.passwordText.length(), password, 0); - - val actionResult = currentState.submitPassword(password) - - password.fill('0'); - - when (actionResult) { - is SignUpResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_up_successful_message), - Toast.LENGTH_SHORT - ).show() - signInAfterSignUp(actionResult.nextState) - } - is SignUpResult.AttributesRequired -> { - navigateToAttributes( - actionResult.nextState - ) - } - else -> { - displayError("Unexpected result: $actionResult") - } - } - } catch (exception: MsalException) { - displayError(exception.message.toString()) - } - } - } - - private fun displayError(errorMsg: String) { - val builder = AlertDialog.Builder(requireContext()) - builder.setTitle(getString(R.string.msal_exception_title)) - .setMessage(errorMsg) - val alertDialog = builder.create() - alertDialog.show() - } - - private suspend fun signInAfterSignUp(nextState: SignInContinuationState) { - val currentState = nextState - val actionResult = currentState.signIn(null) - when (actionResult) { - is SignInResult.Complete -> { - Toast.makeText( - requireContext(), - getString(R.string.sign_in_successful_message), - Toast.LENGTH_SHORT - ).show() - finish() - } - else -> { - displayError("Unexpected result: $actionResult") - } - } - } - - private fun finish() { - val fragmentManager = requireActivity().supportFragmentManager - val name: String? = fragmentManager.getBackStackEntryAt(0).name - fragmentManager.popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE) - } - - private fun navigateToAttributes(nextState: SignUpAttributesRequiredState) { - val bundle = Bundle() - bundle.putParcelable(Constants.STATE, nextState) - val fragment = SignUpAttributesFragment() - fragment.arguments = bundle - - requireActivity().supportFragmentManager - .beginTransaction() - .setReorderingAllowed(true) - .addToBackStack(fragment::class.java.name) - .replace(R.id.scenario_fragment, fragment) - .commit() - } -} diff --git a/testapps/testapp/src/main/res/drawable/ic_baseline_email_24.xml b/testapps/testapp/src/main/res/drawable/ic_baseline_email_24.xml deleted file mode 100644 index a92c2dfd88..0000000000 --- a/testapps/testapp/src/main/res/drawable/ic_baseline_email_24.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/testapps/testapp/src/main/res/drawable/ic_baseline_lock_reset_24.xml b/testapps/testapp/src/main/res/drawable/ic_baseline_lock_reset_24.xml deleted file mode 100644 index 3bac2e66c8..0000000000 --- a/testapps/testapp/src/main/res/drawable/ic_baseline_lock_reset_24.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/testapps/testapp/src/main/res/drawable/ic_baseline_remove_red_eye_24.xml b/testapps/testapp/src/main/res/drawable/ic_baseline_remove_red_eye_24.xml deleted file mode 100644 index fc32883937..0000000000 --- a/testapps/testapp/src/main/res/drawable/ic_baseline_remove_red_eye_24.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/testapps/testapp/src/main/res/drawable/ic_baseline_text_snippet_24.xml b/testapps/testapp/src/main/res/drawable/ic_baseline_text_snippet_24.xml deleted file mode 100644 index 7913f6d909..0000000000 --- a/testapps/testapp/src/main/res/drawable/ic_baseline_text_snippet_24.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/testapps/testapp/src/main/res/drawable/side_nav_bar.xml b/testapps/testapp/src/main/res/drawable/side_nav_bar.xml index 8829a0f6f4..bbb8b0a6c6 100644 --- a/testapps/testapp/src/main/res/drawable/side_nav_bar.xml +++ b/testapps/testapp/src/main/res/drawable/side_nav_bar.xml @@ -6,4 +6,4 @@ android:endColor="#2e367d" android:startColor="#8188c7" android:type="linear" /> - + \ No newline at end of file diff --git a/testapps/testapp/src/main/res/layout/fragment_attribute.xml b/testapps/testapp/src/main/res/layout/fragment_attribute.xml deleted file mode 100644 index c387c53965..0000000000 --- a/testapps/testapp/src/main/res/layout/fragment_attribute.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -