/** * Issue access token in exchange to an Authorization Grant. * * @param tokenReqDTO <Code>OAuth2AccessTokenReqDTO</Code> representing the Access Token request * @return <Code>OAuth2AccessTokenRespDTO</Code> representing the Access Token response */ public OAuth2AccessTokenRespDTO issueAccessToken(OAuth2AccessTokenReqDTO tokenReqDTO) { if (log.isDebugEnabled()) { log.debug( "Access Token request received for Client ID " + tokenReqDTO.getClientId() + ", User ID " + tokenReqDTO.getResourceOwnerUsername() + ", Scope : " + Arrays.toString(tokenReqDTO.getScope()) + " and Grant Type : " + tokenReqDTO.getGrantType()); } try { AccessTokenIssuer tokenIssuer = AccessTokenIssuer.getInstance(); return tokenIssuer.issue(tokenReqDTO); } catch (InvalidOAuthClientException e) { if (log.isDebugEnabled()) { log.debug( "Error occurred while issuing access token for Client ID : " + tokenReqDTO.getClientId() + ", User ID: " + tokenReqDTO.getResourceOwnerUsername() + ", Scope : " + Arrays.toString(tokenReqDTO.getScope()) + " and Grant Type : " + tokenReqDTO.getGrantType(), e); } OAuth2AccessTokenRespDTO tokenRespDTO = new OAuth2AccessTokenRespDTO(); tokenRespDTO.setError(true); tokenRespDTO.setErrorCode(OAuth2ErrorCodes.INVALID_CLIENT); tokenRespDTO.setErrorMsg("Invalid Client"); return tokenRespDTO; } catch (Exception e) { // in case of an error, consider it as a system error log.error( "Error occurred while issuing the access token for Client ID : " + tokenReqDTO.getClientId() + ", User ID " + tokenReqDTO.getResourceOwnerUsername() + ", Scope : " + Arrays.toString(tokenReqDTO.getScope()) + " and Grant Type : " + tokenReqDTO.getGrantType(), e); OAuth2AccessTokenRespDTO tokenRespDTO = new OAuth2AccessTokenRespDTO(); tokenRespDTO.setError(true); if (e.getCause().getCause() instanceof SQLIntegrityConstraintViolationException) { tokenRespDTO.setErrorCode("sql_error"); } else { tokenRespDTO.setErrorCode(OAuth2ErrorCodes.SERVER_ERROR); } tokenRespDTO.setErrorMsg("Server Error"); return tokenRespDTO; } }
private void setResponseHeaders( OAuthTokenReqMessageContext tokReqMsgCtx, OAuth2AccessTokenRespDTO tokenRespDTO) { if (tokReqMsgCtx.getProperty("RESPONSE_HEADERS") != null) { tokenRespDTO.setResponseHeaders( (ResponseHeader[]) tokReqMsgCtx.getProperty("RESPONSE_HEADERS")); } }
private void addUserAttributesToCache( OAuth2AccessTokenReqDTO tokenReqDTO, OAuth2AccessTokenRespDTO tokenRespDTO) { AuthorizationGrantCacheKey oldCacheKey = new AuthorizationGrantCacheKey(tokenReqDTO.getAuthorizationCode()); // checking getUserAttributesId vale of cacheKey before retrieve entry from cache as it causes // to NPE if (oldCacheKey.getUserAttributesId() != null) { AuthorizationGrantCacheEntry authorizationGrantCacheEntry = AuthorizationGrantCache.getInstance().getValueFromCacheByCode(oldCacheKey); AuthorizationGrantCacheKey newCacheKey = new AuthorizationGrantCacheKey(tokenRespDTO.getAccessToken()); if (AuthorizationGrantCache.getInstance().getValueFromCacheByToken(newCacheKey) == null) { if (log.isDebugEnabled()) { log.debug( "No AuthorizationGrantCache entry found for the access token:" + newCacheKey.getUserAttributesId() + ", hence adding to cache"); } AuthorizationGrantCache.getInstance() .addToCacheByToken(newCacheKey, authorizationGrantCacheEntry); AuthorizationGrantCache.getInstance().clearCacheEntryByCode(oldCacheKey); } else { // if the user attributes are already saved for access token, no need to add again. } } }
private OAuth2AccessTokenRespDTO handleError( String errorCode, String errorMsg, OAuth2AccessTokenReqDTO tokenReqDTO) { if (log.isDebugEnabled()) { log.debug( "OAuth-Error-Code=" + errorCode + " client-id=" + tokenReqDTO.getClientId() + " grant-type=" + tokenReqDTO.getGrantType() + " scope=" + OAuth2Util.buildScopeString(tokenReqDTO.getScope())); } OAuth2AccessTokenRespDTO tokenRespDTO; tokenRespDTO = new OAuth2AccessTokenRespDTO(); tokenRespDTO.setError(true); tokenRespDTO.setErrorCode(errorCode); tokenRespDTO.setErrorMsg(errorMsg); return tokenRespDTO; }
@POST @Path("/") @Consumes("application/x-www-form-urlencoded") @Produces("application/json") public Response issueAccessToken( @Context HttpServletRequest request, MultivaluedMap<String, String> paramMap) throws OAuthSystemException { try { PrivilegedCarbonContext.startTenantFlow(); PrivilegedCarbonContext carbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext(); carbonContext.setTenantId(MultitenantConstants.SUPER_TENANT_ID); carbonContext.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); HttpServletRequestWrapper httpRequest = new OAuthRequestWrapper(request, paramMap); if (log.isDebugEnabled()) { logAccessTokenRequest(httpRequest); } // extract the basic auth credentials if present in the request and use for // authentication. if (request.getHeader(OAuthConstants.HTTP_REQ_HEADER_AUTHZ) != null) { try { String[] clientCredentials = EndpointUtil.extractCredentialsFromAuthzHeader( request.getHeader(OAuthConstants.HTTP_REQ_HEADER_AUTHZ)); // The client MUST NOT use more than one authentication method in each request if (paramMap.containsKey(OAuth.OAUTH_CLIENT_ID) && paramMap.containsKey(OAuth.OAUTH_CLIENT_SECRET)) { return handleBasicAuthFailure(); } // If a client sends an invalid base64 encoded clientid:clientsecret value, it results in // this // array to only contain 1 element. This happens on specific errors though. if (clientCredentials.length != 2) { return handleBasicAuthFailure(); } // add the credentials available in Authorization header to the parameter map paramMap.add(OAuth.OAUTH_CLIENT_ID, clientCredentials[0]); paramMap.add(OAuth.OAUTH_CLIENT_SECRET, clientCredentials[1]); } catch (OAuthClientException e) { // malformed credential string is considered as an auth failure. log.error("Error while extracting credentials from authorization header", e); return handleBasicAuthFailure(); } } try { CarbonOAuthTokenRequest oauthRequest = new CarbonOAuthTokenRequest(httpRequest); // exchange the access token for the authorization grant. OAuth2AccessTokenRespDTO oauth2AccessTokenResp = getAccessToken(oauthRequest); // if there BE has returned an error if (oauth2AccessTokenResp.getErrorMsg() != null) { // if there is an auth failure, HTTP 401 Status Code should be sent back to the client. if (OAuth2ErrorCodes.INVALID_CLIENT.equals(oauth2AccessTokenResp.getErrorCode())) { return handleBasicAuthFailure(); } else if ("sql_error".equals(oauth2AccessTokenResp.getErrorCode())) { return handleSQLError(); } else if (OAuth2ErrorCodes.SERVER_ERROR.equals(oauth2AccessTokenResp.getErrorCode())) { return handleServerError(); } else { // Otherwise send back HTTP 400 Status Code OAuthResponse.OAuthErrorResponseBuilder oAuthErrorResponseBuilder = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST) .setError(oauth2AccessTokenResp.getErrorCode()) .setErrorDescription(oauth2AccessTokenResp.getErrorMsg()); OAuthResponse response = oAuthErrorResponseBuilder.buildJSONMessage(); ResponseHeader[] headers = oauth2AccessTokenResp.getResponseHeaders(); ResponseBuilder respBuilder = Response.status(response.getResponseStatus()); if (headers != null && headers.length > 0) { for (int i = 0; i < headers.length; i++) { if (headers[i] != null) { respBuilder.header(headers[i].getKey(), headers[i].getValue()); } } } return respBuilder.entity(response.getBody()).build(); } } else { OAuthTokenResponseBuilder oAuthRespBuilder = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK) .setAccessToken(oauth2AccessTokenResp.getAccessToken()) .setRefreshToken(oauth2AccessTokenResp.getRefreshToken()) .setExpiresIn(Long.toString(oauth2AccessTokenResp.getExpiresIn())) .setTokenType(BEARER); oAuthRespBuilder.setScope(oauth2AccessTokenResp.getAuthorizedScopes()); // OpenID Connect ID token if (oauth2AccessTokenResp.getIDToken() != null) { oAuthRespBuilder.setParam(OAuthConstants.ID_TOKEN, oauth2AccessTokenResp.getIDToken()); } OAuthResponse response = oAuthRespBuilder.buildJSONMessage(); ResponseHeader[] headers = oauth2AccessTokenResp.getResponseHeaders(); ResponseBuilder respBuilder = Response.status(response.getResponseStatus()) .header( OAuthConstants.HTTP_RESP_HEADER_CACHE_CONTROL, OAuthConstants.HTTP_RESP_HEADER_VAL_CACHE_CONTROL_NO_STORE) .header( OAuthConstants.HTTP_RESP_HEADER_PRAGMA, OAuthConstants.HTTP_RESP_HEADER_VAL_PRAGMA_NO_CACHE); if (headers != null && headers.length > 0) { for (int i = 0; i < headers.length; i++) { if (headers[i] != null) { respBuilder.header(headers[i].getKey(), headers[i].getValue()); } } } return respBuilder.entity(response.getBody()).build(); } } catch (OAuthProblemException e) { log.error("Error while creating the Carbon OAuth token request", e); OAuthResponse res = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST) .error(e) .buildJSONMessage(); return Response.status(res.getResponseStatus()).entity(res.getBody()).build(); } } finally { PrivilegedCarbonContext.endTenantFlow(); } }
public OAuth2AccessTokenRespDTO issue(OAuth2AccessTokenReqDTO tokenReqDTO) throws IdentityException, InvalidOAuthClientException { String grantType = tokenReqDTO.getGrantType(); OAuth2AccessTokenRespDTO tokenRespDTO; AuthorizationGrantHandler authzGrantHandler = authzGrantHandlers.get(grantType); OAuthTokenReqMessageContext tokReqMsgCtx = new OAuthTokenReqMessageContext(tokenReqDTO); // If multiple client authentication methods have been used the authorization server must reject // the request int authenticatorHandlerIndex = -1; for (int i = 0; i < clientAuthenticationHandlers.size(); i++) { if (clientAuthenticationHandlers.get(i).canAuthenticate(tokReqMsgCtx)) { if (authenticatorHandlerIndex > -1) { log.debug( "Multiple Client Authentication Methods used for client id : " + tokenReqDTO.getClientId()); tokenRespDTO = handleError( OAuthConstants.OAuthError.TokenResponse.UNSUPPORTED_CLIENT_AUTHENTICATION_METHOD, "Unsupported Client Authentication Method!", tokenReqDTO); setResponseHeaders(tokReqMsgCtx, tokenRespDTO); return tokenRespDTO; } authenticatorHandlerIndex = i; } } if (authenticatorHandlerIndex < 0 && authzGrantHandler.isConfidentialClient()) { log.debug( "Confidential client cannot be authenticated for client id : " + tokenReqDTO.getClientId()); tokenRespDTO = handleError( OAuthConstants.OAuthError.TokenResponse.UNSUPPORTED_CLIENT_AUTHENTICATION_METHOD, "Unsupported Client Authentication Method!", tokenReqDTO); setResponseHeaders(tokReqMsgCtx, tokenRespDTO); return tokenRespDTO; } ClientAuthenticationHandler clientAuthHandler = null; if (authenticatorHandlerIndex > -1) { clientAuthHandler = clientAuthenticationHandlers.get(authenticatorHandlerIndex); } boolean isAuthenticated; if (clientAuthHandler != null) { isAuthenticated = clientAuthHandler.authenticateClient(tokReqMsgCtx); } else { isAuthenticated = true; } if (!isAuthenticated) { if (log.isDebugEnabled()) { log.debug("Client Authentication failed for client Id: " + tokenReqDTO.getClientId()); } tokenRespDTO = handleError( OAuthError.TokenResponse.INVALID_CLIENT, "Client credentials are invalid.", tokenReqDTO); setResponseHeaders(tokReqMsgCtx, tokenRespDTO); return tokenRespDTO; } // loading the stored application data OAuthAppDO oAuthAppDO = getAppInformation(tokenReqDTO); if (!authzGrantHandler.isOfTypeApplicationUser()) { tokReqMsgCtx.setAuthorizedUser(OAuth2Util.getUserFromUserName(oAuthAppDO.getUserName())); tokReqMsgCtx .getAuthorizedUser() .setTenantDomain(IdentityTenantUtil.getTenantDomain(oAuthAppDO.getTenantId())); } boolean isValidGrant = false; String error = "Provided Authorization Grant is invalid"; try { isValidGrant = authzGrantHandler.validateGrant(tokReqMsgCtx); } catch (IdentityOAuth2Exception e) { if (log.isDebugEnabled()) { log.debug("Error occurred while validating grant", e); } error = e.getMessage(); } if (!isValidGrant) { if (log.isDebugEnabled()) { log.debug("Invalid Grant provided by the client Id: " + tokenReqDTO.getClientId()); } tokenRespDTO = handleError(OAuthError.TokenResponse.INVALID_GRANT, error, tokenReqDTO); setResponseHeaders(tokReqMsgCtx, tokenRespDTO); return tokenRespDTO; } boolean isAuthorized = authzGrantHandler.authorizeAccessDelegation(tokReqMsgCtx); if (!isAuthorized) { if (log.isDebugEnabled()) { log.debug("Invalid authorization for client Id = " + tokenReqDTO.getClientId()); } tokenRespDTO = handleError( OAuthError.TokenResponse.UNAUTHORIZED_CLIENT, "Unauthorized Client!", tokenReqDTO); setResponseHeaders(tokReqMsgCtx, tokenRespDTO); return tokenRespDTO; } boolean isValidScope = authzGrantHandler.validateScope(tokReqMsgCtx); if (!isValidScope) { if (log.isDebugEnabled()) { log.debug("Invalid scope provided by client Id: " + tokenReqDTO.getClientId()); } tokenRespDTO = handleError(OAuthError.TokenResponse.INVALID_SCOPE, "Invalid Scope!", tokenReqDTO); setResponseHeaders(tokReqMsgCtx, tokenRespDTO); return tokenRespDTO; } try { // set the token request context to be used by downstream handlers. This is introduced as a // fix for // IDENTITY-4111. OAuth2Util.setTokenRequestContext(tokReqMsgCtx); tokenRespDTO = authzGrantHandler.issue(tokReqMsgCtx); } finally { // clears the token request context. OAuth2Util.clearTokenRequestContext(); } tokenRespDTO.setCallbackURI(oAuthAppDO.getCallbackUrl()); String[] scopes = tokReqMsgCtx.getScope(); if (scopes != null && scopes.length > 0) { StringBuilder scopeString = new StringBuilder(""); for (String scope : scopes) { scopeString.append(scope); scopeString.append(" "); } tokenRespDTO.setAuthorizedScopes(scopeString.toString().trim()); } setResponseHeaders(tokReqMsgCtx, tokenRespDTO); // Do not change this log format as these logs use by external applications if (log.isDebugEnabled()) { log.debug( "Access token issued to client Id: " + tokenReqDTO.getClientId() + " username: "******" and scopes: " + tokenRespDTO.getAuthorizedScopes()); } if (tokReqMsgCtx.getScope() != null && OAuth2Util.isOIDCAuthzRequest(tokReqMsgCtx.getScope())) { IDTokenBuilder builder = OAuthServerConfiguration.getInstance().getOpenIDConnectIDTokenBuilder(); tokenRespDTO.setIDToken(builder.buildIDToken(tokReqMsgCtx, tokenRespDTO)); } if (tokenReqDTO.getGrantType().equals(GrantType.AUTHORIZATION_CODE.toString())) { addUserAttributesToCache(tokenReqDTO, tokenRespDTO); } return tokenRespDTO; }