Java tutorial
/* * Copyright (c) 2013, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.identity.oauth.endpoint.revoke; import org.apache.axis2.transport.http.HTTPConstants; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.oltu.oauth2.as.response.OAuthASResponse; import org.apache.oltu.oauth2.common.OAuth; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.apache.oltu.oauth2.common.message.OAuthResponse; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.oauth.common.OAuth2ErrorCodes; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth.common.exception.OAuthClientException; import org.wso2.carbon.identity.oauth.endpoint.OAuthRequestWrapper; import org.wso2.carbon.identity.oauth.endpoint.util.EndpointUtil; import org.wso2.carbon.identity.oauth2.ResponseHeader; import org.wso2.carbon.identity.oauth2.dto.OAuthRevocationRequestDTO; import org.wso2.carbon.identity.oauth2.dto.OAuthRevocationResponseDTO; import org.wso2.carbon.ui.util.CharacterEncoder; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import java.util.Enumeration; @Path("/revoke") public class OAuthRevocationEndpoint { private static final Log log = LogFactory.getLog(OAuthRevocationEndpoint.class); @POST @Path("/") @Consumes("application/x-www-form-urlencoded") public Response revokeAccessToken(@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()) { logAccessTokenRevocationRequest(httpRequest); } String token = httpRequest.getParameter("token"); if (StringUtils.isBlank(token) && paramMap.get("token") != null && !paramMap.isEmpty()) { token = paramMap.get("token").get(0); } String tokenType = httpRequest.getParameter("token_type_hint"); if (StringUtils.isBlank(tokenType) && paramMap.get("token_type_hint") != null && !paramMap.get("token_type_hint").isEmpty()) { tokenType = paramMap.get("token_type_hint").get(0); } String callback = httpRequest.getParameter("callback"); if (StringUtils.isBlank(callback) && paramMap.get("callback") != null && !paramMap.get("callback").isEmpty()) { callback = paramMap.get("callback").get(0); } // 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(callback); } if (clientCredentials.length != 2) { handleBasicAuthFailure(callback); } // add the credentials available in Authorization 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(callback); } } try { OAuthRevocationRequestDTO revokeRequest = new OAuthRevocationRequestDTO(); if (paramMap.get(OAuth.OAUTH_CLIENT_ID) != null) { revokeRequest.setConsumerKey(paramMap.get(OAuth.OAUTH_CLIENT_ID).get(0)); } if (paramMap.get(OAuth.OAUTH_CLIENT_SECRET) != null) { revokeRequest.setConsumerSecret(paramMap.get(OAuth.OAUTH_CLIENT_SECRET).get(0)); } if (StringUtils.isNotEmpty(token)) { revokeRequest.setToken(token); } else { handleClientFailure(callback); } if (StringUtils.isNotEmpty(tokenType)) { revokeRequest.setToken_type(tokenType); } OAuthRevocationResponseDTO oauthRevokeResp = revokeTokens(revokeRequest); // if there BE has returned an error if (oauthRevokeResp.getErrorMsg() != null) { // if there is an auth failure, HTTP 401 Status Code should be sent back to the client. if (OAuth2ErrorCodes.INVALID_CLIENT.equals(oauthRevokeResp.getErrorCode())) { return handleBasicAuthFailure(callback); } else if (OAuth2ErrorCodes.UNAUTHORIZED_CLIENT.equals(oauthRevokeResp.getErrorCode())) { return handleAuthorizationFailure(callback); } // Otherwise send back HTTP 400 Status Code return handleClientFailure(callback, oauthRevokeResp); } else { OAuthResponse response; if (StringUtils.isNotEmpty(callback)) { response = CarbonOAuthASResponse.revokeResponse(HttpServletResponse.SC_OK) .buildBodyMessage(); response.setBody(callback + "();"); } else { response = CarbonOAuthASResponse.revokeResponse(HttpServletResponse.SC_OK) .buildBodyMessage(); } ResponseHeader[] headers = oauthRevokeResp.getResponseHeaders(); ResponseBuilder respBuilder = Response.status(response.getResponseStatus()) .header(OAuthConstants.HTTP_RESP_HEADER_CACHE_CONTROL, OAuthConstants.HTTP_RESP_HEADER_VAL_CACHE_CONTROL_NO_STORE) .header(HTTPConstants.HEADER_CONTENT_LENGTH, "0") .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()); } } } if (StringUtils.isNotEmpty(callback)) { respBuilder.header("Content-Type", "application/javascript"); } else { respBuilder.header("Content-Type", "text/html"); } return respBuilder.entity(response.getBody()).build(); } } catch (OAuthClientException e) { return handleServerFailure(callback, e); } } finally { PrivilegedCarbonContext.endTenantFlow(); } } private Response handleBasicAuthFailure(String callback) throws OAuthSystemException { if (callback == null || "".equals(callback)) { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED) .setError(OAuth2ErrorCodes.INVALID_CLIENT).setErrorDescription("Client Authentication failed.") .buildJSONMessage(); return Response.status(response.getResponseStatus()) .header(OAuthConstants.HTTP_RESP_HEADER_AUTHENTICATE, EndpointUtil.getRealmInfo()) .header("Content-Type", "text/html").entity(response.getBody()).build(); } else { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED) .setError(OAuth2ErrorCodes.INVALID_CLIENT).buildJSONMessage(); return Response.status(response.getResponseStatus()) .header(OAuthConstants.HTTP_RESP_HEADER_AUTHENTICATE, EndpointUtil.getRealmInfo()) .header("Content-Type", "application/javascript") .entity(callback + "(" + response.getBody() + ");").build(); } } private Response handleAuthorizationFailure(String callback) throws OAuthSystemException { if (callback == null || "".equals(callback)) { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED) .setError(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT) .setErrorDescription("Client Authentication failed.").buildJSONMessage(); return Response.status(response.getResponseStatus()) .header(OAuthConstants.HTTP_RESP_HEADER_AUTHENTICATE, EndpointUtil.getRealmInfo()) .header("Content-Type", "text/html").entity(response.getBody()).build(); } else { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED) .setError(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT).buildJSONMessage(); return Response.status(response.getResponseStatus()) .header(OAuthConstants.HTTP_RESP_HEADER_AUTHENTICATE, EndpointUtil.getRealmInfo()) .header("Content-Type", "application/javascript") .entity(callback + "(" + response.getBody() + ");").build(); } } private Response handleServerFailure(String callback, Exception e) throws OAuthSystemException { if (callback == null || "".equals(callback)) { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_INTERNAL_SERVER_ERROR) .setError(OAuth2ErrorCodes.SERVER_ERROR).setErrorDescription(e.getMessage()).buildJSONMessage(); return Response.status(response.getResponseStatus()).header("Content-Type", "text/html") .entity(response.getBody()).build(); } else { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_INTERNAL_SERVER_ERROR) .setError(OAuth2ErrorCodes.SERVER_ERROR).buildJSONMessage(); return Response.status(response.getResponseStatus()).header("Content-Type", "application/javascript") .entity(callback + "(" + response.getBody() + ");").build(); } } private Response handleClientFailure(String callback) throws OAuthSystemException { if (callback == null || "".equals(callback)) { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST) .setError(OAuth2ErrorCodes.INVALID_REQUEST).setErrorDescription("Invalid revocation request") .buildJSONMessage(); return Response.status(response.getResponseStatus()).header("Content-Type", "text/html") .entity(response.getBody()).build(); } else { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST) .setError(OAuth2ErrorCodes.INVALID_REQUEST).buildJSONMessage(); return Response.status(response.getResponseStatus()).header("Content-Type", "application/javascript") .entity(callback + "(" + response.getBody() + ");").build(); } } private Response handleClientFailure(String callback, OAuthRevocationResponseDTO dto) throws OAuthSystemException { if (callback == null || "".equals(callback)) { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST) .setError(dto.getErrorCode()).setErrorDescription(dto.getErrorMsg()).buildJSONMessage(); return Response.status(response.getResponseStatus()).header("Content-Type", "text/html") .entity(response.getBody()).build(); } else { OAuthResponse response = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST) .setError(dto.getErrorCode()).buildJSONMessage(); return Response.status(response.getResponseStatus()).header("Content-Type", "application/javascript") .entity(callback + "(" + response.getBody() + ");").build(); } } private void logAccessTokenRevocationRequest(HttpServletRequest request) { log.debug("Received a access token revocation request : " + request.getRequestURI()); // log the headers. log.debug("----------logging request headers.----------"); Enumeration headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = (String) headerNames.nextElement(); Enumeration headers = request.getHeaders(headerName); while (headers.hasMoreElements()) { log.debug(headerName + " : " + headers.nextElement()); } } // log the parameters. log.debug("----------logging request parameters.----------"); log.debug("token - " + request.getParameter("token")); } private OAuthRevocationResponseDTO revokeTokens(OAuthRevocationRequestDTO oauthRequest) throws OAuthClientException { OAuthRevocationRequestDTO revokeReqDTO = new OAuthRevocationRequestDTO(); revokeReqDTO.setConsumerKey(oauthRequest.getConsumerKey()); revokeReqDTO.setConsumerSecret(oauthRequest.getConsumerSecret()); revokeReqDTO.setToken(oauthRequest.getToken()); revokeReqDTO.setToken_type(oauthRequest.getToken_type()); return EndpointUtil.getOAuth2Service().revokeTokenByOAuthClient(revokeReqDTO); } }