diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7a3601b0e3b7dcc6881020733acfa8fa52ad594d..f9934458fa6c5cc4a686c4bf80221cf6a2ecd7b2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,9 @@ stages: before_script: - echo email.key=$PEPPER >> local.properties + - echo MURENA_CLIENT_ID=$MURENA_CLIENT_ID >> local.properties + - echo MURENA_CLIENT_SECRET=$MURENA_CLIENT_SECRET >> local.properties + - echo MURENA_REDIRECT_URI=$MURENA_REDIRECT_URI >> local.properties - echo GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID >> local.properties - echo GOOGLE_REDIRECT_URI=$GOOGLE_REDIRECT_URI >> local.properties - echo YAHOO_CLIENT_ID=$YAHOO_CLIENT_ID >> local.properties diff --git a/app/build.gradle b/app/build.gradle index 1a900b11a777a22ae344e2c2b1f650205091ed9e..6418c44c0ba5565b784d8e0b4720470149eb9acb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -108,6 +108,10 @@ android { } defaultConfig { + buildConfigField "String", "MURENA_CLIENT_ID", "\"${retrieveKey("MURENA_CLIENT_ID")}\"" + buildConfigField "String", "MURENA_CLIENT_SECRET", "\"${retrieveKey("MURENA_CLIENT_SECRET")}\"" + buildConfigField "String", "MURENA_REDIRECT_URI", "\"${retrieveKey("MURENA_REDIRECT_URI")}\"" + buildConfigField "String", "GOOGLE_CLIENT_ID", "\"${retrieveKey("GOOGLE_CLIENT_ID")}\"" buildConfigField "String", "GOOGLE_REDIRECT_URI", "\"${retrieveKey("GOOGLE_REDIRECT_URI")}\"" @@ -115,7 +119,8 @@ android { manifestPlaceholders = [ 'appAuthRedirectScheme': applicationId, - "googleAuthRedirectScheme": retrieveKey("GOOGLE_REDIRECT_URI") + "googleAuthRedirectScheme": retrieveKey("GOOGLE_REDIRECT_URI"), + "murenaAuthRedirectScheme": retrieveKey("MURENA_REDIRECT_URI") ] } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fd66593b2d4d009d1af3d7ecd79ddab4f8d08b82..24a70afbfa21c93fc2b7e00eb1229a25ad5e7f2f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -675,6 +675,7 @@ + diff --git a/app/src/main/java/at/bitfire/davdroid/authorization/IdentityProvider.java b/app/src/main/java/at/bitfire/davdroid/authorization/IdentityProvider.java index 3e25ddd2de4e720f9e1ecc4607ac97dae78b5caf..c4bd3d78d1899f7994cb75079d3920b7e1228d55 100644 --- a/app/src/main/java/at/bitfire/davdroid/authorization/IdentityProvider.java +++ b/app/src/main/java/at/bitfire/davdroid/authorization/IdentityProvider.java @@ -33,6 +33,17 @@ import at.bitfire.davdroid.BuildConfig; */ public class IdentityProvider { + public static final IdentityProvider MURENA = new IdentityProvider( + "https://accounts.eeo.one/auth/realms/eeo.one/.well-known/openid-configuration", + null, + null, + BuildConfig.MURENA_CLIENT_ID, + BuildConfig.MURENA_CLIENT_SECRET, + BuildConfig.MURENA_REDIRECT_URI + ":/redirect", + "openid address profile email phone roles offline_access web-origins microprofile-jwt", + null + ); + public static final IdentityProvider GOOGLE = new IdentityProvider( "https://accounts.google.com/.well-known/openid-configuration", null, diff --git a/app/src/main/java/at/bitfire/davdroid/network/HttpClient.kt b/app/src/main/java/at/bitfire/davdroid/network/HttpClient.kt index 4cd6b08e46b2c5b0e9872808a6868aa41cdd8b3f..9b85b6ab17f0ab142af36eb9fee8a078e57b502f 100644 --- a/app/src/main/java/at/bitfire/davdroid/network/HttpClient.kt +++ b/app/src/main/java/at/bitfire/davdroid/network/HttpClient.kt @@ -156,10 +156,9 @@ class HttpClient private constructor( } // use account settings for authentication and cookies - if (accountSettings != null) - addAuthentication(null, accountSettings.credentials(), authStateCallback = { authState: AuthState -> - accountSettings.credentials(Credentials(authState = authState)) - }) + if (accountSettings != null) { + addAuthentication(accountSettings) + } } constructor(context: Context, host: String?, credentials: Credentials?) : this(context) { @@ -167,6 +166,30 @@ class HttpClient private constructor( addAuthentication(host, credentials) } + private fun addAuthentication(accountSettings: AccountSettings) { + val credential = accountSettings.credentials() + + addAuthentication( + null, + credential, + authStateCallback = { authState: AuthState -> + updateCredentials(accountSettings, authState, credential.clientSecret) + }) + } + + private fun updateCredentials( + accountSettings: AccountSettings, + authState: AuthState, + clientSecret: String? + ) { + accountSettings.credentials( + Credentials( + authState = authState, + clientSecret = clientSecret + ) + ) + } + fun addAuthentication(host: String?, credentials: Credentials, insecurePreemptive: Boolean = false, authStateCallback: BearerAuthInterceptor.AuthStateUpdateCallback? = null): Builder { if (credentials.userName != null && credentials.password != null) { val authHandler = BasicDigestAuthHandler(UrlUtils.hostToDomain(host), credentials.userName, credentials.password, insecurePreemptive) diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountUtils.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountUtils.kt index cbe2ba8ebdf6e33c8cbb04fb4fbf510a8c15fb1d..22ebaf52938ff06cce0dba3b908f9d64fb0ceab6 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountUtils.kt +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/AccountUtils.kt @@ -111,6 +111,7 @@ object AccountUtils { fun getOpenIdMainAccountTypes(context: Context) = listOf( + context.getString(R.string.eelo_account_type), context.getString(R.string.google_account_type), context.getString(R.string.yahoo_account_type) ) diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/DefaultAccountAuthenticatorService.kt b/app/src/main/java/at/bitfire/davdroid/syncadapter/DefaultAccountAuthenticatorService.kt index e31e04345b60d1d6b58b4b57ba775bd5f1336115..cc19d2dfa086f3be63a4e23adfeb1f0cc8c893bd 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/DefaultAccountAuthenticatorService.kt +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/DefaultAccountAuthenticatorService.kt @@ -143,6 +143,11 @@ abstract class DefaultAccountAuthenticatorService : Service(), OnAccountsUpdateL LoginActivity.OPEN_APP_ACTIVITY_AFTER_AUTH, it.getString(LoginActivity.OPEN_APP_ACTIVITY_AFTER_AUTH) ) + + intent.putExtra( + LoginActivity.USERNAME_HINT, + it.getString(LoginActivity.USERNAME_HINT) + ) } val bundle = Bundle(1) @@ -210,6 +215,11 @@ abstract class DefaultAccountAuthenticatorService : Service(), OnAccountsUpdateL AccountSettings.KEY_AUTH_STATE, authState.jsonSerializeString() ) + accountManager.setUserData( + account, + AccountSettings.KEY_CLIENT_SECRET, + clientSecretString + ) val result = Bundle() result.putString(AccountManager.KEY_ACCOUNT_NAME, account!!.name) result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type) diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt index 747b0310c1b18d5f6712960cdbf20075450389a0..343ae97ef91c7be0b3409c49200595348de4d0b4 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.kt @@ -279,14 +279,8 @@ class AccountDetailsFragment : Fragment() { val accountManager = AccountManager.get(context) if (!AccountUtils.createAccount(context, account, userData, credentials?.password)) { - if (accountType in AccountUtils.getOpenIdMainAccountTypes(context)) { - for (openIdAccount in AccountUtils.getOpenIdMainAccounts(context)) { - if (userData.get(AccountSettings.KEY_EMAIL_ADDRESS) == accountManager - .getUserData(account, AccountSettings.KEY_EMAIL_ADDRESS)) { - accountManager.setUserData(openIdAccount, AccountSettings.KEY_AUTH_STATE, - userData.getString(AccountSettings.KEY_AUTH_STATE)) - } - } + if (accountType in AccountUtils.getOpenIdMainAccountTypes(context) && credentials?.authState != null) { + updateAuthState(userData, accountManager, account) } else { result.postValue(false) return@launch @@ -383,6 +377,27 @@ class AccountDetailsFragment : Fragment() { return result } + private fun updateAuthState( + userData: Bundle, + accountManager: AccountManager, + account: Account + ) { + for (openIdAccount in AccountUtils.getOpenIdMainAccounts(context)) { + if (userData.get(AccountSettings.KEY_EMAIL_ADDRESS) == accountManager + .getUserData(account, AccountSettings.KEY_EMAIL_ADDRESS) + ) { + accountManager.setUserData( + openIdAccount, AccountSettings.KEY_AUTH_STATE, + userData.getString(AccountSettings.KEY_AUTH_STATE) + ) + accountManager.setUserData( + openIdAccount, AccountSettings.KEY_CLIENT_SECRET, + userData.getString(AccountSettings.KEY_CLIENT_SECRET) + ) + } + } + } + private fun insertService( accountName: String, authState: String?, diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/DetectConfigurationFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/DetectConfigurationFragment.kt index c5286e67cfc56dc6eb0db624c273feb5e0df0bf4..92114462c591cc8ef88f598159f127d8a15182a7 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/DetectConfigurationFragment.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/DetectConfigurationFragment.kt @@ -47,11 +47,11 @@ class DetectConfigurationFragment: Fragment() { return } - val isMurenaAccountType = (accountType == getString(R.string.eelo_account_type)) + val blockOnUnauthorizedException = (accountType == getString(R.string.eelo_account_type)) && !EeloAuthenticatorModel.enableOpenIdSupport val baseURI = loginModel.baseURI ?: return - model.detectConfiguration(baseURI, loginModel.credentials, loginModel.cardDavURI, isMurenaAccountType).observe(this) { result -> + model.detectConfiguration(baseURI, loginModel.credentials, loginModel.cardDavURI, blockOnUnauthorizedException).observe(this) { result -> // save result for next step loginModel.configuration = result @@ -97,7 +97,7 @@ class DetectConfigurationFragment: Fragment() { } - fun detectConfiguration(baseURI: URI, credentials: Credentials?, cardDavURI: URI?, blockOnUnauthorizedException: Boolean): LiveData { + fun detectConfiguration(baseURI: URI, credentials: Credentials?, cardDavURI: URI?, blockOnUnauthorizedException: Boolean = false): LiveData { synchronized(result) { if (detectionThread != null) // detection already running diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorFragment.kt index 50061c91beeb83e72fd7a2a373ae35eb55ec7c91..77b0252c74c3991a0685e53b924bf7db4da990a0 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorFragment.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorFragment.kt @@ -27,6 +27,7 @@ import android.view.ViewGroup import android.widget.Button import android.widget.Toast import androidx.core.content.ContextCompat +import androidx.core.view.isVisible import androidx.core.widget.doOnTextChanged import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -55,6 +56,7 @@ class EeloAuthenticatorFragment : Fragment() { private lateinit var serverUrlEditTextLayout: TextInputLayout private lateinit var serverUrlEditText: TextInputEditText private lateinit var passwordEditText: TextInputEditText + private lateinit var passwordHolder: View private fun isNetworkAvailable(): Boolean { val connectivityManager = requireActivity().getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager @@ -64,11 +66,7 @@ class EeloAuthenticatorFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - - if (!isNetworkAvailable()) { - Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() - requireActivity().finish() - } + handleNoNetworkAvailable() val v = FragmentEeloAuthenticatorBinding.inflate(inflater, container, false) v.lifecycleOwner = this @@ -79,12 +77,17 @@ class EeloAuthenticatorFragment : Fragment() { serverUrlEditTextLayout = v.root.findViewById(R.id.urlpwd_server_uri_layout) serverUrlEditText = v.root.findViewById(R.id.urlpwd_server_uri) passwordEditText = v.root.findViewById(R.id.urlpwd_password) + passwordHolder = v.root.findViewById(R.id.password_holder) + + passwordHolder.isVisible = !EeloAuthenticatorModel.enableOpenIdSupport serverToggleButton.setOnClickListener { expandCollapse() } v.root.findViewById(R.id.sign_in).setOnClickListener { login() } - v.root.findViewById(R.id.twofa_info_button).setOnClickListener { show2FAInfoDialog() } + val tfaButton = v.root.findViewById(R.id.twofa_info_button) + tfaButton.setOnClickListener { show2FAInfoDialog() } + tfaButton.isVisible = !EeloAuthenticatorModel.enableOpenIdSupport userIdEditText.doOnTextChanged { text, _, _, _ -> val domain = computeDomain(text) @@ -190,24 +193,40 @@ class EeloAuthenticatorFragment : Fragment() { return domain } - private fun login() { - if (!isNetworkAvailable()) { - Toast.makeText(context, "Please check your internet connection", Toast.LENGTH_LONG).show() - requireActivity().finish() + private fun handleNoNetworkAvailable() { + if (isNetworkAvailable()) { + return } - if ((userIdEditText.text.toString() != "") && (passwordEditText.text.toString() != "")) { - if (validate()) - parentFragmentManager.beginTransaction() - .replace(android.R.id.content, DetectConfigurationFragment(), null) - .addToBackStack(null) - .commit() + Toast.makeText(context, R.string.no_internet_toast, Toast.LENGTH_LONG).show() + requireActivity().finish() + } + + private fun login() { + handleNoNetworkAvailable() + + val handleOpenIdAuth = EeloAuthenticatorModel.enableOpenIdSupport && !toggleButtonState + val userId = userIdEditText.text.toString() + val password = passwordEditText.text.toString() + + if (handleOpenIdAuth && userId.isNotBlank()) { + requireActivity().intent.putExtra(LoginActivity.USERNAME_HINT, userIdEditText.text.toString()) + navigate(MurenaOpenIdAuthFragment()) + } else if (userId.isNotBlank() && password.isNotBlank() && validate()) { + navigate(DetectConfigurationFragment()) } else { - Toast.makeText(context, "Please enter a valid username and password", Toast.LENGTH_LONG).show() + Toast.makeText(context, R.string.invalid_credentials, Toast.LENGTH_LONG).show() } } + private fun navigate(fragment: Fragment) { + parentFragmentManager.beginTransaction() + .replace(android.R.id.content, fragment, null) + .addToBackStack(null) + .commit() + } + // if user wants to login with murena account, add support to automated retry // if user in any case provide wrong accountId as email (ex: abc@murena.io instead of abc@e.email) private fun addSupportRetryOn401IfPossible(serverUrl: String) { @@ -279,11 +298,20 @@ class EeloAuthenticatorFragment : Fragment() { serverUrlEditTextLayout.visibility = View.VISIBLE serverUrlEditText.isEnabled = true toggleButtonState = true + + passwordHolder.visibility = View.VISIBLE } else { serverToggleButton.setCompoundDrawablesWithIntrinsicBounds(null, null , ContextCompat.getDrawable(requireContext(), R.drawable.ic_expand_more), null) serverUrlEditTextLayout.visibility = View.GONE serverUrlEditText.isEnabled = false toggleButtonState = false + + if(!EeloAuthenticatorModel.enableOpenIdSupport) { + return + } + + passwordHolder.visibility = View.GONE + passwordEditText.text?.clear() } } diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorModel.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorModel.kt index ce607af20cf88c454b59cc16796c6541ecf9967c..c65296df1a15c71d505ded1a55fa11ec712ec70f 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorModel.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/EeloAuthenticatorModel.kt @@ -24,24 +24,25 @@ import at.bitfire.davdroid.ECloudAccountHelper class EeloAuthenticatorModel(application: Application) : AndroidViewModel(application) { + companion object { + // as https://gitlab.e.foundation/e/backlog/-/issues/6287 is blocked, the openId implementation is not ready yet. + // But we want to push the changes so later we won't face any conflict. So we are disabling the openId feature for now. + const val enableOpenIdSupport = false + } + private var initialized = false + val loginWithUrlAndTokens = MutableLiveData() val baseUrl = MutableLiveData() val baseUrlError = MutableLiveData() - val emailAddress = MutableLiveData() - val emailAddressError = MutableLiveData() - val username = MutableLiveData() - val usernameError = MutableLiveData() val password = MutableLiveData() - val passwordError = MutableLiveData() val certificateAlias = MutableLiveData() - val certificateAliasError = MutableLiveData() init { loginWithUrlAndTokens.value = true @@ -53,7 +54,6 @@ class EeloAuthenticatorModel(application: Application) : AndroidViewModel(applic // we've got initial login data val givenUrl = intent.getStringExtra(LoginActivity.EXTRA_URL) - val givenUsername = intent.getStringExtra(LoginActivity.EXTRA_USERNAME) val givenPassword = intent.getStringExtra(LoginActivity.EXTRA_PASSWORD) baseUrl.value = givenUrl diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginActivity.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginActivity.kt index 8bbd99bf090d8cf7322c1a5dad908bb65b8cd561..df981373c778b678a3590d15218754be983a0313 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginActivity.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/LoginActivity.kt @@ -38,6 +38,8 @@ class LoginActivity: AppCompatActivity() { */ const val EXTRA_PASSWORD = "password" + const val USERNAME_HINT = "userNameHint" + const val AUTH_STATE = "authState" const val ACCOUNT_TYPE = "account_type" const val OPENID_AUTH_FLOW_COMPLETE = "openId_authFlow_complete" diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/MurenaLoginFragmentFactory.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/MurenaLoginFragmentFactory.kt index 3a2462e932083d00fea25a2691a59dc26bc8cd8d..4bb15ba6f81fb8ef3432c0ede540840abd66012e 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/MurenaLoginFragmentFactory.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/MurenaLoginFragmentFactory.kt @@ -35,12 +35,21 @@ class MurenaLoginFragmentFactory @Inject constructor(@ApplicationContext val con val accountType = intent.getStringExtra(LoginActivity.ACCOUNT_TYPE) ?: return null return when (accountType) { - context.getString(R.string.eelo_account_type) -> EeloAuthenticatorFragment() + context.getString(R.string.eelo_account_type) -> getMurenaFragment(intent) context.getString(R.string.google_account_type) -> GoogleAuthFragment() context.getString(R.string.yahoo_account_type) -> YahooAuthFragment() else -> null } } + + private fun getMurenaFragment(intent: Intent): Fragment { + val isAuthFlowComplete = intent.getBooleanExtra(LoginActivity.OPENID_AUTH_FLOW_COMPLETE, false) + + return when (isAuthFlowComplete) { + true -> MurenaOpenIdAuthFragment() + else -> EeloAuthenticatorFragment() + } + } } @Module diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/MurenaOpenIdAuthFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/MurenaOpenIdAuthFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..8a5636accfa099f12f1f09e08f94ddfe05d34c00 --- /dev/null +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/MurenaOpenIdAuthFragment.kt @@ -0,0 +1,54 @@ +/* + * Copyright MURENA SAS 2023 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package at.bitfire.davdroid.ui.setup + +import android.os.Bundle +import android.view.View +import at.bitfire.davdroid.ECloudAccountHelper +import at.bitfire.davdroid.authorization.IdentityProvider +import org.json.JSONObject + +class MurenaOpenIdAuthFragment : OpenIdAuthenticationBaseFragment(IdentityProvider.MURENA) { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + if (!isAuthFlowComplete() && ECloudAccountHelper.alreadyHasECloudAccount(requireContext())) { + ECloudAccountHelper.showMultipleECloudAccountNotAcceptedDialog(requireActivity()) + return + } + + startAuthFLow() + } + + override fun onAuthenticationComplete(userData: JSONObject) { + val userNameKey = "username" + + if (!userData.has(userNameKey)) { + handleLoginFailedToast() + return + } + + val userName = userData.getString(userNameKey) + if (userName.isBlank()) { + handleLoginFailedToast() + return + } + + proceedNext(userName, "https://murena.io/remote.php/dav/files/$userName") + } +} diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationViewModel.kt b/app/src/main/java/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationViewModel.kt index b5c23d460068d4dc97449455adefe283f26a2204..175872dc535f3ca318c76db71bfc31a20cc6ccd3 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationViewModel.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationViewModel.kt @@ -25,6 +25,7 @@ import androidx.lifecycle.AndroidViewModel import at.bitfire.davdroid.OpenIdUtils import at.bitfire.davdroid.authorization.IdentityProvider import at.bitfire.davdroid.log.Logger +import net.openid.appauth.AppAuthConfiguration import net.openid.appauth.AuthState import net.openid.appauth.AuthState.AuthStateAction import net.openid.appauth.AuthorizationException @@ -46,10 +47,20 @@ import java.util.logging.Level class OpenIdAuthenticationViewModel(application: Application) : AndroidViewModel(application) { - private val authorizationService: AuthorizationService = AuthorizationService(getApplication()) + private val authorizationService: AuthorizationService private var authState: AuthState? = null var identityProvider: IdentityProvider? = null + init { + val appAuthConfig = AppAuthConfiguration.Builder() + .setBrowserMatcher { + it.useCustomTab + } + .build() + + authorizationService = AuthorizationService(getApplication(), appAuthConfig) + } + override fun onCleared() { authorizationService.dispose() super.onCleared() @@ -65,7 +76,8 @@ class OpenIdAuthenticationViewModel(application: Application) : AndroidViewModel } val authStateString = - intent.getStringExtra(LoginActivity.AUTH_STATE) ?: return OpenIdAuthStateSetupState.SET_UP_FAILED + intent.getStringExtra(LoginActivity.AUTH_STATE) + ?: return OpenIdAuthStateSetupState.SET_UP_FAILED authState = AuthState.jsonDeserialize(authStateString) @@ -76,15 +88,22 @@ class OpenIdAuthenticationViewModel(application: Application) : AndroidViewModel return OpenIdAuthStateSetupState.SET_UP_SUCCEED } - fun requestAuthCode(serviceConfiguration: AuthorizationServiceConfiguration, intent: Intent) { + fun requestAuthCode( + serviceConfiguration: AuthorizationServiceConfiguration, + intent: Intent + ) { authState = AuthState(serviceConfiguration) + val loginHint = intent.getStringExtra(LoginActivity.USERNAME_HINT) + val authRequest = AuthorizationRequest.Builder( serviceConfiguration, identityProvider!!.clientId, ResponseTypeValues.CODE, identityProvider!!.redirectUri - ).setScope(identityProvider!!.scope) + ) + .setScope(identityProvider!!.scope) + .setLoginHint(sanitizeHint(loginHint)) .build() authorizationService.performAuthorizationRequest( @@ -94,6 +113,10 @@ class OpenIdAuthenticationViewModel(application: Application) : AndroidViewModel ) } + private fun sanitizeHint(hint: String?): String? { + return if (hint.isNullOrBlank()) null else hint + } + private fun createPostAuthorizationIntent( request: AuthorizationRequest, providedIntent: Intent diff --git a/app/src/main/res/layout/fragment_eelo_authenticator.xml b/app/src/main/res/layout/fragment_eelo_authenticator.xml index 0321f345d07c5c0ffcf01c8e65edae8667a11b0a..58d9cec2be88c8c3dee7b12043dee6b0c450a0c6 100644 --- a/app/src/main/res/layout/fragment_eelo_authenticator.xml +++ b/app/src/main/res/layout/fragment_eelo_authenticator.xml @@ -82,6 +82,7 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 100c5ad075ae851dbb5b89cab4526cffb35f976b..45cbd6c6c8a19235257aafe8f08a3ef86ff6b63b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -582,4 +582,5 @@ Login failed, please try again later OK + Authentication failed. Please enter a valid credentials