From 704f35b35b17bee93099b92df352b63f0a342995 Mon Sep 17 00:00:00 2001 From: rosariopf Date: Mon, 17 Mar 2025 17:16:36 +0000 Subject: [PATCH] refactor: clear credman state after signOut and user deletion --- .../java/com/firebase/ui/auth/AuthUI.java | 60 +++++++++++++++---- .../auth/ui/idp/AuthMethodPickerActivity.kt | 3 +- .../firebase/ui/auth/util/GoogleApiUtils.java | 6 ++ .../CredentialManagerHandler.kt | 4 +- 4 files changed, 59 insertions(+), 14 deletions(-) diff --git a/auth/src/main/java/com/firebase/ui/auth/AuthUI.java b/auth/src/main/java/com/firebase/ui/auth/AuthUI.java index d389af20b..c7c828843 100644 --- a/auth/src/main/java/com/firebase/ui/auth/AuthUI.java +++ b/auth/src/main/java/com/firebase/ui/auth/AuthUI.java @@ -17,6 +17,7 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -32,6 +33,7 @@ import com.firebase.ui.auth.util.data.PhoneNumberUtils; import com.firebase.ui.auth.util.data.ProviderAvailability; import com.firebase.ui.auth.util.data.ProviderUtils; +import com.google.android.gms.auth.api.identity.Identity; import com.google.android.gms.auth.api.signin.GoogleSignIn; import com.google.android.gms.auth.api.signin.GoogleSignInAccount; import com.google.android.gms.auth.api.signin.GoogleSignInOptions; @@ -39,6 +41,7 @@ import com.google.android.gms.common.api.CommonStatusCodes; import com.google.android.gms.common.api.Scope; import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.TaskCompletionSource; import com.google.android.gms.tasks.Tasks; import com.google.firebase.FirebaseApp; import com.google.firebase.auth.ActionCodeSettings; @@ -68,6 +71,8 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import androidx.annotation.CallSuper; import androidx.annotation.DrawableRes; @@ -76,6 +81,9 @@ import androidx.annotation.RestrictTo; import androidx.annotation.StringDef; import androidx.annotation.StyleRes; +import androidx.credentials.ClearCredentialStateRequest; +import androidx.credentials.CredentialManagerCallback; +import androidx.credentials.exceptions.ClearCredentialException; /** * The entry point to the AuthUI authentication flow, and related utility methods. If your @@ -280,8 +288,9 @@ public Task signOut(@NonNull Context context) { if (!playServicesAvailable) { Log.w(TAG, "Google Play services not available during signOut"); } - - return signOutIdps(context).continueWith(task -> { + signOutIdps(context); + Executor singleThreadExecutor = Executors.newSingleThreadExecutor(); + return clearCredentialState(context, singleThreadExecutor).continueWith(task -> { task.getResult(); // Propagate exceptions if any. mAuth.signOut(); return null; @@ -303,9 +312,10 @@ public Task delete(@NonNull final Context context) { String.valueOf(CommonStatusCodes.SIGN_IN_REQUIRED), "No currently signed in user.")); } - - return signOutIdps(context).continueWithTask(task -> { - task.getResult(); // Propagate exception if there was one. + signOutIdps(context); + Executor singleThreadExecutor = Executors.newSingleThreadExecutor(); + return clearCredentialState(context, singleThreadExecutor).continueWithTask(task -> { + task.getResult(); // Propagate exceptions if any. return currentUser.delete(); }); } @@ -338,15 +348,43 @@ public int getEmulatorPort() { return mEmulatorPort; } - private Task signOutIdps(@NonNull Context context) { + private void signOutIdps(@NonNull Context context) { if (ProviderAvailability.IS_FACEBOOK_AVAILABLE) { LoginManager.getInstance().logOut(); } - if (GoogleApiUtils.isPlayServicesAvailable(context)) { - return GoogleSignIn.getClient(context, GoogleSignInOptions.DEFAULT_SIGN_IN).signOut(); - } else { - return Tasks.forResult((Void) null); - } + } + + /** + * A Task to clear the credential state in Credential Manager. + * @param context + * @param executor + * @return + */ + private Task clearCredentialState( + @NonNull Context context, + @NonNull Executor executor + ) { + TaskCompletionSource completionSource = new TaskCompletionSource<>(); + + ClearCredentialStateRequest clearRequest = new ClearCredentialStateRequest(); + GoogleApiUtils.getCredentialManager(context) + .clearCredentialStateAsync( + clearRequest, + new CancellationSignal(), + executor, + new CredentialManagerCallback<>() { + @Override + public void onResult(Void unused) { + completionSource.setResult(unused); + } + + @Override + public void onError(@NonNull ClearCredentialException e) { + completionSource.setException(e); + } + } + ); + return completionSource.getTask(); } /** diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.kt b/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.kt index c2cc8ec32..5cec78510 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/idp/AuthMethodPickerActivity.kt @@ -86,6 +86,7 @@ import androidx.credentials.exceptions.GetCredentialException import com.firebase.ui.auth.AuthUI.EMAIL_LINK_PROVIDER import com.firebase.ui.auth.util.ExtraConstants.GENERIC_OAUTH_BUTTON_ID import com.firebase.ui.auth.util.ExtraConstants.GENERIC_OAUTH_PROVIDER_ID +import com.firebase.ui.auth.util.GoogleApiUtils import com.google.android.libraries.identity.googleid.GetGoogleIdOption import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException @@ -105,7 +106,7 @@ class AuthMethodPickerActivity : AppCompatBase() { // For demonstration, assume that CredentialManager provides a create() method. private val credentialManager by lazy { // Replace with your actual CredentialManager instance creation. - CredentialManager.create(this) + GoogleApiUtils.getCredentialManager(this) } companion object { diff --git a/auth/src/main/java/com/firebase/ui/auth/util/GoogleApiUtils.java b/auth/src/main/java/com/firebase/ui/auth/util/GoogleApiUtils.java index c496a3c3e..15d1e0ebb 100644 --- a/auth/src/main/java/com/firebase/ui/auth/util/GoogleApiUtils.java +++ b/auth/src/main/java/com/firebase/ui/auth/util/GoogleApiUtils.java @@ -9,6 +9,7 @@ import androidx.annotation.NonNull; import androidx.annotation.RestrictTo; +import androidx.credentials.CredentialManager; @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public final class GoogleApiUtils { @@ -25,4 +26,9 @@ public static boolean isPlayServicesAvailable(@NonNull Context context) { public static SignInClient getSignInClient(@NonNull Context context) { return Identity.getSignInClient(context); } + + @NonNull + public static CredentialManager getCredentialManager(@NonNull Context context) { + return CredentialManager.create(context); + } } diff --git a/auth/src/main/java/com/firebase/ui/auth/viewmodel/credentialmanager/CredentialManagerHandler.kt b/auth/src/main/java/com/firebase/ui/auth/viewmodel/credentialmanager/CredentialManagerHandler.kt index 2c75e47e2..83ed0f69d 100644 --- a/auth/src/main/java/com/firebase/ui/auth/viewmodel/credentialmanager/CredentialManagerHandler.kt +++ b/auth/src/main/java/com/firebase/ui/auth/viewmodel/credentialmanager/CredentialManagerHandler.kt @@ -4,13 +4,13 @@ import android.app.Application import android.content.Context import androidx.lifecycle.viewModelScope import androidx.credentials.CreatePasswordRequest -import androidx.credentials.CredentialManager import androidx.credentials.CreateCredentialResponse import androidx.credentials.exceptions.CreateCredentialException import com.firebase.ui.auth.ErrorCodes import com.firebase.ui.auth.FirebaseUiException import com.firebase.ui.auth.IdpResponse import com.firebase.ui.auth.data.model.Resource +import com.firebase.ui.auth.util.GoogleApiUtils import com.firebase.ui.auth.viewmodel.AuthViewModelBase import com.google.firebase.auth.FirebaseUser import kotlinx.coroutines.launch @@ -18,7 +18,7 @@ import kotlinx.coroutines.launch class CredentialManagerHandler(application: Application) : AuthViewModelBase(application) { - private val credentialManager = CredentialManager.create(application) + private val credentialManager = GoogleApiUtils.getCredentialManager(application) private var response: IdpResponse? = null fun setResponse(newResponse: IdpResponse) {