/* * 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.log4j.Logger; import org.jboss.resteasy.client.ClientExecutor; import org.jboss.resteasy.client.ClientRequest; import org.xdi.oxauth.model.authorize.AuthorizeRequestParam; import org.xdi.oxauth.model.common.AuthorizationMethod; import org.xdi.oxauth.model.common.Display; import org.xdi.oxauth.model.common.Prompt; import org.xdi.oxauth.model.common.ResponseType; import javax.ws.rs.HttpMethod; import javax.ws.rs.core.MediaType; import java.util.ArrayList; import java.util.List; /** * Encapsulates functionality to make authorization request calls to an authorization server via REST Services. * * @author Javier Rojas Blum * @version December 26, 2016 */ public class AuthorizeClient extends BaseClient<AuthorizationRequest, AuthorizationResponse> { private static final Logger LOG = Logger.getLogger(AuthorizeClient.class); static String NO_REDIRECT_HEADER = "X-Gluu-NoRedirect"; /** * Constructs an authorize client by providing a REST url where the * authorize service is located. * * @param url The REST Service location. */ public AuthorizeClient(String url) { super(url); } @Override public String getHttpMethod() { if (request.getAuthorizationMethod() == null || request.getAuthorizationMethod() == AuthorizationMethod.AUTHORIZATION_REQUEST_HEADER_FIELD || request.getAuthorizationMethod() == AuthorizationMethod.FORM_ENCODED_BODY_PARAMETER) { return HttpMethod.POST; } else { // AuthorizationMethod.URL_QUERY_PARAMETER return HttpMethod.GET; } } /** * The authorization code grant type is used to obtain both access tokens * and refresh tokens and is optimized for confidential clients. As a * redirection-based flow, the client must be capable of interacting with * the resource owner's user-agent (typically a web browser) and capable of * receiving incoming requests (via redirection) from the authorization * server. * * @param clientId The client identifier. This parameter is required. * @param scopes The scope of the access request. This parameter is optional. * @param redirectUri The redirection URI. This parameter is optional. * @param nonce A string value used to associate a user agent session with an ID Token, * and to mitigate replay attacks. * forgery. This parameter is recommended. * @param state An opaque value used by the client to maintain state between * the request and callback. The authorization server includes * this value when redirecting the user-agent back to the client. * The parameter should be used for preventing cross-site request * forgery. * @param req A JWT encoded OpenID Request Object. * @param reqUri An URL that points to an OpenID Request Object. * @param display An ASCII string value that specifies how the Authorization Server displays the * authentication page to the End-User. * @param prompt A space delimited list of ASCII strings that can contain the values login, consent, * select_account, and none. * @return The authorization response. */ public AuthorizationResponse execAuthorizationCodeGrant( String clientId, List<String> scopes, String redirectUri, String nonce, String state, String req, String reqUri, Display display, List<Prompt> prompt) { List<ResponseType> responseTypes = new ArrayList<ResponseType>(); responseTypes.add(ResponseType.CODE); setRequest(new AuthorizationRequest(responseTypes, clientId, scopes, redirectUri, nonce)); getRequest().setRedirectUri(redirectUri); getRequest().setState(state); getRequest().setRequest(req); getRequest().setRedirectUri(reqUri); getRequest().setDisplay(display); getRequest().getPrompts().addAll(prompt); return exec(); } /** * <p> * The implicit grant type is used to obtain access tokens (it does not * support the issuance of refresh tokens) and is optimized for public * clients known to operate a particular redirection URI. These clients are * typically implemented in a browser using a scripting language such as * JavaScript. * </p> * <p> * As a redirection-based flow, the client must be capable of interacting * with the resource owner's user-agent (typically a web browser) and * capable of receiving incoming requests (via redirection) from the * authorization server. * </p> * <p> * Unlike the authorization code grant type in which the client makes * separate requests for authorization and access token, the client receives * the access token as the result of the authorization request. * </p> * <p> * The implicit grant type does not include client authentication, and * relies on the presence of the resource owner and the registration of the * redirection URI. Because the access token is encoded into the redirection * URI, it may be exposed to the resource owner and other applications * residing on its device. * </p> * * @param clientId The client identifier. This parameter is required. * @param scopes The scope of the access request. This parameter is optional. * @param redirectUri The redirection URI. This parameter is optional. * @param nonce A string value used to associate a user agent session with an ID Token, * and to mitigate replay attacks. * forgery. This parameter is recommended. * @param state An opaque value used by the client to maintain state between * the request and callback. The authorization server includes * this value when redirecting the user-agent back to the client. * The parameter should be used for preventing cross-site request * forgery. * @param req A JWT encoded OpenID Request Object. * @param reqUri An URL that points to an OpenID Request Object. * @param display An ASCII string value that specifies how the Authorization Server displays the * authentication page to the End-User. * @param prompt A space delimited list of ASCII strings that can contain the values login, consent, * select_account, and none. * @return The authorization response. */ @Deprecated // it produces confusion since we have parameters and request object at the same time public AuthorizationResponse execImplicitGrant( String clientId, List<String> scopes, String redirectUri, String nonce, String state, String req, String reqUri, Display display, List<Prompt> prompt) { List<ResponseType> responseTypes = new ArrayList<ResponseType>(); responseTypes.add(ResponseType.TOKEN); setRequest(new AuthorizationRequest(responseTypes, clientId, scopes, redirectUri, nonce)); getRequest().setRedirectUri(redirectUri); getRequest().setState(state); getRequest().setRequest(req); getRequest().setRedirectUri(reqUri); getRequest().setDisplay(display); getRequest().getPrompts().addAll(prompt); return exec(); } /** * Executes the call to the REST Service and processes the response. * * @return The authorization response. */ public AuthorizationResponse exec() { AuthorizationResponse response = null; try { initClientRequest(); response = exec_(); } catch (Exception e) { LOG.error(e.getMessage(), e); } finally { closeConnection(); } return response; } @Deprecated public AuthorizationResponse exec(ClientExecutor clientExecutor) { AuthorizationResponse response = null; try { clientRequest = new ClientRequest(getUrl(), clientExecutor); response = exec_(); } catch (Exception e) { LOG.error(e.getMessage(), e); } // Do not close the connection for this case. return response; } private AuthorizationResponse exec_() throws Exception { // Prepare request parameters clientRequest.header("Content-Type", MediaType.APPLICATION_FORM_URLENCODED); clientRequest.setHttpMethod(getHttpMethod()); if (getRequest().isUseNoRedirectHeader()) { clientRequest.header(NO_REDIRECT_HEADER, "true"); } final String responseTypesAsString = getRequest().getResponseTypesAsString(); final String scopesAsString = getRequest().getScopesAsString(); final String promptsAsString = getRequest().getPromptsAsString(); final String uiLocalesAsString = getRequest().getUiLocalesAsString(); final String claimLocalesAsString = getRequest().getClaimsLocalesAsString(); final String acrValuesAsString = getRequest().getAcrValuesAsString(); final String claimsAsString = getRequest().getClaimsAsString(); addReqParam(AuthorizeRequestParam.RESPONSE_TYPE, responseTypesAsString); addReqParam(AuthorizeRequestParam.CLIENT_ID, getRequest().getClientId()); addReqParam(AuthorizeRequestParam.SCOPE, scopesAsString); addReqParam(AuthorizeRequestParam.REDIRECT_URI, getRequest().getRedirectUri()); addReqParam(AuthorizeRequestParam.STATE, getRequest().getState()); addReqParam(AuthorizeRequestParam.NONCE, getRequest().getNonce()); addReqParam(AuthorizeRequestParam.DISPLAY, getRequest().getDisplay()); addReqParam(AuthorizeRequestParam.PROMPT, promptsAsString); if (getRequest().getMaxAge() != null) { addReqParam(AuthorizeRequestParam.MAX_AGE, getRequest().getMaxAge().toString()); } addReqParam(AuthorizeRequestParam.UI_LOCALES, uiLocalesAsString); addReqParam(AuthorizeRequestParam.CLAIMS_LOCALES, claimLocalesAsString); addReqParam(AuthorizeRequestParam.ID_TOKEN_HINT, getRequest().getIdTokenHint()); addReqParam(AuthorizeRequestParam.LOGIN_HINT, getRequest().getLoginHint()); addReqParam(AuthorizeRequestParam.ACR_VALUES, acrValuesAsString); addReqParam(AuthorizeRequestParam.CLAIMS, claimsAsString); addReqParam(AuthorizeRequestParam.REGISTRATION, getRequest().getRegistration()); addReqParam(AuthorizeRequestParam.REQUEST, getRequest().getRequest()); addReqParam(AuthorizeRequestParam.REQUEST_URI, getRequest().getRequestUri()); addReqParam(AuthorizeRequestParam.ACCESS_TOKEN, getRequest().getAccessToken()); addReqParam(AuthorizeRequestParam.CUSTOM_RESPONSE_HEADERS, getRequest().getCustomResponseHeadersAsString()); // PKCE addReqParam(AuthorizeRequestParam.CODE_CHALLENGE, getRequest().getCodeChallenge()); addReqParam(AuthorizeRequestParam.CODE_CHALLENGE_METHOD, getRequest().getCodeChallengeMethod()); if (getRequest().isRequestSessionState()) { addReqParam(AuthorizeRequestParam.REQUEST_SESSION_STATE, Boolean.toString(getRequest().isRequestSessionState())); } addReqParam(AuthorizeRequestParam.SESSION_STATE, getRequest().getSessionState()); // Custom params for (String key : request.getCustomParameters().keySet()) { addReqParam(key, request.getCustomParameters().get(key)); } if (request.getAuthorizationMethod() != AuthorizationMethod.FORM_ENCODED_BODY_PARAMETER && request.hasCredentials()) { clientRequest.header("Authorization", "Basic " + request.getEncodedCredentials()); } // Call REST Service and handle response if (request.getAuthorizationMethod() == AuthorizationMethod.FORM_ENCODED_BODY_PARAMETER) { clientResponse = clientRequest.post(String.class); } else { clientResponse = clientRequest.get(String.class); } setResponse(new AuthorizationResponse(clientResponse)); return getResponse(); } }