Skip to content

Commit

Permalink
Merge pull request #115 from auth0/add-encrypted-manager
Browse files Browse the repository at this point in the history
Add an encrypted version of the CredentialsManager
  • Loading branch information
lbalmaceda authored Oct 5, 2017
2 parents 55a1d30 + ef3ebf9 commit dac05f1
Show file tree
Hide file tree
Showing 17 changed files with 2,224 additions and 48 deletions.
65 changes: 57 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,20 +434,26 @@ users
> In all the cases, the `User ID` parameter is the unique identifier of the auth0 account instance. i.e. in `google-oauth2|123456789081523216417` it would be the part after the '|' pipe: `123456789081523216417`.

### Credentials Manager
This library ships with a `CredentialsManager` class to easily store and retrieve fresh Credentials from a given `Storage`.

## Credentials Manager

This library ships with two additional classes that help you manage the Credentials received during authentication. Depending on the minimum API level that your application is targeting you'd like to use a different implementation.

### Basic (Min API 15)

The basic version supports asking for `Credentials` existence, storing them and getting them back. If the credentials have expired and a refresh_token was saved, they are automatically refreshed. The class is called `CredentialsManager`.

#### Usage
1. **Instantiate the manager**
You'll need an `AuthenticationAPIClient` instance used to renew the credentials when they expire and a `Storage`. The Storage implementation is up to you. We provide a `SharedPreferencesStorage` that uses `SharedPreferences` to create a file in the application's directory with Context.MODE_PRIVATE mode. This implementation is thread safe and can either be obtained through a Singleton like method or be created every time it's needed.
1. **Instantiate the manager:**
You'll need an `AuthenticationAPIClient` instance to renew the credentials when they expire and a `Storage`. We provide a `SharedPreferencesStorage` that uses `SharedPreferences` to create a file in the application's directory with **Context.MODE_PRIVATE** mode. This implementation is thread safe and can either be obtained through a shared method or on demand.

```java
AuthenticationAPIClient authentication = new AuthenticationAPIClient(account);
Storage storage = new SharedPreferencesStorage(this);
CredentialsManager manager = new CredentialsManager(authentication, storage);
```

2. **Save credentials**
2. **Save credentials:**
The credentials to save **must have** `expires_in` and at least an `access_token` or `id_token` value. If one of the values is missing when trying to set the credentials, the method will throw a `CredentialsManagerException`. If you want the manager to successfully renew the credentials when expired you must also request the `offline_access` scope when logging in in order to receive a `refresh_token` value along with the rest of the tokens. i.e. Logging in with a database connection and saving the credentials:

```java
Expand All @@ -468,14 +474,14 @@ authentication
});
```

3. **Check credentials existence**
3. **Check credentials existence:**
There are cases were you just want to check if a user session is still valid (i.e. to know if you should present the login screen or the main screen). For convenience we include a `hasValidCredentials` method that can let you know in advance if a non-expired token is available without making an additional network call. The same rules of the `getCredentials` method apply:

```java
boolean authenticated = manager.hasValidCredentials();
```

4. **Retrieve credentials**
4. **Retrieve credentials:**
Existing credentials will be returned if they are still valid, otherwise the `refresh_token` will be used to attempt to renew them. If the `expires_in` or both the `access_token` and `id_token` values are missing, the method will throw a `CredentialsManagerException`. The same will happen if the credentials have expired and there's no `refresh_token` available.

```java
Expand All @@ -491,13 +497,56 @@ manager.getCredentials(new BaseCallback<Credentials, CredentialsManagerException
```


5. **Clear credentials**
5. **Clear credentials:**
When you want to log the user out:

```java
manager.clearCredentials();
```


### Encryption enforced (Min API 21)

This version expands the minimum version and adds encryption to the data storage. In those devices where a Secure LockScreen has been configured it can require the user authentication before letting them obtain the stored credentials. The class is called `SecureCredentialsManager`.


#### Usage
The usage is similar to the previous version, with the slight difference that the manager now requires a valid `Context` as shown below:

```java
AuthenticationAPIClient authentication = new AuthenticationAPIClient(account);
Storage storage = new SharedPreferencesStorage(this);
SecureCredentialsManager manager = new SecureCredentialsManager(this, authentication, storage);
```

#### Requiring Authentication

You can require the user authentication to obtain credentials. This will make the manager prompt the user with the device's configured LockScreen, which they must pass correctly in order to obtain the credentials. **This feature is only available on devices where the user has setup a secured LockScreen** (PIN, Pattern, Password or Fingerprint).

To enable authentication you must call the `requireAuthentication` method passing a valid _Activity_ context, a Request Code that represents the authentication call, and the title and description to display in the LockScreen. As seen in the snippet below, you can leave these last two parameters with `null` to use the system default resources.

```java
//You might want to define a constant with the Request Code
private static final int AUTH_REQ_CODE = 11;

manager.requireAuthentication(this, AUTH_REQ_CODE, null, null);
```

When the above conditions are met and the manager requires the user authentication, it will use the activity context to launch a new activity for result. The outcome of getting approved or rejected by the LockScreen is given back to the activity in the `onActivityResult` method, which your activity must override to redirect the data to the manager using the `checkAuthenticationResult` method.

```java
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (manager.checkAuthenticationResult(requestCode, resultCode)) {
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
```

The `checkAuthenticationResult` method will continue the retrieval of credentials on a successful authentication, and the decrypted credentials will be delivered to the callback passed on the `getCredentials` call.


## FAQ

* Why is the Android Lint _error_ `'InvalidPackage'` considered a _warning_?
Expand Down
5 changes: 4 additions & 1 deletion auth0/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,12 @@ dependencies {

testCompile 'junit:junit:4.12'
testCompile 'org.hamcrest:java-hamcrest:2.0.0.0'
testCompile 'org.powermock:powermock-module-junit4:1.6.5'
testCompile 'org.powermock:powermock-module-junit4-rule:1.6.5'
testCompile 'org.powermock:powermock-api-mockito:1.6.5'
testCompile 'org.mockito:mockito-core:1.10.19'
testCompile 'com.squareup.okhttp:mockwebserver:2.7.5'
testCompile 'com.jayway.awaitility:awaitility:1.6.4'
testCompile 'org.robolectric:robolectric:3.1.2'
testCompile 'org.robolectric:robolectric:3.4.2'
testCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
*/
@SuppressWarnings("WeakerAccess")
public class CredentialsManagerException extends Auth0Exception {
public CredentialsManagerException(String message, Throwable cause) {
CredentialsManagerException(String message, Throwable cause) {
super(message, cause);
}

public CredentialsManagerException(String message) {
CredentialsManagerException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.auth0.android.authentication.storage;

/**
* Exception thrown by the {@link CryptoUtil} class whenever an operation goes wrong.
*/
public class CryptoException extends RuntimeException {
CryptoException(String message, Throwable cause) {
super(message, cause);
}
}
Loading

0 comments on commit dac05f1

Please sign in to comment.