-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #96 from auth0/credentials-storage
Add CredentialsManager and generic Storage
- Loading branch information
Showing
17 changed files
with
1,113 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
auth0/src/main/java/com/auth0/android/authentication/storage/CredentialsManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package com.auth0.android.authentication.storage; | ||
|
||
import android.support.annotation.NonNull; | ||
import android.support.annotation.VisibleForTesting; | ||
|
||
import com.auth0.android.authentication.AuthenticationAPIClient; | ||
import com.auth0.android.authentication.AuthenticationException; | ||
import com.auth0.android.callback.AuthenticationCallback; | ||
import com.auth0.android.callback.BaseCallback; | ||
import com.auth0.android.result.Credentials; | ||
|
||
import java.util.Date; | ||
|
||
import static android.text.TextUtils.isEmpty; | ||
|
||
/** | ||
* Class that handles credentials and allows to save and retrieve them. | ||
*/ | ||
@SuppressWarnings({"WeakerAccess", "unused"}) | ||
public class CredentialsManager { | ||
private static final String KEY_ACCESS_TOKEN = "com.auth0.access_token"; | ||
private static final String KEY_REFRESH_TOKEN = "com.auth0.refresh_token"; | ||
private static final String KEY_ID_TOKEN = "com.auth0.id_token"; | ||
private static final String KEY_TOKEN_TYPE = "com.auth0.token_type"; | ||
private static final String KEY_EXPIRES_AT = "com.auth0.expires_at"; | ||
private static final String KEY_SCOPE = "com.auth0.scope"; | ||
|
||
private final AuthenticationAPIClient authClient; | ||
private final Storage storage; | ||
|
||
/** | ||
* Creates a new instance of the manager that will store the credentials in the given Storage. | ||
* | ||
* @param authenticationClient the Auth0 Authentication client to refresh credentials with. | ||
* @param storage the storage to use for the credentials. | ||
*/ | ||
public CredentialsManager(@NonNull AuthenticationAPIClient authenticationClient, @NonNull Storage storage) { | ||
this.authClient = authenticationClient; | ||
this.storage = storage; | ||
} | ||
|
||
/** | ||
* Stores the given credentials in the storage. Must have an access_token or id_token and a expires_in value. | ||
* | ||
* @param credentials the credentials to save in the storage. | ||
*/ | ||
public void saveCredentials(@NonNull Credentials credentials) { | ||
if ((isEmpty(credentials.getAccessToken()) && isEmpty(credentials.getIdToken())) || credentials.getExpiresAt() == null) { | ||
throw new CredentialsManagerException("Credentials must have a valid date of expiration and a valid access_token or id_token value."); | ||
} | ||
storage.store(KEY_ACCESS_TOKEN, credentials.getAccessToken()); | ||
storage.store(KEY_REFRESH_TOKEN, credentials.getRefreshToken()); | ||
storage.store(KEY_ID_TOKEN, credentials.getIdToken()); | ||
storage.store(KEY_TOKEN_TYPE, credentials.getType()); | ||
storage.store(KEY_EXPIRES_AT, credentials.getExpiresAt().getTime()); | ||
storage.store(KEY_SCOPE, credentials.getScope()); | ||
} | ||
|
||
/** | ||
* Retrieves the credentials from the storage and refresh them if they have already expired. | ||
* It will fail with {@link CredentialsManagerException} if the saved access_token or id_token is null, | ||
* or if the tokens have already expired and the refresh_token is null. | ||
* | ||
* @param callback the callback that will receive a valid {@link Credentials} or the {@link CredentialsManagerException}. | ||
*/ | ||
public void getCredentials(@NonNull final BaseCallback<Credentials, CredentialsManagerException> callback) { | ||
String accessToken = storage.retrieveString(KEY_ACCESS_TOKEN); | ||
String refreshToken = storage.retrieveString(KEY_REFRESH_TOKEN); | ||
String idToken = storage.retrieveString(KEY_ID_TOKEN); | ||
String tokenType = storage.retrieveString(KEY_TOKEN_TYPE); | ||
Long expiresAt = storage.retrieveLong(KEY_EXPIRES_AT); | ||
String scope = storage.retrieveString(KEY_SCOPE); | ||
|
||
if (isEmpty(accessToken) && isEmpty(idToken) || expiresAt == null) { | ||
callback.onFailure(new CredentialsManagerException("No Credentials were previously set.")); | ||
return; | ||
} | ||
if (expiresAt > getCurrentTimeInMillis()) { | ||
callback.onSuccess(recreateCredentials(idToken, accessToken, tokenType, refreshToken, new Date(expiresAt), scope)); | ||
return; | ||
} | ||
if (refreshToken == null) { | ||
callback.onFailure(new CredentialsManagerException("Credentials have expired and no Refresh Token was available to renew them.")); | ||
return; | ||
} | ||
|
||
authClient.renewAuth(refreshToken).start(new AuthenticationCallback<Credentials>() { | ||
@Override | ||
public void onSuccess(Credentials freshCredentials) { | ||
callback.onSuccess(freshCredentials); | ||
} | ||
|
||
@Override | ||
public void onFailure(AuthenticationException error) { | ||
callback.onFailure(new CredentialsManagerException("An error occurred while trying to use the Refresh Token to renew the Credentials.", error)); | ||
} | ||
}); | ||
} | ||
|
||
@VisibleForTesting | ||
Credentials recreateCredentials(String idToken, String accessToken, String tokenType, String refreshToken, Date expiresAt, String scope) { | ||
return new Credentials(idToken, accessToken, tokenType, refreshToken, expiresAt, scope); | ||
} | ||
|
||
@VisibleForTesting | ||
long getCurrentTimeInMillis() { | ||
return System.currentTimeMillis(); | ||
} | ||
|
||
} |
18 changes: 18 additions & 0 deletions
18
...0/src/main/java/com/auth0/android/authentication/storage/CredentialsManagerException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.auth0.android.authentication.storage; | ||
|
||
|
||
import com.auth0.android.Auth0Exception; | ||
|
||
/** | ||
* Represents an error raised by the {@link CredentialsManager}. | ||
*/ | ||
@SuppressWarnings("WeakerAccess") | ||
public class CredentialsManagerException extends Auth0Exception { | ||
public CredentialsManagerException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
|
||
public CredentialsManagerException(String message) { | ||
super(message); | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
auth0/src/main/java/com/auth0/android/authentication/storage/SharedPreferencesStorage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package com.auth0.android.authentication.storage; | ||
|
||
|
||
import android.content.Context; | ||
import android.content.SharedPreferences; | ||
import android.support.annotation.NonNull; | ||
import android.support.annotation.Nullable; | ||
import android.text.TextUtils; | ||
|
||
/** | ||
* An implementation of {@link Storage} that uses {@link android.content.SharedPreferences} in Context.MODE_PRIVATE to store the values. | ||
*/ | ||
@SuppressWarnings({"WeakerAccess", "unused"}) | ||
public class SharedPreferencesStorage implements Storage { | ||
|
||
private static final String SHARED_PREFERENCES_NAME = "com.auth0.authentication.storage"; | ||
|
||
private final SharedPreferences sp; | ||
|
||
/** | ||
* Creates a new {@link Storage} that uses {@link SharedPreferences} in Context.MODE_PRIVATE to store values. | ||
* | ||
* @param context a valid context | ||
*/ | ||
public SharedPreferencesStorage(@NonNull Context context) { | ||
this(context, SHARED_PREFERENCES_NAME); | ||
} | ||
|
||
/** | ||
* Creates a new {@link Storage} that uses {@link SharedPreferences} in Context.MODE_PRIVATE to store values. | ||
* | ||
* @param context a valid context | ||
* @param sharedPreferencesName the preferences file name | ||
*/ | ||
public SharedPreferencesStorage(@NonNull Context context, @NonNull String sharedPreferencesName) { | ||
if (TextUtils.isEmpty(sharedPreferencesName)) { | ||
throw new IllegalArgumentException("The SharedPreferences name is invalid."); | ||
} | ||
sp = context.getSharedPreferences(sharedPreferencesName, Context.MODE_PRIVATE); | ||
} | ||
|
||
@Override | ||
public void store(@NonNull String name, @Nullable Long value) { | ||
if (value == null) { | ||
sp.edit().remove(name).apply(); | ||
} else { | ||
sp.edit().putLong(name, value).apply(); | ||
} | ||
} | ||
|
||
@Override | ||
public void store(@NonNull String name, @Nullable Integer value) { | ||
if (value == null) { | ||
sp.edit().remove(name).apply(); | ||
} else { | ||
sp.edit().putInt(name, value).apply(); | ||
} | ||
} | ||
|
||
@Override | ||
public void store(@NonNull String name, @Nullable String value) { | ||
if (value == null) { | ||
sp.edit().remove(name).apply(); | ||
} else { | ||
sp.edit().putString(name, value).apply(); | ||
} | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public Long retrieveLong(@NonNull String name) { | ||
if (!sp.contains(name)) { | ||
return null; | ||
} | ||
return sp.getLong(name, 0); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public String retrieveString(@NonNull String name) { | ||
if (!sp.contains(name)) { | ||
return null; | ||
} | ||
return sp.getString(name, null); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public Integer retrieveInteger(@NonNull String name) { | ||
if (!sp.contains(name)) { | ||
return null; | ||
} | ||
return sp.getInt(name, 0); | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
auth0/src/main/java/com/auth0/android/authentication/storage/Storage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package com.auth0.android.authentication.storage; | ||
|
||
import android.support.annotation.NonNull; | ||
import android.support.annotation.Nullable; | ||
|
||
/** | ||
* Represents a Storage of key-value data. | ||
* Supported classes are String, Long and Integer. | ||
*/ | ||
@SuppressWarnings("WeakerAccess") | ||
public interface Storage { | ||
|
||
/** | ||
* Store a given value in the Storage. | ||
* | ||
* @param name the name of the value to store. | ||
* @param value the value to store. Can be null. | ||
*/ | ||
void store(@NonNull String name, @Nullable Long value); | ||
|
||
/** | ||
* Store a given value in the Storage. | ||
* | ||
* @param name the name of the value to store. | ||
* @param value the value to store. Can be null. | ||
*/ | ||
void store(@NonNull String name, @Nullable Integer value); | ||
|
||
/** | ||
* Store a given value in the Storage. | ||
* | ||
* @param name the name of the value to store. | ||
* @param value the value to store. Can be null. | ||
*/ | ||
void store(@NonNull String name, @Nullable String value); | ||
|
||
/** | ||
* Retrieve a value from the Storage. | ||
* | ||
* @param name the name of the value to retrieve. | ||
* @return the value that was previously saved. Can be null. | ||
*/ | ||
@Nullable | ||
Long retrieveLong(@NonNull String name); | ||
|
||
/** | ||
* Retrieve a value from the Storage. | ||
* | ||
* @param name the name of the value to retrieve. | ||
* @return the value that was previously saved. Can be null. | ||
*/ | ||
@Nullable | ||
String retrieveString(@NonNull String name); | ||
|
||
/** | ||
* Retrieve a value from the Storage. | ||
* | ||
* @param name the name of the value to retrieve. | ||
* @return the value that was previously saved. Can be null. | ||
*/ | ||
@Nullable | ||
Integer retrieveInteger(@NonNull String name); | ||
} |
Oops, something went wrong.