Permalink
Browse files

SECOAUTH-241: added InsufficientScopeException

  • Loading branch information...
1 parent 43bd44a commit 3e964c2af6b0be10bef947fa539ed4cc0a89f550 @dsyer dsyer committed Apr 23, 2012
@@ -261,12 +261,12 @@ public void testInvalidScopeInTokenRequest() throws Exception {
// Need to use the client with a redirect because "my-less-trusted-client" has no registered scopes
String code = getAuthorizationCode("my-client-with-registered-redirect", "http://anywhere?key=value", "bogus");
confirmTokenRequestError("my-client-with-registered-redirect", "http://anywhere?key=value", code, "bogus",
- HttpStatus.FORBIDDEN, "invalid_scope");
+ HttpStatus.BAD_REQUEST, "invalid_scope");
}
@Test
@OAuth2ContextConfiguration(resource = MyClientWithRegisteredRedirect.class, initialize = false)
- public void testInvalidScopeInResourceRequest() throws Exception {
+ public void testInsufficientScopeInResourceRequest() throws Exception {
AuthorizationCodeResourceDetails resource = (AuthorizationCodeResourceDetails) context.getResource();
resource.setScope(Arrays.asList("trust"));
approveAccessTokenGrant("http://anywhere?key=value", true);
@@ -0,0 +1,36 @@
+package org.springframework.security.oauth2.common.exceptions;
+
+import java.util.Set;
+
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.oauth2.common.util.OAuth2Utils;
+
+/**
+ * Exception representing insufficient scope in a token when a request is handled by a Resource Server. It is akin to an
+ * {@link AccessDeniedException} and should result in a 403 (FORBIDDEN) HTTP status.
+ *
+ * @author Dave Syer
+ */
+public class InsufficientScopeException extends OAuth2Exception {
+
+ public InsufficientScopeException(String msg, Set<String> validScope) {
+ this(msg);
+ addAdditionalInformation("scope", OAuth2Utils.formatParameterList(validScope));
+ }
+
+ public InsufficientScopeException(String msg) {
+ super(msg);
+ }
+
+ @Override
+ public int getHttpErrorCode() {
+ return 403;
+ }
+
+ @Override
+ public String getOAuth2ErrorCode() {
+ // Not defined in the spec, so not really an OAuth2Exception
+ return "insufficient_scope";
+ }
+
+}
@@ -7,9 +7,7 @@
/**
* Exception representing an invalid scope in a token or authorization request (i.e. from an Authorization Server). Note
* that this is not the same as an access denied exception if the scope presented to a Resource Server is insufficient.
- * The spec is unclear on the correct value for the error code. The bearer spec says 403 (FORBIDDEN), so that's what we
- * use and it seems appropriate (the request is authenticated but not permitted), but it but it seems to be muddled
- * between this and the access denied case on the Resource Server.
+ * The spec in this case mandates a 400 status code.
*
* @author Ryan Heaton
* @author Dave Syer
@@ -26,11 +24,6 @@ public InvalidScopeException(String msg) {
}
@Override
- public int getHttpErrorCode() {
- return 403;
- }
-
- @Override
public String getOAuth2ErrorCode() {
return "invalid_scope";
}
@@ -26,7 +26,7 @@
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
-import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
+import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.web.util.ThrowableAnalyzer;
@@ -77,7 +77,7 @@
int status = e.getHttpErrorCode();
HttpHeaders headers = new HttpHeaders();
headers.set("Cache-Control", "no-store");
- if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InvalidScopeException)) {
+ if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) {
headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary()));
}
@@ -19,7 +19,7 @@
import java.util.HashSet;
import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
+import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.WebSecurityExpressionRoot;
@@ -80,12 +80,12 @@ public boolean oauthHasScope(String scope) {
*
* @param roles the scopes to check
* @return true if the OAuth2 token has one of these scopes
- * @throws InvalidScopeException if the scope is invalid and we were initialized with the flag to throw the exception
+ * @throws InsufficientScopeException if the scope is invalid and we were initialized with the flag to throw the exception
*/
public boolean oauthHasAnyScope(String... scopes) {
boolean result = OAuth2ExpressionUtils.hasAnyScope(authentication, scopes);
if (!result && throwExceptionOnInvalidScope) {
- throw new InvalidScopeException("Invalid scope for this resource scopes", new HashSet<String>(
+ throw new InsufficientScopeException("Invalid scope for this resource scopes", new HashSet<String>(
Arrays.asList(scopes)));
}
return result;
@@ -0,0 +1,53 @@
+/*
+ * Cloud Foundry 2012.02.03 Beta
+ * Copyright (c) [2009-2012] VMware, Inc. All Rights Reserved.
+ *
+ * This product is licensed to you under the Apache License, Version 2.0 (the "License").
+ * You may not use this product except in compliance with the License.
+ *
+ * This product includes a number of subcomponents with
+ * separate copyright notices and license terms. Your use of these
+ * subcomponents is subject to the terms and conditions of the
+ * subcomponent's license, as noted in the LICENSE file.
+ */
+
+package org.springframework.security.oauth2.provider.token;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
+
+/**
+ * A composite token enhancer that loops over its delegate enhancers.
+ *
+ * @author Dave Syer
+ *
+ */
+public class TokenEnhancerChain implements TokenEnhancer {
+
+ private List<TokenEnhancer> delegates = Collections.emptyList();
+
+ /**
+ * @param delegates the delegates to set
+ */
+ public void setTokenEnhancers(List<TokenEnhancer> delegates) {
+ this.delegates = delegates;
+ }
+
+ /**
+ * Loop over the {@link #setTokenEnhancers(List) delegates} passing the result into the next member of the chain.
+ *
+ * @see org.springframework.security.oauth2.provider.token.TokenEnhancer#enhance(org.springframework.security.oauth2.common.OAuth2AccessToken,
+ * org.springframework.security.oauth2.provider.OAuth2Authentication)
+ */
+ public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
+ OAuth2AccessToken result = accessToken;
+ for (TokenEnhancer enhancer : delegates) {
+ result = enhancer.enhance(result, authentication);
+ }
+ return result;
+ }
+
+}
@@ -23,7 +23,7 @@
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
+import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
@@ -63,9 +63,9 @@
private boolean throwException = true;
/**
- * Flag to determine the behaviour on access denied. If set then we throw an {@link InvalidScopeException} instead
- * of returning {@link AccessDecisionVoter#ACCESS_DENIED}. This is unconventional for an access decision voter
- * because it vetos the other voters in the chain, but it enables us to pass a message to the caller with
+ * Flag to determine the behaviour on access denied. If set then we throw an {@link InsufficientScopeException}
+ * instead of returning {@link AccessDecisionVoter#ACCESS_DENIED}. This is unconventional for an access decision
+ * voter because it vetos the other voters in the chain, but it enables us to pass a message to the caller with
* information about the required scope.
*
* @param throwException the flag to set (default true)
@@ -143,7 +143,7 @@ public int vote(Authentication authentication, Object object, Collection<ConfigA
}
}
if (result == ACCESS_DENIED && throwException) {
- throw new InvalidScopeException("Invalid scope for this resource scopes",
+ throw new InsufficientScopeException("Insufficient scope for this resource scopes",
Collections.singleton(attribute.getAttribute()));
}
}
@@ -26,7 +26,7 @@
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
+import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
@@ -82,7 +82,7 @@ public void testAccessDeniedIfWrongScopesPresent() throws Exception {
Collections.<ConfigAttribute> singleton(new SecurityConfig("SCOPE_WRITE"))));
}
- @Test(expected=InvalidScopeException.class)
+ @Test(expected=InsufficientScopeException.class)
public void testExceptionThrownIfWrongScopesPresent() throws Exception {
AuthorizationRequest clientAuthentication = new AuthorizationRequest("foo", Collections.singleton("read"), null, null);
Authentication userAuthentication = null;

0 comments on commit 3e964c2

Please sign in to comment.