Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Verified Commit e1c3269c authored by Fahim M. Choudhury's avatar Fahim M. Choudhury
Browse files

refactor: use OidcTokenRefresher to refresh authState in MurenaTokenManager

parent 15a8ea4b
Loading
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ object OidcTokenRefresher {
        account: Account?,
        getClientAuth: () -> ClientAuthentication?,
        readAuthState: () -> AuthState?,
        writeAuthState: (AuthState) -> Unit
        writeAuthState: ((AuthState) -> Unit)? = null
    ): AuthState? = synchronized(javaClass) {
        val authState = readAuthState() ?: return null
        // Use cached authState if possible
@@ -97,7 +97,9 @@ object OidcTokenRefresher {
            authState.performActionWithFreshTokens(
                authService, clientAuth
            ) { accessToken, _, exception ->
                if (writeAuthState != null) {
                    writeAuthState(authState)
                }
                when {
                    accessToken != null -> {
                        logger.info("Token refreshed for $account")
+40 −36
Original line number Diff line number Diff line
@@ -25,12 +25,12 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.OpenIdUtils
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.network.HttpClient
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.ui.NetworkUtils
import dagger.hilt.android.EntryPointAccessors
import com.nextcloud.android.sso.OidcTokenRefresher
import net.openid.appauth.AuthState
import net.openid.appauth.AuthorizationException
import java.text.SimpleDateFormat
@@ -134,11 +134,6 @@ object MurenaTokenManager {
   // Refreshes the authentication token and updates stored credentials if successful.
    private fun refreshAuthToken(context: Context, onComplete: ((AuthState?) -> Unit)? = null) {
        try {
            val httpEntryPoint = EntryPointAccessors.fromApplication(
                context, HttpClient.HttpClientEntryPoint::class.java
            )

            val authService = httpEntryPoint.authorizationService()
            val accountSettings = getAccountSettings(context) ?: run {
                Logger.log.warning("No account settings found during token refresh.")
                return
@@ -156,38 +151,47 @@ object MurenaTokenManager {
                return
            }

            val tokenRequest = authState.createTokenRefreshRequest()
            authService.performTokenRequest(tokenRequest) { response, exception ->
                when {
                    response != null && exception == null -> {
                        authState.update(response, null)
                        accountSettings.credentials(credentials.copy(authState = authState))
                        Logger.log.info("Token refreshed for ${accountSettings.account.name}")
            val updatedAuthState: AuthState? = try {
                OidcTokenRefresher.refreshAuthState(
                    context = context,
                    account = accountSettings.account,
                    getClientAuth = { OpenIdUtils.getClientAuthentication(credentials.clientSecret) },
                    readAuthState = { authState }
                )
            } catch (e: AuthorizationException) {
                if (isInvalidGrant(e)) {
                    Logger.log.log(
                        Level.SEVERE,
                        "Invalid grant: refresh cancelled, User must re-authenticate.",
                        e
                    )
                    cancelTokenRefreshAlarm(context)
                } else {
                    Logger.log.log(Level.SEVERE, "Token refresh failed: $e, retrying in 5 minutes.")
                    setTokenRefreshAlarm(
                        context,
                        System.currentTimeMillis() + 5.minutes.inWholeMilliseconds
                    )
                }
                onComplete?.invoke(null)
                null
            }

            if (updatedAuthState != null) {
                accountSettings.credentials(credentials.copy(authState = updatedAuthState))
                Logger.log.info("Token refreshed for ${accountSettings.account}")

                // Schedule at least 2 minutes early for the new token.
                        val refreshAt = authState.accessTokenExpirationTime?.minus(2.minutes.inWholeMilliseconds)
                val refreshAt =
                    updatedAuthState.accessTokenExpirationTime?.minus(2.minutes.inWholeMilliseconds)
                if (refreshAt != null) {
                    setTokenRefreshAlarm(context, refreshAt)
                }

                        onComplete?.invoke(authState)
                    }

                    isInvalidGrant(exception) -> {
                        Logger.log.log(Level.SEVERE, "Invalid grant: refresh cancelled, User must re-authenticate.", exception)
                        cancelTokenRefreshAlarm(context)
                onComplete?.invoke(updatedAuthState)
            }

                    else -> {
                        Logger.log.log(Level.SEVERE, "Token refresh failed: unknown error, retrying in 5 minutes.")
                        setTokenRefreshAlarm(context, System.currentTimeMillis() + 5.minutes.inWholeMilliseconds)
                    }
                }
            }
        } catch (e: Exception) {
            Logger.log.log(Level.SEVERE, "Token refresh failed due to unexpected exception.", e)
        } finally {
            onComplete?.invoke(null)
        }
    }

@@ -199,7 +203,7 @@ object MurenaTokenManager {

    // Retrieves the Murena account settings for the currently active account, if available.
    // We only allow one murena account.
    fun getAccountSettings(context: Context): AccountSettings? {
    private fun getAccountSettings(context: Context): AccountSettings? {
        val accountType = context.getString(R.string.eelo_account_type)
        val account = AccountManager.get(context)
            .getAccountsByType(accountType)