diff --git a/auth0/src/main/java/com/auth0/android/authentication/storage/SecureCredentialsManager.java b/auth0/src/main/java/com/auth0/android/authentication/storage/SecureCredentialsManager.java index 2fde37d7b..3b2bbf9a9 100644 --- a/auth0/src/main/java/com/auth0/android/authentication/storage/SecureCredentialsManager.java +++ b/auth0/src/main/java/com/auth0/android/authentication/storage/SecureCredentialsManager.java @@ -41,7 +41,9 @@ public class SecureCredentialsManager { private static final String KEY_CREDENTIALS = "com.auth0.credentials"; private static final String KEY_EXPIRES_AT = "com.auth0.credentials_expires_at"; private static final String KEY_CAN_REFRESH = "com.auth0.credentials_can_refresh"; - private static final String KEY_ALIAS = "com.auth0.key"; + private static final String KEY_CRYPTO_ALIAS = "com.auth0.manager_key_alias"; + @VisibleForTesting + static final String KEY_ALIAS = "com.auth0.key"; private final AuthenticationAPIClient apiClient; private final Storage storage; @@ -165,6 +167,7 @@ public void saveCredentials(@NonNull Credentials credentials) throws Credentials storage.store(KEY_CREDENTIALS, encryptedEncoded); storage.store(KEY_EXPIRES_AT, expiresAt); storage.store(KEY_CAN_REFRESH, canRefresh); + storage.store(KEY_CRYPTO_ALIAS, KEY_ALIAS); } catch (IncompatibleDeviceException e) { throw new CredentialsManagerException(String.format("This device is not compatible with the %s class.", SecureCredentialsManager.class.getSimpleName()), e); } catch (CryptoException e) { @@ -211,6 +214,7 @@ public void clearCredentials() { storage.remove(KEY_CREDENTIALS); storage.remove(KEY_EXPIRES_AT); storage.remove(KEY_CAN_REFRESH); + storage.remove(KEY_CRYPTO_ALIAS); Log.d(TAG, "Credentials were just removed from the storage"); } @@ -223,9 +227,10 @@ public boolean hasValidCredentials() { String encryptedEncoded = storage.retrieveString(KEY_CREDENTIALS); Long expiresAt = storage.retrieveLong(KEY_EXPIRES_AT); Boolean canRefresh = storage.retrieveBoolean(KEY_CAN_REFRESH); - return !(isEmpty(encryptedEncoded) || - expiresAt == null || - expiresAt <= getCurrentTimeInMillis() && (canRefresh == null || !canRefresh)); + String keyAliasUsed = storage.retrieveString(KEY_CRYPTO_ALIAS); + return KEY_ALIAS.equals(keyAliasUsed) && + !(isEmpty(encryptedEncoded) || expiresAt == null || + expiresAt <= getCurrentTimeInMillis() && (canRefresh == null || !canRefresh)); } private void continueGetCredentials(final BaseCallback callback) { diff --git a/auth0/src/test/java/com/auth0/android/authentication/storage/SecureCredentialsManagerTest.java b/auth0/src/test/java/com/auth0/android/authentication/storage/SecureCredentialsManagerTest.java index cc684574b..389b71e9f 100644 --- a/auth0/src/test/java/com/auth0/android/authentication/storage/SecureCredentialsManagerTest.java +++ b/auth0/src/test/java/com/auth0/android/authentication/storage/SecureCredentialsManagerTest.java @@ -128,6 +128,7 @@ public void shouldSaveRefreshableCredentialsInStorage() { verify(storage).store(eq("com.auth0.credentials"), stringCaptor.capture()); verify(storage).store("com.auth0.credentials_expires_at", sharedExpirationTime); verify(storage).store("com.auth0.credentials_can_refresh", true); + verify(storage).store("com.auth0.manager_key_alias", SecureCredentialsManager.KEY_ALIAS); verifyNoMoreInteractions(storage); final String encodedJson = stringCaptor.getValue(); assertThat(encodedJson, is(notNullValue())); @@ -155,6 +156,7 @@ public void shouldSaveRefreshableCredentialsUsingAccessTokenExpForCacheExpiratio verify(storage).store(eq("com.auth0.credentials"), stringCaptor.capture()); verify(storage).store("com.auth0.credentials_expires_at", accessTokenExpirationTime); verify(storage).store("com.auth0.credentials_can_refresh", true); + verify(storage).store("com.auth0.manager_key_alias", SecureCredentialsManager.KEY_ALIAS); verifyNoMoreInteractions(storage); final String encodedJson = stringCaptor.getValue(); assertThat(encodedJson, is(notNullValue())); @@ -183,6 +185,7 @@ public void shouldSaveRefreshableCredentialsUsingIdTokenExpForCacheExpirationInS verify(storage).store(eq("com.auth0.credentials"), stringCaptor.capture()); verify(storage).store("com.auth0.credentials_expires_at", idTokenExpirationTime); verify(storage).store("com.auth0.credentials_can_refresh", true); + verify(storage).store("com.auth0.manager_key_alias", SecureCredentialsManager.KEY_ALIAS); verifyNoMoreInteractions(storage); final String encodedJson = stringCaptor.getValue(); assertThat(encodedJson, is(notNullValue())); @@ -210,6 +213,7 @@ public void shouldSaveNonRefreshableCredentialsInStorage() { verify(storage).store(eq("com.auth0.credentials"), stringCaptor.capture()); verify(storage).store("com.auth0.credentials_expires_at", expirationTime); verify(storage).store("com.auth0.credentials_can_refresh", false); + verify(storage).store("com.auth0.manager_key_alias", SecureCredentialsManager.KEY_ALIAS); verifyNoMoreInteractions(storage); final String encodedJson = stringCaptor.getValue(); assertThat(encodedJson, is(notNullValue())); @@ -573,6 +577,7 @@ public void shouldClearCredentials() { verify(storage).remove("com.auth0.credentials"); verify(storage).remove("com.auth0.credentials_expires_at"); verify(storage).remove("com.auth0.credentials_can_refresh"); + verify(storage).remove("com.auth0.manager_key_alias"); verifyNoMoreInteractions(storage); } @@ -586,6 +591,7 @@ public void shouldHaveCredentialsWhenTokenHasNotExpired() { when(storage.retrieveLong("com.auth0.credentials_expires_at")).thenReturn(expirationTime); when(storage.retrieveBoolean("com.auth0.credentials_can_refresh")).thenReturn(false); when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"id_token\":\"idToken\"}"); + when(storage.retrieveString("com.auth0.manager_key_alias")).thenReturn(SecureCredentialsManager.KEY_ALIAS); assertThat(manager.hasValidCredentials(), is(true)); when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"access_token\":\"accessToken\"}"); @@ -598,6 +604,7 @@ public void shouldNotHaveCredentialsWhenTokenHasExpiredAndNoRefreshTokenIsAvaila when(storage.retrieveLong("com.auth0.credentials_expires_at")).thenReturn(expirationTime); when(storage.retrieveBoolean("com.auth0.credentials_can_refresh")).thenReturn(false); when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"id_token\":\"idToken\"}"); + when(storage.retrieveString("com.auth0.manager_key_alias")).thenReturn(SecureCredentialsManager.KEY_ALIAS); assertThat(manager.hasValidCredentials(), is(false)); when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"access_token\":\"accessToken\"}"); @@ -610,6 +617,7 @@ public void shouldHaveCredentialsWhenTokenHasExpiredButRefreshTokenIsAvailable() when(storage.retrieveLong("com.auth0.credentials_expires_at")).thenReturn(expirationTime); when(storage.retrieveBoolean("com.auth0.credentials_can_refresh")).thenReturn(true); when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"id_token\":\"idToken\", \"refresh_token\":\"refreshToken\"}"); + when(storage.retrieveString("com.auth0.manager_key_alias")).thenReturn(SecureCredentialsManager.KEY_ALIAS); assertThat(manager.hasValidCredentials(), is(true)); when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"access_token\":\"accessToken\", \"refresh_token\":\"refreshToken\"}"); @@ -619,10 +627,37 @@ public void shouldHaveCredentialsWhenTokenHasExpiredButRefreshTokenIsAvailable() @Test public void shouldNotHaveCredentialsWhenAccessTokenAndIdTokenAreMissing() { when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"token_type\":\"type\", \"refresh_token\":\"refreshToken\"}"); + when(storage.retrieveString("com.auth0.manager_key_alias")).thenReturn(SecureCredentialsManager.KEY_ALIAS); assertFalse(manager.hasValidCredentials()); } + @Test + public void shouldNotHaveCredentialsWhenTheAliasUsedHasNotBeenMigratedYet() { + long expirationTime = CredentialsMock.CURRENT_TIME_MS + 123456L * 1000; + when(storage.retrieveLong("com.auth0.credentials_expires_at")).thenReturn(expirationTime); + when(storage.retrieveBoolean("com.auth0.credentials_can_refresh")).thenReturn(false); + when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"id_token\":\"idToken\"}"); + when(storage.retrieveString("com.auth0.manager_key_alias")).thenReturn("old_alias"); + assertThat(manager.hasValidCredentials(), is(false)); + + when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"access_token\":\"accessToken\"}"); + assertThat(manager.hasValidCredentials(), is(false)); + } + + @Test + public void shouldNotHaveCredentialsWhenTheAliasUsedHasNotBeenSetYet() { + long expirationTime = CredentialsMock.CURRENT_TIME_MS + 123456L * 1000; + when(storage.retrieveLong("com.auth0.credentials_expires_at")).thenReturn(expirationTime); + when(storage.retrieveBoolean("com.auth0.credentials_can_refresh")).thenReturn(false); + when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"id_token\":\"idToken\"}"); + when(storage.retrieveString("com.auth0.manager_key_alias")).thenReturn(null); + assertThat(manager.hasValidCredentials(), is(false)); + + when(storage.retrieveString("com.auth0.credentials")).thenReturn("{\"access_token\":\"accessToken\"}"); + assertThat(manager.hasValidCredentials(), is(false)); + } + /* * Authentication tests */ @@ -860,6 +895,7 @@ private String insertTestCredentials(boolean hasIdToken, boolean hasAccessToken, when(storage.retrieveString("com.auth0.credentials")).thenReturn(encoded); when(storage.retrieveLong("com.auth0.credentials_expires_at")).thenReturn(willExpireAt != null ? willExpireAt.getTime() : null); when(storage.retrieveBoolean("com.auth0.credentials_can_refresh")).thenReturn(hasRefreshToken); + when(storage.retrieveString("com.auth0.manager_key_alias")).thenReturn(SecureCredentialsManager.KEY_ALIAS); return storedJson; }