package org.openmhealth.reference.domain; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.UUID; import org.joda.time.DateTime; import org.openmhealth.reference.data.ThirdPartyBin; import org.openmhealth.reference.exception.OmhException; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; /** * <p> * The authorization code generated for a third-party to give to a user when * attempting to gain authorization to some set of data. * </p> * * <p> * This class is immutable. * </p> * * @author John Jenkins */ public class AuthorizationCode 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_CODE_LIFETIME_MILLIS = 1000 * 60 * 5; /** * The JSON key for the identifier of a third-party that this token * references. */ public static final String JSON_KEY_THIRD_PARTY = "third_party"; /** * The JSON key for the code. */ public static final String JSON_KEY_CODE = "code"; /** * 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 JSON key for the list of scopes to which this key applies. */ public static final String JSON_KEY_SCOPES = "scopes"; /** * The JSON key for the state that was given to the server when the code * was created. */ public static final String JSON_KEY_STATE = "state"; /** * The unique identifier for the third-party to which this token applies. */ @JsonProperty(JSON_KEY_THIRD_PARTY) private final String thirdParty; /** * The code value. */ @JsonProperty(JSON_KEY_CODE) private final String code; /** * 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; /** * The set of scopes to which this token applies. */ @JsonProperty(JSON_KEY_SCOPES) private final Set<String> scopes = new HashSet<String>(); /** * The state given by the third-party when this code was created. */ @JsonProperty(JSON_KEY_STATE) private final String state; /** * Creates a new, valid authorization code. * * @param thirdParty * The third-party to which this token will apply. * * @param scopes * The set of scopes, e.g. schema IDs, that apply to this * authorization token. * * @throws OmhException * A parameter is invalid. */ public AuthorizationCode( final ThirdParty thirdParty, final Set<String> scopes, final String state) throws OmhException { // Validate the parameters. if(thirdParty == null) { throw new OmhException("The third-party is null."); } else if(scopes == null) { throw new OmhException("The scopes is null."); } else if(scopes.size() == 0) { throw new OmhException( "An authorization token cannot be created without any " + "scope."); } // Store the relevant information. this.thirdParty = thirdParty.getId(); this.code = UUID.randomUUID().toString(); this.creationTime = DateTime.now().getMillis(); this.expirationTime = this.creationTime + DEFAULT_CODE_LIFETIME_MILLIS; this.scopes.addAll(scopes); this.state = state; } /** * Creates an authorization code presumably from an existing one since all * of the fields are given. To create a new code, it is recommended that * {@link #AuthorizationCode(ThirdParty, Set, String)} be used. * * @param thirdParty * The unique identifier for the third-party to which this token * pertains. * * @param code * The code 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. * * @param scopes * The set of scopes for this token. * * @param state * The state given by the third-party when this code was created. * * @throws OmhException * A parameter is invalid. * * @see #AuthorizationCode(ThirdParty, Set, String) */ @JsonCreator public AuthorizationCode( @JsonProperty(JSON_KEY_THIRD_PARTY) final String thirdParty, @JsonProperty(JSON_KEY_CODE) final String code, @JsonProperty(JSON_KEY_CREATION_TIME) final long creationTime, @JsonProperty(JSON_KEY_EXPIRATION_TIME) final long expirationTime, @JsonProperty(JSON_KEY_SCOPES) final Set<String> scopes, @JsonProperty(JSON_KEY_STATE) final String state) throws OmhException { // Validate the third-party. if(thirdParty == null) { throw new OmhException("The third-party is null."); } else { this.thirdParty = thirdParty; } // Validate the code. if(code == null) { throw new OmhException("The code is null."); } else { this.code = code; } // 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; } // Validate the scopes. if(scopes == null) { throw new OmhException("The scopes set is null."); } else if(scopes.size() == 0) { throw new OmhException( "An authorization token cannot be created without any " + "scope."); } else { this.scopes.addAll(scopes); } // The state can be anything, so we don't validate it. this.state = state; } /** * Returns the unique identifier for the third-party entity. * * @return The unique identifier for the third-party entity. */ public String getThirdPartyId() { return thirdParty; } /** * Returns the third-party associated with this authorization code. * * @return The third-party associated with this authorization code. */ public ThirdParty getThirdParty() { return ThirdPartyBin.getInstance().getThirdParty(thirdParty); } /** * Returns the code. * * @return The code. */ public String getCode() { return code; } /** * Returns the time at which the code was created. * * @return The time, in milliseconds since the epoch, when this code was * created. */ public long getCreationTime() { return creationTime; } /** * Returns the time at which the code expires. * * @return The time, in milliseconds since the epoch, when this code * expires. */ public long getExpirationTime() { return expirationTime; } /** * Returns the set of scopes. * * @return The, unmodifiable, set of scopes. */ public Set<String> getScopes() { return Collections.unmodifiableSet(scopes); } /** * Returns the state given by the third-party when this request was made. * * @return The state that is being passed around while the authorization is * being verified. */ public String getState() { return state; } }