Loading app/src/main/kotlin/at/bitfire/davdroid/authorization/MurenaOfflineAccessValidator.kt 0 → 100644 +25 −0 Original line number Diff line number Diff line package at.bitfire.davdroid.authorization import net.openid.appauth.AuthState import net.openid.appauth.AuthorizationException object MurenaOfflineAccessValidator { fun hasUsableOfflineAccess(authState: AuthState): Boolean { return hasUsableOfflineAccess( accessToken = authState.accessToken, refreshToken = authState.refreshToken, authorizationException = authState.authorizationException ) } internal fun hasUsableOfflineAccess( accessToken: String?, refreshToken: String?, authorizationException: AuthorizationException? ): Boolean { return authorizationException == null && !accessToken.isNullOrBlank() && !refreshToken.isNullOrBlank() } } app/src/main/kotlin/at/bitfire/davdroid/ui/setup/MurenaOpenIdAuthFragment.kt +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.os.Bundle import android.view.View import at.bitfire.davdroid.ECloudAccountHelper import at.bitfire.davdroid.authorization.IdentityProvider import at.bitfire.davdroid.authorization.MurenaOfflineAccessValidator import at.bitfire.davdroid.murenasso.MurenaSsoMigrationPreferences import at.bitfire.davdroid.ui.account.SettingsActivity import org.json.JSONObject Loading Loading @@ -56,6 +57,11 @@ class MurenaOpenIdAuthFragment : OpenIdAuthenticationBaseFragment(IdentityProvid return } if (!MurenaOfflineAccessValidator.hasUsableOfflineAccess(getAuthState())) { handleLoginFailedToast() return } val userNameKey = "username" if (!userData.has(userNameKey)) { Loading app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt +3 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import net.openid.appauth.AuthState.AuthStateAction import net.openid.appauth.AuthState import net.openid.appauth.AuthorizationException import net.openid.appauth.AuthorizationResponse import net.openid.appauth.AuthorizationService.TokenResponseCallback Loading Loading @@ -203,6 +204,8 @@ abstract class OpenIdAuthenticationBaseFragment(private val identityProvider: Id finishActivity() } protected fun getAuthState(): AuthState = viewModel.getAuthState() protected fun proceedNext(userName: String, baseUrl: String, cardDavUrl: String? = null) { activity?.intent?.putExtra(LoginActivity.OPENID_AUTH_FLOW_COMPLETE, true) Loading app/src/test/kotlin/at/bitfire/davdroid/authorization/IdentityProviderTest.kt +36 −0 Original line number Diff line number Diff line package at.bitfire.davdroid.authorization import net.openid.appauth.AuthorizationException import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test class IdentityProviderTest { Loading @@ -11,4 +14,37 @@ class IdentityProviderTest { assertEquals("openid profile email", scope) } @Test fun `murena offline access validator accepts usable auth state data`() { assertTrue( MurenaOfflineAccessValidator.hasUsableOfflineAccess( accessToken = "access-token", refreshToken = "refresh-token", authorizationException = null ) ) } @Test fun `murena offline access validator rejects missing refresh token`() { assertFalse( MurenaOfflineAccessValidator.hasUsableOfflineAccess( accessToken = "access-token", refreshToken = null, authorizationException = null ) ) } @Test fun `murena offline access validator rejects authorization exception`() { assertFalse( MurenaOfflineAccessValidator.hasUsableOfflineAccess( accessToken = "access-token", refreshToken = "refresh-token", authorizationException = AuthorizationException.TokenRequestErrors.INVALID_GRANT ) ) } } Loading
app/src/main/kotlin/at/bitfire/davdroid/authorization/MurenaOfflineAccessValidator.kt 0 → 100644 +25 −0 Original line number Diff line number Diff line package at.bitfire.davdroid.authorization import net.openid.appauth.AuthState import net.openid.appauth.AuthorizationException object MurenaOfflineAccessValidator { fun hasUsableOfflineAccess(authState: AuthState): Boolean { return hasUsableOfflineAccess( accessToken = authState.accessToken, refreshToken = authState.refreshToken, authorizationException = authState.authorizationException ) } internal fun hasUsableOfflineAccess( accessToken: String?, refreshToken: String?, authorizationException: AuthorizationException? ): Boolean { return authorizationException == null && !accessToken.isNullOrBlank() && !refreshToken.isNullOrBlank() } }
app/src/main/kotlin/at/bitfire/davdroid/ui/setup/MurenaOpenIdAuthFragment.kt +6 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.os.Bundle import android.view.View import at.bitfire.davdroid.ECloudAccountHelper import at.bitfire.davdroid.authorization.IdentityProvider import at.bitfire.davdroid.authorization.MurenaOfflineAccessValidator import at.bitfire.davdroid.murenasso.MurenaSsoMigrationPreferences import at.bitfire.davdroid.ui.account.SettingsActivity import org.json.JSONObject Loading Loading @@ -56,6 +57,11 @@ class MurenaOpenIdAuthFragment : OpenIdAuthenticationBaseFragment(IdentityProvid return } if (!MurenaOfflineAccessValidator.hasUsableOfflineAccess(getAuthState())) { handleLoginFailedToast() return } val userNameKey = "username" if (!userData.has(userNameKey)) { Loading
app/src/main/kotlin/at/bitfire/davdroid/ui/setup/OpenIdAuthenticationBaseFragment.kt +3 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import net.openid.appauth.AuthState.AuthStateAction import net.openid.appauth.AuthState import net.openid.appauth.AuthorizationException import net.openid.appauth.AuthorizationResponse import net.openid.appauth.AuthorizationService.TokenResponseCallback Loading Loading @@ -203,6 +204,8 @@ abstract class OpenIdAuthenticationBaseFragment(private val identityProvider: Id finishActivity() } protected fun getAuthState(): AuthState = viewModel.getAuthState() protected fun proceedNext(userName: String, baseUrl: String, cardDavUrl: String? = null) { activity?.intent?.putExtra(LoginActivity.OPENID_AUTH_FLOW_COMPLETE, true) Loading
app/src/test/kotlin/at/bitfire/davdroid/authorization/IdentityProviderTest.kt +36 −0 Original line number Diff line number Diff line package at.bitfire.davdroid.authorization import net.openid.appauth.AuthorizationException import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test class IdentityProviderTest { Loading @@ -11,4 +14,37 @@ class IdentityProviderTest { assertEquals("openid profile email", scope) } @Test fun `murena offline access validator accepts usable auth state data`() { assertTrue( MurenaOfflineAccessValidator.hasUsableOfflineAccess( accessToken = "access-token", refreshToken = "refresh-token", authorizationException = null ) ) } @Test fun `murena offline access validator rejects missing refresh token`() { assertFalse( MurenaOfflineAccessValidator.hasUsableOfflineAccess( accessToken = "access-token", refreshToken = null, authorizationException = null ) ) } @Test fun `murena offline access validator rejects authorization exception`() { assertFalse( MurenaOfflineAccessValidator.hasUsableOfflineAccess( accessToken = "access-token", refreshToken = "refresh-token", authorizationException = AuthorizationException.TokenRequestErrors.INVALID_GRANT ) ) } }