/*
* oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2014, Gluu
*/
package org.xdi.oxauth.client;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.xdi.oxauth.model.common.AuthenticationMethod;
import org.xdi.oxauth.model.common.GrantType;
import org.xdi.oxauth.model.token.ClientAssertionType;
import javax.ws.rs.HttpMethod;
/**
* Encapsulates functionality to make token request calls to an authorization
* server via REST Services.
*
* @author Javier Rojas Blum Date: 10.19.2011
*/
public class TokenClient extends BaseClient<TokenRequest, TokenResponse> {
private static final Logger LOG = Logger.getLogger(TokenClient.class);
/**
* Constructs a token client by providing a REST url where the token service
* is located.
*
* @param url The REST Service location.
*/
public TokenClient(String url) {
super(url);
}
@Override
public String getHttpMethod() {
return HttpMethod.POST;
}
/**
* <p>
* Executes the call to the REST Service requesting the authorization and
* processes the response.
* </p>
* <p>
* The authorization code is obtained by using an authorization server as an
* intermediary between the client and resource owner. Instead of requesting
* authorization directly from the resource owner, the client directs the
* resource owner to an authorization server (via its user- agent as defined in
* [RFC2616]), which in turn directs the resource owner back to the client with
* the authorization code.
* </p>
* <p>
* Before directing the resource owner back to the client with the authorization
* code, the authorization server authenticates the resource owner and obtains
* authorization. Because the resource owner only authenticates with the
* authorization server, the resource owner's credentials are never shared with
* the client.
* </p>
* <p>
* The authorization code provides a few important security benefits such as the
* ability to authenticate the client, and the transmission of the access token
* directly to the client without passing it through the resource owner's
* user-agent, potentially exposing it to others, including the resource owner.
* </p>
*
* @param code he authorization code received from the authorization server.
* This parameter is required.
* @param redirectUri The redirection URI. This parameter is required.
* @param clientId The client identifier.
* @param clientSecret The client secret.
* @return The token response.
*/
public TokenResponse execAuthorizationCode(String code, String redirectUri,
String clientId, String clientSecret) {
setRequest(new TokenRequest(GrantType.AUTHORIZATION_CODE));
getRequest().setCode(code);
getRequest().setRedirectUri(redirectUri);
getRequest().setAuthUsername(clientId);
getRequest().setAuthPassword(clientSecret);
return exec();
}
/**
* <p>
* Executes the call to the REST Service requesting the authorization and
* processes the response.
* </p>
* <p>
* The resource owner password credentials grant type is suitable in cases
* where the resource owner has a trust relationship with the client, such
* as its device operating system or a highly privileged application. The
* authorization server should take special care when enabling this grant
* type, and only allow it when other flows are not viable.
* </p>
* <p>
* The grant type is suitable for clients capable of obtaining the resource
* owner's credentials (username and password, typically using an
* interactive form). It is also used to migrate existing clients using
* direct authentication schemes such as HTTP Basic or Digest authentication
* to OAuth by converting the stored credentials to an access token.
* </p>
*
* @param username The resource owner username. This parameter is required.
* @param password The resource owner password. This parameter is required.
* @param scope The scope of the access request. This parameter is optional.
* @param clientId The client identifier.
* @param clientSecret The client secret.
* @return The token response.
*/
public TokenResponse execResourceOwnerPasswordCredentialsGrant(
String username, String password, String scope,
String clientId, String clientSecret) {
setRequest(new TokenRequest(GrantType.RESOURCE_OWNER_PASSWORD_CREDENTIALS));
getRequest().setUsername(username);
getRequest().setPassword(password);
getRequest().setScope(scope);
getRequest().setAuthUsername(clientId);
getRequest().setAuthPassword(clientSecret);
return exec();
}
/**
* <p>
* Executes the call to the REST Service requesting the authorization and
* processes the response.
* </p>
* <p>
* The client can request an access token using only its client credentials
* when the client is requesting access to the protected resources under its
* control, or those of another resource owner which has been previously
* arranged with the authorization server. The client credentials grant type
* must only be used by confidential clients.
* </p>
*
* @param scope The scope of the access request. This parameter is optional.
* @param clientId The client identifier.
* @param clientSecret The client secret.
* @return The token response.
*/
public TokenResponse execClientCredentialsGrant(
String scope, String clientId, String clientSecret) {
setRequest(new TokenRequest(GrantType.CLIENT_CREDENTIALS));
getRequest().setScope(scope);
getRequest().setAuthUsername(clientId);
getRequest().setAuthPassword(clientSecret);
return exec();
}
/**
* <p>
* Executes the call to the REST Service requesting the authorization and
* processes the response.
* </p>
* <p>
* The client uses an extension grant type by specifying the grant type
* using an absolute URI (defined by the authorization server) as the value
* of the grant_type parameter of the token endpoint, and by adding any
* additional parameters necessary.
* </p>
*
* @param grantTypeUri Absolute URI.
* @param assertion Assertion grant type.
* @param clientId The client identifier.
* @param clientSecret The client secret.
* @return The token response.
*/
public TokenResponse execExtensionGrant(String grantTypeUri, String assertion,
String clientId, String clientSecret) {
GrantType grantType = GrantType.fromString(grantTypeUri);
setRequest(new TokenRequest(grantType));
getRequest().setAssertion(assertion);
getRequest().setAuthUsername(clientId);
getRequest().setAuthPassword(clientSecret);
return exec();
}
/**
* <p>
* Executes the call to the REST Service requesting the authorization and
* processes the response.
* </p>
* <p>
* If the authorization server issued a refresh token to the client, the
* client can make a request to the token endpoint for a new access token.
* </p>
*
* @param scope The scope of the access request. This value is optional.
* @param refreshToken The refresh token issued to the client. This value is
* required.
* @param clientId The client identifier.
* @param clientSecret The client secret.
* @return The token response.
*/
public TokenResponse execRefreshToken(String scope, String refreshToken,
String clientId, String clientSecret) {
setRequest(new TokenRequest(GrantType.REFRESH_TOKEN));
getRequest().setScope(scope);
getRequest().setRefreshToken(refreshToken);
getRequest().setAuthUsername(clientId);
getRequest().setAuthPassword(clientSecret);
return exec();
}
/**
* Executes the call to the REST Service and processes the response.
*
* @return The token response.
*/
public TokenResponse exec() {
// Prepare request parameters
initClientRequest();
if (request.getAuthenticationMethod() == AuthenticationMethod.CLIENT_SECRET_BASIC
&& request.hasCredentials()) {
clientRequest.header("Authorization", "Basic " + request.getEncodedCredentials());
}
clientRequest.header("Content-Type", request.getContentType());
clientRequest.setHttpMethod(getHttpMethod());
if (getRequest().getGrantType() != null) {
clientRequest.formParameter("grant_type", getRequest().getGrantType());
}
if (StringUtils.isNotBlank(getRequest().getCode())) {
clientRequest.formParameter("code", getRequest().getCode());
}
if (StringUtils.isNotBlank(getRequest().getCodeVerifier())) {
clientRequest.formParameter("code_verifier", getRequest().getCodeVerifier());
}
if (StringUtils.isNotBlank(getRequest().getRedirectUri())) {
clientRequest.formParameter("redirect_uri", getRequest().getRedirectUri());
}
if (StringUtils.isNotBlank(getRequest().getUsername())) {
clientRequest.formParameter("username", getRequest().getUsername());
}
if (StringUtils.isNotBlank(getRequest().getPassword())) {
clientRequest.formParameter("password", getRequest().getPassword());
}
if (StringUtils.isNotBlank(getRequest().getScope())) {
clientRequest.formParameter("scope", getRequest().getScope());
}
if (StringUtils.isNotBlank(getRequest().getAssertion())) {
clientRequest.formParameter("assertion", getRequest().getAssertion());
}
if (StringUtils.isNotBlank(getRequest().getRefreshToken())) {
clientRequest.formParameter("refresh_token", getRequest().getRefreshToken());
}
if (StringUtils.isNotBlank(getRequest().getOxAuthExchangeToken())) {
clientRequest.formParameter("oxauth_exchange_token", getRequest().getOxAuthExchangeToken());
}
if (getRequest().getAuthenticationMethod() == AuthenticationMethod.CLIENT_SECRET_POST) {
if (getRequest().getAuthUsername() != null && !getRequest().getAuthUsername().isEmpty()) {
clientRequest.formParameter("client_id", getRequest().getAuthUsername());
}
if (getRequest().getAuthPassword() != null && !getRequest().getAuthPassword().isEmpty()) {
clientRequest.formParameter("client_secret", getRequest().getAuthPassword());
}
} else if (getRequest().getAuthenticationMethod() == AuthenticationMethod.CLIENT_SECRET_JWT ||
getRequest().getAuthenticationMethod() == AuthenticationMethod.PRIVATE_KEY_JWT) {
clientRequest.formParameter("client_assertion_type", ClientAssertionType.JWT_BEARER);
clientRequest.formParameter("client_assertion", getRequest().getClientAssertion());
if (getRequest().getAuthUsername() != null && !getRequest().getAuthUsername().isEmpty()) {
clientRequest.formParameter("client_id", getRequest().getAuthUsername());
}
}
for (String key : getRequest().getCustomParameters().keySet()) {
clientRequest.formParameter(key, getRequest().getCustomParameters().get(key));
}
// Call REST Service and handle response
try {
clientResponse = clientRequest.post(String.class);
final TokenResponse tokenResponse = new TokenResponse(clientResponse);
tokenResponse.injectDataFromJson();
setResponse(tokenResponse);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
} finally {
closeConnection();
}
return getResponse();
}
}