com.nimbusds.oauth2.sdk.AuthorizationRequest Maven / Gradle / Ivy
package com.nimbusds.oauth2.sdk;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;
import net.jcip.annotations.Immutable;
import org.apache.commons.lang3.StringUtils;
import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.oauth2.sdk.id.State;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.util.URIUtils;
import com.nimbusds.oauth2.sdk.util.URLUtils;
/**
* Authorisation request. Used to authenticate an end-user and request the
* end-user's consent to grant the client access to a protected resource.
*
* Extending classes may define additional request parameters as well as
* enforce tighter requirements on the base parameters.
*
*
Example HTTP request:
*
*
* https://server.example.com/authorize?
* response_type=code
* &client_id=s6BhdRkqt3
* &state=xyz
* &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
*
*
* Related specifications:
*
*
* - OAuth 2.0 (RFC 6749), sections 4.1.1 and 4.2.1.
*
*/
@Immutable
public class AuthorizationRequest extends AbstractRequest {
/**
* The response type (required).
*/
private final ResponseType rt;
/**
* The client identifier (required).
*/
private final ClientID clientID;
/**
* The redirection URI where the response will be sent (optional).
*/
private final URI redirectURI;
/**
* The scope (optional).
*/
private final Scope scope;
/**
* The opaque value to maintain state between the request and the
* callback (recommended).
*/
private final State state;
/**
* Builder for constructing authorisation requests.
*/
public static class Builder {
/**
* The endpoint URI (optional).
*/
private URI uri;
/**
* The response type (required).
*/
private final ResponseType rt;
/**
* The client identifier (required).
*/
private final ClientID clientID;
/**
* The redirection URI where the response will be sent
* (optional).
*/
private URI redirectURI;
/**
* The scope (optional).
*/
private Scope scope;
/**
* The opaque value to maintain state between the request and
* the callback (recommended).
*/
private State state;
/**
* Creates a new authorisation request builder.
*
* @param rt The response type. Corresponds to the
* {@code response_type} parameter. Must not be
* {@code null}.
* @param clientID The client identifier. Corresponds to the
* {@code client_id} parameter. Must not be
* {@code null}.
*/
public Builder(final ResponseType rt, final ClientID clientID) {
if (rt == null)
throw new IllegalArgumentException("The response type must not be null");
this.rt = rt;
if (clientID == null)
throw new IllegalArgumentException("The client ID must not be null");
this.clientID = clientID;
}
/**
* Sets the redirection URI. Corresponds to the optional
* {@code redirection_uri} parameter.
*
* @param redirectURI The redirection URI, {@code null} if not
* specified.
*
* @return This builder.
*/
public Builder redirectionURI(final URI redirectURI) {
this.redirectURI = redirectURI;
return this;
}
/**
* Sets the scope. Corresponds to the optional {@code scope}
* parameter.
*
* @param scope The scope, {@code null} if not specified.
*
* @return This builder.
*/
public Builder scope(final Scope scope) {
this.scope = scope;
return this;
}
/**
* Sets the state. Corresponds to the recommended {@code state}
* parameter.
*
* @param state The state, {@code null} if not specified.
*
* @return This builder.
*/
public Builder state(final State state) {
this.state = state;
return this;
}
/**
* Sets the URI of the endpoint (HTTP or HTTPS) for which the
* request is intended.
*
* @param uri The endpoint URI, {@code null} if not specified.
*
* @return This builder.
*/
public Builder endpointURI(final URI uri) {
this.uri = uri;
return this;
}
/**
* Builds a new authorisation request.
*
* @return The authorisation request.
*/
public AuthorizationRequest build() {
return new AuthorizationRequest(uri, rt, clientID, redirectURI, scope, state);
}
}
/**
* Creates a new minimal authorisation request.
*
* @param uri The URI of the authorisation endpoint. May be
* {@code null} if the {@link #toHTTPRequest} method
* will not be used.
* @param rt The response type. Corresponds to the
* {@code response_type} parameter. Must not be
* {@code null}.
* @param clientID The client identifier. Corresponds to the
* {@code client_id} parameter. Must not be
* {@code null}.
*/
public AuthorizationRequest(final URI uri,
final ResponseType rt,
final ClientID clientID) {
this(uri, rt, clientID, null, null, null);
}
/**
* Creates a new authorisation request.
*
* @param uri The URI of the authorisation endpoint. May be
* {@code null} if the {@link #toHTTPRequest} method
* will not be used.
* @param rt The response type. Corresponds to the
* {@code response_type} parameter. Must not be
* {@code null}.
* @param clientID The client identifier. Corresponds to the
* {@code client_id} parameter. Must not be
* {@code null}.
* @param redirectURI The redirection URI. Corresponds to the optional
* {@code redirect_uri} parameter. {@code null} if
* not specified.
* @param scope The request scope. Corresponds to the optional
* {@code scope} parameter. {@code null} if not
* specified.
* @param state The state. Corresponds to the recommended
* {@code state} parameter. {@code null} if not
* specified.
*/
public AuthorizationRequest(final URI uri,
final ResponseType rt,
final ClientID clientID,
final URI redirectURI,
final Scope scope,
final State state) {
super(uri);
if (rt == null)
throw new IllegalArgumentException("The response type must not be null");
this.rt = rt;
if (clientID == null)
throw new IllegalArgumentException("The client ID must not be null");
this.clientID = clientID;
this.redirectURI = redirectURI;
this.scope = scope;
this.state = state;
}
/**
* Gets the response type. Corresponds to the {@code response_type}
* parameter.
*
* @return The response type.
*/
public ResponseType getResponseType() {
return rt;
}
/**
* Gets the client identifier. Corresponds to the {@code client_id}
* parameter.
*
* @return The client identifier.
*/
public ClientID getClientID() {
return clientID;
}
/**
* Gets the redirection URI. Corresponds to the optional
* {@code redirection_uri} parameter.
*
* @return The redirection URI, {@code null} if not specified.
*/
public URI getRedirectionURI() {
return redirectURI;
}
/**
* Gets the scope. Corresponds to the optional {@code scope} parameter.
*
* @return The scope, {@code null} if not specified.
*/
public Scope getScope() {
return scope;
}
/**
* Gets the state. Corresponds to the recommended {@code state}
* parameter.
*
* @return The state, {@code null} if not specified.
*/
public State getState() {
return state;
}
/**
* Returns the parameters for this authorisation request.
*
* Example parameters:
*
*
* response_type = code
* client_id = s6BhdRkqt3
* state = xyz
* redirect_uri = https://client.example.com/cb
*
*
* @return The parameters.
*
* @throws SerializeException If this authorisation request couldn't be
* serialised to an parameters map.
*/
public Map toParameters()
throws SerializeException {
Map params = new LinkedHashMap<>();
params.put("response_type", rt.toString());
params.put("client_id", clientID.getValue());
if (redirectURI != null)
params.put("redirect_uri", redirectURI.toString());
if (scope != null)
params.put("scope", scope.toString());
if (state != null)
params.put("state", state.getValue());
return params;
}
/**
* Returns the URI query string for this authorisation request.
*
* Note that the '?' character preceding the query string in an URI
* is not included in the returned string.
*
*
Example URI query string:
*
*
* response_type=code
* &client_id=s6BhdRkqt3
* &state=xyz
* &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
*
*
* @return The URI query string.
*
* @throws SerializeException If this authorisation request couldn't be
* serialised to an URI query string.
*/
public String toQueryString()
throws SerializeException {
return URLUtils.serializeParameters(toParameters());
}
/**
* Returns the complete URI representation for this authorisation
* request, consisting of the {@link #getEndpointURI authorization
* endpoint URI} with the {@link #toQueryString query string} appended.
*
* Example URI:
*
*
* https://server.example.com/authorize?
* response_type=code
* &client_id=s6BhdRkqt3
* &state=xyz
* &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
*
*
* @return The URI representation.
*
* @throws SerializeException If this authorisation request couldn't be
* serialised to a URI.
*/
public URI toURI()
throws SerializeException {
if (getEndpointURI() == null)
throw new SerializeException("The authorization endpoint URI is not specified");
StringBuilder sb = new StringBuilder(getEndpointURI().toString());
sb.append('?');
sb.append(toQueryString());
try {
return new URI(sb.toString());
} catch (URISyntaxException e) {
throw new SerializeException("Couldn't append query string: " + e.getMessage(), e);
}
}
/**
* Returns the matching HTTP request.
*
* @param method The HTTP request method which can be GET or POST. Must
* not be {@code null}.
*
* @return The HTTP request.
*
* @throws SerializeException If the authorisation request message
* couldn't be serialised to an HTTP
* request.
*/
public HTTPRequest toHTTPRequest(final HTTPRequest.Method method)
throws SerializeException {
if (getEndpointURI() == null)
throw new SerializeException("The endpoint URI is not specified");
HTTPRequest httpRequest;
URL endpointURL;
try {
endpointURL = getEndpointURI().toURL();
} catch (MalformedURLException e) {
throw new SerializeException(e.getMessage(), e);
}
if (method.equals(HTTPRequest.Method.GET)) {
httpRequest = new HTTPRequest(HTTPRequest.Method.GET, endpointURL);
} else if (method.equals(HTTPRequest.Method.POST)) {
httpRequest = new HTTPRequest(HTTPRequest.Method.POST, endpointURL);
} else {
throw new IllegalArgumentException("The HTTP request method must be GET or POST");
}
httpRequest.setQuery(toQueryString());
return httpRequest;
}
@Override
public HTTPRequest toHTTPRequest()
throws SerializeException {
return toHTTPRequest(HTTPRequest.Method.GET);
}
/**
* Parses an authorisation request from the specified parameters.
*
* Example parameters:
*
*
* response_type = code
* client_id = s6BhdRkqt3
* state = xyz
* redirect_uri = https://client.example.com/cb
*
*
* @param params The parameters. Must not be {@code null}.
*
* @return The authorisation request.
*
* @throws ParseException If the parameters couldn't be parsed to an
* authorisation request.
*/
public static AuthorizationRequest parse(final Map params)
throws ParseException {
return parse(null, params);
}
/**
* Parses an authorisation request from the specified parameters.
*
* Example parameters:
*
*
* response_type = code
* client_id = s6BhdRkqt3
* state = xyz
* redirect_uri = https://client.example.com/cb
*
*
* @param uri The URI of the authorisation endpoint. May be
* {@code null} if the {@link #toHTTPRequest()} method
* will not be used.
* @param params The parameters. Must not be {@code null}.
*
* @return The authorisation request.
*
* @throws ParseException If the parameters couldn't be parsed to an
* authorisation request.
*/
public static AuthorizationRequest parse(final URI uri, final Map params)
throws ParseException {
// Parse mandatory client ID first
String v = params.get("client_id");
if (StringUtils.isBlank(v))
throw new ParseException("Missing \"client_id\" parameter",
OAuth2Error.INVALID_REQUEST);
ClientID clientID = new ClientID(v);
// Parse optional redirection URI second
v = params.get("redirect_uri");
URI redirectURI = null;
if (StringUtils.isNotBlank(v)) {
try {
redirectURI = new URI(v);
} catch (URISyntaxException e) {
throw new ParseException("Invalid \"redirect_uri\" parameter: " + e.getMessage(),
OAuth2Error.INVALID_REQUEST, clientID, null, null, e);
}
}
// Parse optional state third
State state = State.parse(params.get("state"));
// Parse mandatory response type
v = params.get("response_type");
ResponseType rt;
try {
rt = ResponseType.parse(v);
} catch (ParseException e) {
throw new ParseException(e.getMessage(),
OAuth2Error.UNSUPPORTED_RESPONSE_TYPE,
clientID, redirectURI, state, e);
}
// Parse optional scope
v = params.get("scope");
Scope scope = null;
if (StringUtils.isNotBlank(v))
scope = Scope.parse(v);
return new AuthorizationRequest(uri, rt, clientID, redirectURI, scope, state);
}
/**
* Parses an authorisation request from the specified URI query string.
*
* Example URI query string:
*
*
* response_type=code
* &client_id=s6BhdRkqt3
* &state=xyz
* &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
*
*
* @param query The URI query string. Must not be {@code null}.
*
* @return The authorisation request.
*
* @throws ParseException If the query string couldn't be parsed to an
* authorisation request.
*/
public static AuthorizationRequest parse(final String query)
throws ParseException {
return parse(null, URLUtils.parseParameters(query));
}
/**
* Parses an authorisation request from the specified URI query string.
*
* Example URI query string:
*
*
* response_type=code
* &client_id=s6BhdRkqt3
* &state=xyz
* &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
*
*
* @param uri The URI of the authorisation endpoint. May be
* {@code null} if the {@link #toHTTPRequest()} method
* will not be used.
* @param query The URI query string. Must not be {@code null}.
*
* @return The authorisation request.
*
* @throws ParseException If the query string couldn't be parsed to an
* authorisation request.
*/
public static AuthorizationRequest parse(final URI uri, final String query)
throws ParseException {
return parse(uri, URLUtils.parseParameters(query));
}
/**
* Parses an authorisation request from the specified URI.
*
* Example URI:
*
*
* https://server.example.com/authorize?
* response_type=code
* &client_id=s6BhdRkqt3
* &state=xyz
* &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
*
*
* @param uri The URI. Must not be {@code null}.
*
* @return The authorisation request.
*
* @throws ParseException If the URI couldn't be parsed to an
* authorisation request.
*/
public static AuthorizationRequest parse(final URI uri)
throws ParseException {
return parse(URIUtils.getBaseURI(uri), URLUtils.parseParameters(uri.getQuery()));
}
/**
* Parses an authorisation request from the specified HTTP request.
*
* Example HTTP request (GET):
*
*
* https://server.example.com/authorize?
* response_type=code
* &client_id=s6BhdRkqt3
* &state=xyz
* &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
*
*
* @param httpRequest The HTTP request. Must not be {@code null}.
*
* @return The authorisation request.
*
* @throws ParseException If the HTTP request couldn't be parsed to an
* authorisation request.
*/
public static AuthorizationRequest parse(final HTTPRequest httpRequest)
throws ParseException {
String query = httpRequest.getQuery();
if (query == null)
throw new ParseException("Missing URI query string");
try {
return parse(URIUtils.getBaseURI(httpRequest.getURL().toURI()), query);
} catch (URISyntaxException e) {
throw new ParseException(e.getMessage(), e);
}
}
}