firebase / FirebaseUI-Android

Optimized UI components for Firebase
https://firebaseopensource.com/projects/firebase/firebaseui-android/
Apache License 2.0
4.64k stars 1.83k forks source link

Support for Google Password Policy constraints, on FirebaseUI #2128

Open smlima opened 1 year ago

smlima commented 1 year ago

Step 3: Describe the problem:

I'm working on an app that uses the Google Identity platform (GIdP), and we're setting the password policy to be way more restricted than the normal 6 chars that firebaseUI has on Android (and also iOS, but will create a separate issue for it). So it would be interesting to be able to show on the signup screen, instead of a generic error say exactly which policies are failing, because that information does come down from GIdP. Because if the user knows that the password must include an Uppercase, then he will add it, instead of going round and round, or contact support asking why he can't create an account.

I believe It would be a simple change to have a somewhat FirebaseAuthPasswordPolicyException coming down from firebase.auth, with all the required info and then check at RegisterEmailFragment for that exception and then show the failing policy elements on the UI.

We could eventually hack it on FirebaseUI of something like `public class FirebaseAuthPasswordPolicyException extends Exception {

public static boolean instance(Exception e) {
    return e.getMessage().contains("PASSWORD_DOES_NOT_MEET_REQUIREMENTS");
}

public FirebaseAuthPasswordPolicyException(Exception e) {
    super(e);
}

public String prettyMessage() {
    String mesg = getMessage();
    int index1 = mesg.lastIndexOf("[");
    int index2 = mesg.indexOf("]");

    String errorM = mesg.substring(index1+1, index2);

    return errorM.replace(", ", "\n");
}

} ` But I believe this should come from above, not created on the FirebaseUI.

and then on the RegisterEmailFragment class ,line 122


            protected void onFailure(@NonNull Exception e) {
                if (e instanceof FirebaseAuthWeakPasswordException) {
                    mPasswordInput.setError(getResources().getQuantityString(
                            R.plurals.fui_error_weak_password,
                            R.integer.fui_min_password_length));
                } else if (e instanceof FirebaseAuthInvalidCredentialsException) {
                    mEmailInput.setError(getString(R.string.fui_invalid_email_address));
                } else if (e instanceof FirebaseAuthAnonymousUpgradeException) {
                    IdpResponse response = ((FirebaseAuthAnonymousUpgradeException) e).getResponse();
                    mListener.onMergeFailure(response);
                } else if (e instanceof FirebaseAuthPasswordPolicyException) {
                    mPasswordInput.setError(((FirebaseAuthPasswordPolicyException) e).prettyMessage());
                } else {
                    // General error message, this branch should not be invoked but
                    // covers future API changes
                    mEmailInput.setError(getString(R.string.fui_email_account_creation_error));
                }
            }

And on the EmailProviderResponseHandler

authOperationManager.createOrLinkUserWithEmailAndPassword(getAuth(),
                getArguments(),
                email,
                password)
                .continueWithTask(new ProfileMerger(response))
                .addOnFailureListener(new TaskFailureLogger(TAG, "Error creating user"))
                .addOnSuccessListener(result -> handleSuccess(response, result))
                .addOnFailureListener(e -> {
                    if (e instanceof FirebaseAuthUserCollisionException) {
                        if (authOperationManager.canUpgradeAnonymous(getAuth(),
                                getArguments())) {
                            AuthCredential credential = EmailAuthProvider.getCredential(email,
                                    password);
                            handleMergeFailure(credential);
                        } else {
                            Log.w(TAG, "Got a collision error during a non-upgrade flow", e);

                            // Collision with existing user email without anonymous upgrade
                            // it should be very hard for the user to even get to this error
                            // due to CheckEmailFragment.
                            ProviderUtils.fetchTopProvider(getAuth(), getArguments(), email)
                                    .addOnSuccessListener(new StartWelcomeBackFlow(email))
                                    .addOnFailureListener(e1 -> setResult(Resource.forFailure(
                                            e1)));
                        }
                    } else if (FirebaseAuthPasswordPolicyException.instance(e)) {
                        setResult(Resource.forFailure(new FirebaseAuthPasswordPolicyException(e)));
                    } else {
                        setResult(Resource.forFailure(e));
                    }
                });

And this should be enough for exposing the password policy failures.

What do you think?

jrgcubano commented 1 year ago

Any news regarding this @thatfiredev?. I think it makes a lot of sense to implement it. Thanks