From 553b644e88e4d6d0d7efc9b1fb26a547896292dd Mon Sep 17 00:00:00 2001 From: Luciano Balmaceda Date: Tue, 27 Apr 2021 12:46:06 +0200 Subject: [PATCH 1/3] raise "unauthorized" error through provided callback --- .../android/lock/AuthenticationCallback.java | 7 +++++ .../com/auth0/android/lock/Constants.java | 1 + .../java/com/auth0/android/lock/Lock.java | 5 ++-- .../com/auth0/android/lock/LockActivity.java | 26 +++++++++++++++---- .../auth0/android/lock/PasswordlessLock.java | 5 ++-- .../lock/PasswordlessLockActivity.java | 18 ++++++++++++- .../android/lock/utils/LockException.java | 7 +++++ .../lock/AuthenticationCallbackTest.java | 12 +++++++++ 8 files changed, 71 insertions(+), 10 deletions(-) diff --git a/lib/src/main/java/com/auth0/android/lock/AuthenticationCallback.java b/lib/src/main/java/com/auth0/android/lock/AuthenticationCallback.java index 4c1fa0896..6379af312 100644 --- a/lib/src/main/java/com/auth0/android/lock/AuthenticationCallback.java +++ b/lib/src/main/java/com/auth0/android/lock/AuthenticationCallback.java @@ -29,6 +29,8 @@ import androidx.annotation.NonNull; +import com.auth0.android.authentication.AuthenticationException; +import com.auth0.android.lock.utils.LockException; import com.auth0.android.result.Credentials; import java.util.Date; @@ -75,6 +77,11 @@ public void onEvent(@LockEvent int event, @NonNull Intent data) { * @param data the intent received at the end of the login process. */ private void parseAuthentication(Intent data) { + if (data.hasExtra(Constants.EXCEPTION_EXTRA)) { + AuthenticationException error = (AuthenticationException) data.getSerializableExtra(Constants.EXCEPTION_EXTRA); + onError(new LockException(error)); + return; + } String idToken = data.getStringExtra(Constants.ID_TOKEN_EXTRA); String accessToken = data.getStringExtra(Constants.ACCESS_TOKEN_EXTRA); String tokenType = data.getStringExtra(Constants.TOKEN_TYPE_EXTRA); diff --git a/lib/src/main/java/com/auth0/android/lock/Constants.java b/lib/src/main/java/com/auth0/android/lock/Constants.java index 8670dcac6..ec1e7fa8f 100644 --- a/lib/src/main/java/com/auth0/android/lock/Constants.java +++ b/lib/src/main/java/com/auth0/android/lock/Constants.java @@ -36,6 +36,7 @@ abstract class Constants { static final String CANCELED_ACTION = "com.auth0.android.lock.action.Canceled"; static final String INVALID_CONFIGURATION_ACTION = "com.auth0.android.lock.action.InvalidConfiguration"; + static final String EXCEPTION_EXTRA = "com.auth0.android.lock.extra.Exception"; static final String ERROR_EXTRA = "com.auth0.android.lock.extra.Error"; static final String ID_TOKEN_EXTRA = "com.auth0.android.lock.extra.IdToken"; static final String ACCESS_TOKEN_EXTRA = "com.auth0.android.lock.extra.AccessToken"; diff --git a/lib/src/main/java/com/auth0/android/lock/Lock.java b/lib/src/main/java/com/auth0/android/lock/Lock.java index a7b1ffe8e..808f41558 100644 --- a/lib/src/main/java/com/auth0/android/lock/Lock.java +++ b/lib/src/main/java/com/auth0/android/lock/Lock.java @@ -36,6 +36,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.auth0.android.Auth0; +import com.auth0.android.authentication.AuthenticationException; import com.auth0.android.lock.LockCallback.LockEvent; import com.auth0.android.lock.internal.configuration.Options; import com.auth0.android.lock.internal.configuration.Theme; @@ -150,8 +151,8 @@ private void processEvent(@NonNull Context context, @NonNull Intent data) { switch (action) { case Constants.AUTHENTICATION_ACTION: Log.v(TAG, "AUTHENTICATION action received in our BroadcastReceiver"); - if (data.hasExtra(Constants.ERROR_EXTRA)) { - callback.onError(new LockException(data.getStringExtra(Constants.ERROR_EXTRA))); + if (data.hasExtra(Constants.EXCEPTION_EXTRA)) { + callback.onError(new LockException((AuthenticationException) data.getSerializableExtra(Constants.EXCEPTION_EXTRA))); } else { callback.onEvent(LockEvent.AUTHENTICATION, data); } diff --git a/lib/src/main/java/com/auth0/android/lock/LockActivity.java b/lib/src/main/java/com/auth0/android/lock/LockActivity.java index a21261dd5..737f810f6 100644 --- a/lib/src/main/java/com/auth0/android/lock/LockActivity.java +++ b/lib/src/main/java/com/auth0/android/lock/LockActivity.java @@ -220,6 +220,14 @@ private void deliverAuthenticationResult(Credentials credentials) { finish(); } + private void deliverAuthenticationError(AuthenticationException exception) { + Intent intent = new Intent(Constants.AUTHENTICATION_ACTION); + intent.putExtra(Constants.EXCEPTION_EXTRA, exception); + + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + finish(); + } + private void deliverSignUpResult(DatabaseUser result) { Intent intent = new Intent(Constants.SIGN_UP_ACTION); intent.putExtra(Constants.EMAIL_EXTRA, result.getEmail()); @@ -484,9 +492,13 @@ public void onFailure(@NonNull final Dialog dialog) { @Override public void onFailure(@NonNull final AuthenticationException exception) { + Log.e(TAG, "Failed to authenticate the user: " + exception.getCode(), exception); + if (exception.isRuleError()) { + deliverAuthenticationError(exception); + return; + } final AuthenticationError authError = loginErrorBuilder.buildFrom(exception); final String message = authError.getMessage(LockActivity.this); - Log.e(TAG, "Failed to authenticate the user: " + message, exception); handler.post(() -> showErrorMessage(message)); } @@ -506,12 +518,16 @@ public void onSuccess(@Nullable Credentials credentials) { @Override public void onFailure(@NonNull final AuthenticationException error) { - Log.e(TAG, "Failed to authenticate the user: " + error.getMessage(), error); - final AuthenticationError authError = loginErrorBuilder.buildFrom(error); + Log.e(TAG, "Failed to authenticate the user: " + error.getCode(), error); + if (error.isRuleError()) { + deliverAuthenticationError(error); + return; + } if (error.isVerificationRequired()) { completeDatabaseAuthenticationOnBrowser(); return; } + final AuthenticationError authError = loginErrorBuilder.buildFrom(error); handler.post(() -> { lockView.showProgress(false); @@ -542,7 +558,7 @@ public void onSuccess(@Nullable final DatabaseUser user) { @Override public void onFailure(@NonNull final AuthenticationException error) { - Log.e(TAG, "Failed to create the user: " + error.getMessage(), error); + Log.e(TAG, "Failed to create the user: " + error.getCode(), error); if (error.isVerificationRequired()) { completeDatabaseAuthenticationOnBrowser(); return; @@ -568,7 +584,7 @@ public void onSuccess(@Nullable Void payload) { @Override public void onFailure(@NonNull AuthenticationException error) { - Log.e(TAG, "Failed to reset the user password: " + error.getMessage(), error); + Log.e(TAG, "Failed to reset the user password: " + error.getCode(), error); handler.post(() -> { String message = new AuthenticationError(R.string.com_auth0_lock_db_message_change_password_error).getMessage(LockActivity.this); showErrorMessage(message); diff --git a/lib/src/main/java/com/auth0/android/lock/PasswordlessLock.java b/lib/src/main/java/com/auth0/android/lock/PasswordlessLock.java index 2f58a8379..33ccf3333 100644 --- a/lib/src/main/java/com/auth0/android/lock/PasswordlessLock.java +++ b/lib/src/main/java/com/auth0/android/lock/PasswordlessLock.java @@ -36,6 +36,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.auth0.android.Auth0; +import com.auth0.android.authentication.AuthenticationException; import com.auth0.android.lock.LockCallback.LockEvent; import com.auth0.android.lock.internal.configuration.Options; import com.auth0.android.lock.internal.configuration.Theme; @@ -149,8 +150,8 @@ private void processEvent(Context context, Intent data) { switch (action) { case Constants.AUTHENTICATION_ACTION: Log.v(TAG, "AUTHENTICATION action received in our BroadcastReceiver"); - if (data.getExtras().containsKey(Constants.ERROR_EXTRA)) { - callback.onError(new LockException(data.getStringExtra(Constants.ERROR_EXTRA))); + if (data.hasExtra(Constants.EXCEPTION_EXTRA)) { + callback.onError(new LockException((AuthenticationException) data.getSerializableExtra(Constants.EXCEPTION_EXTRA))); } else { callback.onEvent(LockEvent.AUTHENTICATION, data); } diff --git a/lib/src/main/java/com/auth0/android/lock/PasswordlessLockActivity.java b/lib/src/main/java/com/auth0/android/lock/PasswordlessLockActivity.java index 87456a5d3..fb9baa6a8 100644 --- a/lib/src/main/java/com/auth0/android/lock/PasswordlessLockActivity.java +++ b/lib/src/main/java/com/auth0/android/lock/PasswordlessLockActivity.java @@ -224,6 +224,14 @@ private void deliverAuthenticationResult(Credentials credentials) { finish(); } + private void deliverAuthenticationError(AuthenticationException exception) { + Intent intent = new Intent(Constants.AUTHENTICATION_ACTION); + intent.putExtra(Constants.EXCEPTION_EXTRA, exception); + + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + finish(); + } + private void showErrorMessage(String message) { resultMessage.setBackgroundColor(ContextCompat.getColor(this, R.color.com_auth0_lock_result_message_error_background)); resultMessage.setVisibility(View.VISIBLE); @@ -494,6 +502,10 @@ public void onSuccess(@Nullable Credentials credentials) { @Override public void onFailure(@NonNull final AuthenticationException error) { Log.e(TAG, "Failed to authenticate the user: " + error.getMessage(), error); + if (error.isRuleError()) { + deliverAuthenticationError(error); + return; + } handler.post(() -> showErrorMessage(loginErrorBuilder.buildFrom(error).getMessage(PasswordlessLockActivity.this))); } }; @@ -507,9 +519,13 @@ public void onFailure(@NonNull final Dialog dialog) { @Override public void onFailure(@NonNull final AuthenticationException exception) { + Log.e(TAG, "Failed to authenticate the user: " + exception.getCode(), exception); + if (exception.isRuleError()) { + deliverAuthenticationError(exception); + return; + } final AuthenticationError authError = loginErrorBuilder.buildFrom(exception); final String message = authError.getMessage(PasswordlessLockActivity.this); - Log.e(TAG, "Failed to authenticate the user: " + message, exception); handler.post(() -> showErrorMessage(message)); } diff --git a/lib/src/main/java/com/auth0/android/lock/utils/LockException.java b/lib/src/main/java/com/auth0/android/lock/utils/LockException.java index e26f33c38..0f8d8d732 100644 --- a/lib/src/main/java/com/auth0/android/lock/utils/LockException.java +++ b/lib/src/main/java/com/auth0/android/lock/utils/LockException.java @@ -26,10 +26,17 @@ import androidx.annotation.NonNull; +import com.auth0.android.authentication.AuthenticationException; + public class LockException extends Exception { public LockException(@NonNull String message) { super(message); } + + public LockException(@NonNull AuthenticationException exception) { + super(exception); + } + } diff --git a/lib/src/test/java/com/auth0/android/lock/AuthenticationCallbackTest.java b/lib/src/test/java/com/auth0/android/lock/AuthenticationCallbackTest.java index 931d23d20..f44537386 100644 --- a/lib/src/test/java/com/auth0/android/lock/AuthenticationCallbackTest.java +++ b/lib/src/test/java/com/auth0/android/lock/AuthenticationCallbackTest.java @@ -26,6 +26,7 @@ import android.content.Intent; +import com.auth0.android.authentication.AuthenticationException; import com.auth0.android.lock.LockCallback.LockEvent; import com.auth0.android.lock.utils.MockLockCallback; import com.auth0.android.result.Credentials; @@ -39,6 +40,7 @@ import java.util.Date; import static com.auth0.android.lock.utils.AuthenticationCallbackMatcher.hasAuthentication; +import static com.auth0.android.lock.utils.AuthenticationCallbackMatcher.hasError; import static com.auth0.android.lock.utils.AuthenticationCallbackMatcher.hasNoError; import static com.auth0.android.lock.utils.AuthenticationCallbackMatcher.isCanceled; import static org.hamcrest.CoreMatchers.equalTo; @@ -80,6 +82,16 @@ public void shouldReturnAuthentication() { assertThat(callback, hasNoError()); } + @Test + public void shouldReturnAuthenticationError() { + Intent data = new Intent(); + AuthenticationException error = new AuthenticationException("err_code", "err description"); + data.putExtra(Constants.EXCEPTION_EXTRA, error); + callback.onEvent(LockEvent.AUTHENTICATION, data); + + assertThat(callback, hasError()); + } + @Test public void shouldCallOnCanceled() { Intent data = new Intent(); From 32ae2cdb558c402f585974acd93acda04463b5ca Mon Sep 17 00:00:00 2001 From: Luciano Balmaceda Date: Tue, 27 Apr 2021 13:45:57 +0200 Subject: [PATCH 2/3] include access denied errors --- lib/src/main/java/com/auth0/android/lock/LockActivity.java | 4 ++-- .../java/com/auth0/android/lock/PasswordlessLockActivity.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/com/auth0/android/lock/LockActivity.java b/lib/src/main/java/com/auth0/android/lock/LockActivity.java index 737f810f6..ccbbc4b12 100644 --- a/lib/src/main/java/com/auth0/android/lock/LockActivity.java +++ b/lib/src/main/java/com/auth0/android/lock/LockActivity.java @@ -493,7 +493,7 @@ public void onFailure(@NonNull final Dialog dialog) { @Override public void onFailure(@NonNull final AuthenticationException exception) { Log.e(TAG, "Failed to authenticate the user: " + exception.getCode(), exception); - if (exception.isRuleError()) { + if (exception.isRuleError() || exception.isAccessDenied()) { deliverAuthenticationError(exception); return; } @@ -519,7 +519,7 @@ public void onSuccess(@Nullable Credentials credentials) { @Override public void onFailure(@NonNull final AuthenticationException error) { Log.e(TAG, "Failed to authenticate the user: " + error.getCode(), error); - if (error.isRuleError()) { + if (error.isRuleError() || error.isAccessDenied()) { deliverAuthenticationError(error); return; } diff --git a/lib/src/main/java/com/auth0/android/lock/PasswordlessLockActivity.java b/lib/src/main/java/com/auth0/android/lock/PasswordlessLockActivity.java index fb9baa6a8..df42fe1bf 100644 --- a/lib/src/main/java/com/auth0/android/lock/PasswordlessLockActivity.java +++ b/lib/src/main/java/com/auth0/android/lock/PasswordlessLockActivity.java @@ -502,7 +502,7 @@ public void onSuccess(@Nullable Credentials credentials) { @Override public void onFailure(@NonNull final AuthenticationException error) { Log.e(TAG, "Failed to authenticate the user: " + error.getMessage(), error); - if (error.isRuleError()) { + if (error.isRuleError() || error.isAccessDenied()) { deliverAuthenticationError(error); return; } @@ -520,7 +520,7 @@ public void onFailure(@NonNull final Dialog dialog) { @Override public void onFailure(@NonNull final AuthenticationException exception) { Log.e(TAG, "Failed to authenticate the user: " + exception.getCode(), exception); - if (exception.isRuleError()) { + if (exception.isRuleError() || exception.isAccessDenied()) { deliverAuthenticationError(exception); return; } From 7b7166f948f8385037d178da415b2d72f73cecaa Mon Sep 17 00:00:00 2001 From: Luciano Balmaceda Date: Tue, 27 Apr 2021 14:01:16 +0200 Subject: [PATCH 3/3] add entry to the migration guide --- MIGRATION_GUIDE.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index f0fcaf984..a4513299e 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -68,3 +68,7 @@ Continue reading for the detail of classes and methods that were impacted. ### Changes to the underlying SDK The core SDK has been updated to the version 2+. Since this is exposed as an API scoped dependency, if you were using any of the classes or methods that changed in the new major release (e.g. the `WebAuthProvider` class), you might need to update your code. Follow the [Auth0.Android Migration Guide](https://github.com/auth0/Auth0.Android/blob/main/V2_MIGRATION_GUIDE.md) to assess the impact. + +## Changes in behavior + +The `LockCallback` will get its `onError` method invoked when an [Auth0 Rule](https://auth0.com/docs/rules) returns an `Error` or `UnauthorizedError`. This was previously handled internally by Lock, causing it to display an orange toast with a generic failure message. From this release on, if you are using Auth0 Rules and throwing custom errors, you should obtain the _cause_ of the exception and read the code or description values to understand what went wrong. \ No newline at end of file