package org.openmhealth.reference.domain; import java.util.UUID; import org.joda.time.DateTime; import org.openmhealth.reference.data.AuthorizationCodeBin; import org.openmhealth.reference.data.AuthorizationCodeResponseBin; import org.openmhealth.reference.exception.OmhException; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; /** * <p> * The authorization token for a user to grant access to some scope (e.g. * schema IDs) to some third-party. * </p> * * <p> * This class is immutable. * </p> * * @author John Jenkins */ public class AuthorizationToken implements OmhObject { /** * The version of this class used for serialization purposes. */ private static final long serialVersionUID = 1L; /** * The default number of milliseconds that a token should live. */ public static final long DEFAULT_TOKEN_LIFETIME_MILLIS = 1000 * 60 * 60; /** * The JSON key for the authorization code that backs this authorization * token. */ public static final String JSON_KEY_AUTHORIZATION_CODE = "authorization_code"; /** * The JSON key for the access token. */ public static final String JSON_KEY_ACCESS_TOKEN = "access_token"; /** * The JSON key for the refresh token. */ public static final String JSON_KEY_REFRESH_TOKEN = "refresh_token"; /** * The JSON key for the time the token was created. */ public static final String JSON_KEY_CREATION_TIME = "creation_time"; /** * The JSON key for the time the token expires. */ public static final String JSON_KEY_EXPIRATION_TIME = "expiration_time"; /** * The authorization code that backs this authorization token. When * referencing or refreshing this token, this code and its corresponding * response should be consulted to determine the scope and whether or not * this authorization has been revoked. */ @JsonProperty(JSON_KEY_AUTHORIZATION_CODE) private final String authorizationCode; /** * The access token. */ @JsonProperty(JSON_KEY_ACCESS_TOKEN) private final String accessToken; /** * The refresh token. */ @JsonProperty(JSON_KEY_REFRESH_TOKEN) private final String refreshToken; /** * The number of milliseconds since the epoch at which time this token was * created. */ @JsonProperty(JSON_KEY_CREATION_TIME) private final long creationTime; /** * The number of milliseconds since the epoch at which time this token * expires. */ @JsonProperty(JSON_KEY_EXPIRATION_TIME) private final long expirationTime; /** * Creates a new authorization token. * * @param response * The authorization code response that will be associated with this * token and all subsequent tokens that are created by refreshing * this and those tokens. * * @throws OmhException * A parameter is invalid. */ public AuthorizationToken( final AuthorizationCodeResponse response) throws OmhException { // Validate the parameters. if(response == null) { throw new OmhException("The response is null."); } else if(! response.getGranted()) { throw new OmhException( "An authorization token cannot be created for an " + "authorization code that was denied."); } // Store the relevant information. this.authorizationCode = response.getAuthorizationCode(); this.accessToken = UUID.randomUUID().toString(); this.refreshToken = UUID.randomUUID().toString(); this.creationTime = DateTime.now().getMillis(); this.expirationTime = this.creationTime + DEFAULT_TOKEN_LIFETIME_MILLIS; } /** * Creates a new authentication token with new access and refresh tokens * and new creation and expiration times. This is not a copy constructor. * This is designed for creating new tokens via a refresh. * * @param oldToken * The old token that will be used to create the new token. * * @throws OmhException * The old token was null or already invalidated. */ public AuthorizationToken( final AuthorizationToken oldToken) throws OmhException { // Validate the token. if(oldToken == null) { throw new OmhException("The token is null."); } // Store the relevant information. this.authorizationCode = oldToken.authorizationCode; this.accessToken = UUID.randomUUID().toString(); this.refreshToken = UUID.randomUUID().toString(); this.creationTime = DateTime.now().getMillis(); this.expirationTime = this.creationTime + DEFAULT_TOKEN_LIFETIME_MILLIS; } /** * Creates an authorization token presumably from an existing one since all * of the fields are given. To create a new token, it is recommended that * {@link #AuthorizationToken(AuthorizationCodeResponse)} or * {@link #AuthorizationToken(AuthorizationToken)} be used. * * @param authorizationCode * The unique identifier for the authorization code that backs this * token. * * @param accessToken * The access token value for this authorization token. * * @param refreshToken * The refresh token value for this authorization token. * * @param creationTime * The number of milliseconds since the epoch at which time this * token was created. * * @param expirationTime * The number of milliseconds since the epoch at which time this * token expires. * * @throws OmhException * A parameter is invalid. * * @see #AuthorizationToken(AuthorizationCodeResponse) * @see #AuthorizationToken(AuthorizationToken) */ @JsonCreator public AuthorizationToken( @JsonProperty(JSON_KEY_AUTHORIZATION_CODE) final String authorizationCode, @JsonProperty(JSON_KEY_ACCESS_TOKEN) final String accessToken, @JsonProperty(JSON_KEY_REFRESH_TOKEN) final String refreshToken, @JsonProperty(JSON_KEY_CREATION_TIME) final long creationTime, @JsonProperty(JSON_KEY_EXPIRATION_TIME) final long expirationTime) throws OmhException { // Validate the authorization code. if(authorizationCode == null) { throw new OmhException("The authorization code is null."); } else { this.authorizationCode = authorizationCode; } // Validate the access token. if(accessToken == null) { throw new OmhException("The access token is null."); } else { this.accessToken = accessToken; } // Validate the refresh token. if(refreshToken == null) { throw new OmhException("The refresh token is null."); } else { this.refreshToken = refreshToken; } // Validate the creation time. DateTime creationTimeDateTime = new DateTime(creationTime); if(creationTimeDateTime.isAfterNow()) { throw new OmhException( "The token's creation time cannot be in the future."); } else { this.creationTime = creationTime; } // Validate the expiration time. if(creationTimeDateTime.isAfter(expirationTime)) { throw new OmhException( "The token's expiration time cannot be before its " + "creation time."); } else { this.expirationTime = expirationTime; } } /** * Returns the authorization code that backs this authorization token. * * @return The authorization code that backs this authorization token as a * string. */ public String getAuthorizationCodeString() { return authorizationCode; } /** * Returns the authorization code that backs this authorization token. * * @return The authorization code that backs this authorization token. */ public AuthorizationCode getAuthorizationCode() { return AuthorizationCodeBin.getInstance().getCode(authorizationCode); } /** * Returns the authorization code response that backs this authorization * token. * * @return The authorization code response that backs this authorization * token. */ public AuthorizationCodeResponse getAuthorizationCodeVerification() { return AuthorizationCodeResponseBin .getInstance().getResponse(authorizationCode); } /** * Returns the third-party associated with this authorization token. * * @return The third-party associated with this authorization token. */ public ThirdParty getThirdParty() { return AuthorizationCodeBin .getInstance().getCode(authorizationCode).getThirdParty(); } /** * Returns the access token. * * @return The access token. */ public String getAccessToken() { return accessToken; } /** * Returns the refresh token. * * @return The refresh token. */ public String getRefreshToken() { return refreshToken; } /** * Returns the time that the token was created. * * @return The time that the token was created. */ public long getCreationTime() { return creationTime; } /** * Returns the time that the token was/will expire. * * @return The time that the token was/will expire. */ public long getExpirationTime() { return expirationTime; } /** * Returns the number of milliseconds before the access token expires. * * @return The number of milliseconds before the access token expires. This * may be negative if the token has already expired. */ public long getExpirationIn() { return expirationTime - DateTime.now().getMillis(); } }