You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2013/06/06 13:00:25 UTC
svn commit: r1490236 - in
/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2:
provider/ services/ utils/
Author: sergeyb
Date: Thu Jun 6 11:00:24 2013
New Revision: 1490236
URL: http://svn.apache.org/r1490236
Log:
[CXF-5060] Adding Token Revocation service
Added:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenRevocationService.java (with props)
Modified:
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthDataProvider.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthConstants.java
Modified: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthDataProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthDataProvider.java?rev=1490236&r1=1490235&r2=1490236&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthDataProvider.java (original)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/OAuthDataProvider.java Thu Jun 6 11:00:24 2013
@@ -86,11 +86,20 @@ public interface OAuthDataProvider {
throws OAuthServiceException;
/**
- * Removes the token
+ * Removes the access token
+ * The runtime will call this method if it finds that a token has expired
* @param accessToken the token
* @throws OAuthServiceException
*/
void removeAccessToken(ServerAccessToken accessToken) throws OAuthServiceException;
+
+ /**
+ * Revokes a refresh or access token
+ * @param token token identifier
+ * @param tokenTypeHint
+ * @throws OAuthServiceException
+ */
+ void revokeToken(Client client, String token, String tokenTypeHint) throws OAuthServiceException;
/**
* Converts the requested scope to the list of permissions
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java?rev=1490236&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java Thu Jun 6 11:00:24 2013
@@ -0,0 +1,149 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.cxf.rs.security.oauth2.services;
+
+import java.security.Principal;
+
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+
+import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.apache.cxf.rs.security.oauth2.common.OAuthError;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
+import org.apache.cxf.rs.security.oauth2.utils.AuthorizationUtils;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
+
+public class AbstractTokenService extends AbstractOAuthService {
+ private boolean canSupportPublicClients;
+ private boolean writeCustomErrors;
+
+ /**
+ * Make sure the client is authenticated
+ */
+ protected Client authenticateClientIfNeeded(MultivaluedMap<String, String> params) {
+ Client client = null;
+ SecurityContext sc = getMessageContext().getSecurityContext();
+
+ if (params.containsKey(OAuthConstants.CLIENT_ID)) {
+ // both client_id and client_secret are expected in the form payload
+ client = getAndValidateClient(params.getFirst(OAuthConstants.CLIENT_ID),
+ params.getFirst(OAuthConstants.CLIENT_SECRET));
+ } else if (sc.getUserPrincipal() != null) {
+ // client has already authenticated
+ Principal p = sc.getUserPrincipal();
+ String scheme = sc.getAuthenticationScheme();
+ if (OAuthConstants.BASIC_SCHEME.equalsIgnoreCase(scheme)) {
+ // section 2.3.1
+ client = getClient(p.getName());
+ } else {
+ // section 2.3.2
+ // the client has authenticated itself using some other scheme
+ // in which case the mapping between the scheme and the client_id
+ // should've been done and the client_id is expected
+ // on the current message
+ Object clientIdProp = getMessageContext().get(OAuthConstants.CLIENT_ID);
+ if (clientIdProp != null) {
+ client = getClient(clientIdProp.toString());
+ // TODO: consider matching client.getUserSubject().getLoginName()
+ // against principal.getName() ?
+ }
+ }
+ } else {
+ // the client id and secret are expected to be in the Basic scheme data
+ String[] parts =
+ AuthorizationUtils.getAuthorizationParts(getMessageContext());
+ if (OAuthConstants.BASIC_SCHEME.equalsIgnoreCase(parts[0])) {
+ String[] authInfo = AuthorizationUtils.getBasicAuthParts(parts[1]);
+ client = getAndValidateClient(authInfo[0], authInfo[1]);
+ }
+ }
+
+ if (client == null) {
+ throw new NotAuthorizedException(Response.status(401).build());
+ }
+ return client;
+ }
+
+ // Get the Client and check the id and secret
+ protected Client getAndValidateClient(String clientId, String clientSecret) {
+ Client client = getClient(clientId);
+ if (canSupportPublicClients
+ && !client.isConfidential()
+ && client.getClientSecret() == null
+ && client.getRedirectUris().isEmpty()
+ && clientSecret == null) {
+ return client;
+ }
+ if (clientSecret == null || client.getClientSecret() == null
+ || !client.getClientId().equals(clientId)
+ || !client.getClientSecret().equals(clientSecret)) {
+ throw new NotAuthorizedException(Response.status(401).build());
+ }
+ return client;
+ }
+
+ protected Response handleException(OAuthServiceException ex, String error) {
+ OAuthError customError = ex.getError();
+ if (writeCustomErrors && customError != null) {
+ return createErrorResponseFromBean(customError);
+ } else {
+ return createErrorResponseFromBean(new OAuthError(error));
+ }
+ }
+
+ protected Response createErrorResponse(MultivaluedMap<String, String> params,
+ String error) {
+ return createErrorResponseFromBean(new OAuthError(error));
+ }
+
+ protected Response createErrorResponseFromBean(OAuthError errorBean) {
+ return Response.status(400).entity(errorBean).build();
+ }
+
+ /**
+ * Get the {@link Client} reference
+ * @param clientId the provided client id
+ * @return Client the client reference
+ * @throws {@link javax.ws.rs.WebApplicationException} if no matching Client is found
+ */
+ protected Client getClient(String clientId) {
+ Client client = null;
+ try {
+ client = getValidClient(clientId);
+ } catch (OAuthServiceException ex) {
+ // log it
+ }
+ if (client == null) {
+ reportInvalidRequestError("Client ID is invalid");
+ }
+ return client;
+
+ }
+
+ public void setCanSupportPublicClients(boolean support) {
+ this.canSupportPublicClients = support;
+ }
+
+ public void setWriteCustomErrors(boolean writeCustomErrors) {
+ this.writeCustomErrors = writeCustomErrors;
+ }
+}
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AbstractTokenService.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java?rev=1490236&r1=1490235&r2=1490236&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java (original)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/AccessTokenService.java Thu Jun 6 11:00:24 2013
@@ -19,30 +19,25 @@
package org.apache.cxf.rs.security.oauth2.services;
-import java.security.Principal;
import java.util.Collections;
import java.util.List;
import javax.ws.rs.Consumes;
-import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
-import javax.ws.rs.core.SecurityContext;
import org.apache.cxf.rs.security.oauth2.common.Client;
import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken;
-import org.apache.cxf.rs.security.oauth2.common.OAuthError;
import org.apache.cxf.rs.security.oauth2.common.OAuthPermission;
import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken;
import org.apache.cxf.rs.security.oauth2.grants.code.AuthorizationCodeDataProvider;
import org.apache.cxf.rs.security.oauth2.grants.code.AuthorizationCodeGrantHandler;
import org.apache.cxf.rs.security.oauth2.provider.AccessTokenGrantHandler;
import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
-import org.apache.cxf.rs.security.oauth2.utils.AuthorizationUtils;
import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils;
@@ -50,14 +45,8 @@ import org.apache.cxf.rs.security.oauth2
* OAuth2 Access Token Service implementation
*/
@Path("/token")
-public class AccessTokenService extends AbstractOAuthService {
+public class AccessTokenService extends AbstractTokenService {
private List<AccessTokenGrantHandler> grantHandlers = Collections.emptyList();
- private boolean writeCustomErrors;
- private boolean canSupportPublicClients;
-
- public void setWriteCustomErrors(boolean write) {
- writeCustomErrors = write;
- }
/**
* Sets the list of optional grant handlers
@@ -91,11 +80,7 @@ public class AccessTokenService extends
try {
serverToken = handler.createAccessToken(client, params);
} catch (OAuthServiceException ex) {
- OAuthError customError = ex.getError();
- if (writeCustomErrors && customError != null) {
- return createErrorResponseFromBean(customError);
- }
-
+ return handleException(ex, OAuthConstants.INVALID_GRANT);
}
if (serverToken == null) {
return createErrorResponse(params, OAuthConstants.INVALID_GRANT);
@@ -122,71 +107,6 @@ public class AccessTokenService extends
}
/**
- * Make sure the client is authenticated
- */
- private Client authenticateClientIfNeeded(MultivaluedMap<String, String> params) {
- Client client = null;
- SecurityContext sc = getMessageContext().getSecurityContext();
-
- if (params.containsKey(OAuthConstants.CLIENT_ID)) {
- // both client_id and client_secret are expected in the form payload
- client = getAndValidateClient(params.getFirst(OAuthConstants.CLIENT_ID),
- params.getFirst(OAuthConstants.CLIENT_SECRET));
- } else if (sc.getUserPrincipal() != null) {
- // client has already authenticated
- Principal p = sc.getUserPrincipal();
- String scheme = sc.getAuthenticationScheme();
- if (OAuthConstants.BASIC_SCHEME.equalsIgnoreCase(scheme)) {
- // section 2.3.1
- client = getClient(p.getName());
- } else {
- // section 2.3.2
- // the client has authenticated itself using some other scheme
- // in which case the mapping between the scheme and the client_id
- // should've been done and the client_id is expected
- // on the current message
- Object clientIdProp = getMessageContext().get(OAuthConstants.CLIENT_ID);
- if (clientIdProp != null) {
- client = getClient(clientIdProp.toString());
- // TODO: consider matching client.getUserSubject().getLoginName()
- // against principal.getName() ?
- }
- }
- } else {
- // the client id and secret are expected to be in the Basic scheme data
- String[] parts =
- AuthorizationUtils.getAuthorizationParts(getMessageContext());
- if (OAuthConstants.BASIC_SCHEME.equalsIgnoreCase(parts[0])) {
- String[] authInfo = AuthorizationUtils.getBasicAuthParts(parts[1]);
- client = getAndValidateClient(authInfo[0], authInfo[1]);
- }
- }
-
- if (client == null) {
- throw new NotAuthorizedException(Response.status(401).build());
- }
- return client;
- }
-
- // Get the Client and check the id and secret
- private Client getAndValidateClient(String clientId, String clientSecret) {
- Client client = getClient(clientId);
- if (canSupportPublicClients
- && !client.isConfidential()
- && client.getClientSecret() == null
- && client.getRedirectUris().isEmpty()
- && clientSecret == null) {
- return client;
- }
- if (clientSecret == null || client.getClientSecret() == null
- || !client.getClientId().equals(clientId)
- || !client.getClientSecret().equals(clientSecret)) {
- throw new NotAuthorizedException(Response.status(401).build());
- }
- return client;
- }
-
- /**
* Find the mathcing grant handler
*/
protected AccessTokenGrantHandler findGrantHandler(MultivaluedMap<String, String> params) {
@@ -210,37 +130,4 @@ public class AccessTokenService extends
return null;
}
-
- protected Response createErrorResponse(MultivaluedMap<String, String> params,
- String error) {
- return createErrorResponseFromBean(new OAuthError(error));
- }
-
- protected Response createErrorResponseFromBean(OAuthError errorBean) {
- return Response.status(400).entity(errorBean).build();
- }
-
- /**
- * Get the {@link Client} reference
- * @param clientId the provided client id
- * @return Client the client reference
- * @throws {@link javax.ws.rs.WebApplicationException} if no matching Client is found
- */
- protected Client getClient(String clientId) {
- Client client = null;
- try {
- client = getValidClient(clientId);
- } catch (OAuthServiceException ex) {
- // log it
- }
- if (client == null) {
- reportInvalidRequestError("Client ID is invalid");
- }
- return client;
-
- }
-
- public void setCanSupportPublicClients(boolean support) {
- this.canSupportPublicClients = support;
- }
-}
+}
\ No newline at end of file
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenRevocationService.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenRevocationService.java?rev=1490236&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenRevocationService.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenRevocationService.java Thu Jun 6 11:00:24 2013
@@ -0,0 +1,63 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.cxf.rs.security.oauth2.services;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
+
+/**
+ * OAuth2 Token Revocation Service implementation
+ */
+@Path("/revoke")
+public class TokenRevocationService extends AbstractTokenService {
+
+ /**
+ * Processes a token revocation request
+ * @param params the form parameters representing the access token grant
+ * @return Access Token or the error
+ */
+ @POST
+ @Consumes("application/x-www-form-urlencoded")
+ @Produces("application/json")
+ public Response handleTokenRevocation(MultivaluedMap<String, String> params) {
+
+ // Make sure the client is authenticated
+ Client client = authenticateClientIfNeeded(params);
+ String token = params.getFirst(OAuthConstants.REVOKED_TOKEN_ID);
+ if (token == null) {
+ return createErrorResponse(params, OAuthConstants.UNSUPPORTED_TOKEN_TYPE);
+ }
+ String tokenTypeHint = params.getFirst(OAuthConstants.REVOKED_TOKEN_TYPE_HINT);
+ try {
+ getDataProvider().revokeToken(client, token, tokenTypeHint);
+ } catch (OAuthServiceException ex) {
+ return handleException(ex, OAuthConstants.UNSUPPORTED_TOKEN_TYPE);
+ }
+ return Response.ok().build();
+ }
+}
\ No newline at end of file
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenRevocationService.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/TokenRevocationService.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthConstants.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthConstants.java?rev=1490236&r1=1490235&r2=1490236&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthConstants.java (original)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthConstants.java Thu Jun 6 11:00:24 2013
@@ -98,6 +98,11 @@ public final class OAuthConstants {
public static final String INVALID_SCOPE = "invalid_scope";
public static final String ACCESS_DENIED = "access_denied";
+ // Token Revocation
+ public static final String REVOKED_TOKEN_ID = "token";
+ public static final String REVOKED_TOKEN_TYPE_HINT = "token_type_hint";
+ public static final String UNSUPPORTED_TOKEN_TYPE = "unsupported_token_type";
+
// CXF-Specific parameters
public static final String ACCESS_TOKEN_ISSUED_AT = "issued_at";
// End Of CXF-Specific