Skip to content
This repository has been archived by the owner on May 31, 2022. It is now read-only.

Commit

Permalink
SECOAUTH-241: added InsufficientScopeException
Browse files Browse the repository at this point in the history
  • Loading branch information
dsyer committed Apr 23, 2012
1 parent 43bd44a commit 3e964c2
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,11 +23,6 @@ public InvalidScopeException(String msg) {
super(msg);
}

@Override
public int getHttpErrorCode() {
return 403;
}

@Override
public String getOAuth2ErrorCode() {
return "invalid_scope";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -77,7 +77,7 @@ private ResponseEntity<OAuth2Exception> handleOAuth2Exception(OAuth2Exception e)
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()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -63,9 +63,9 @@ public class ScopeVoter implements AccessDecisionVoter<Object> {
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)
Expand Down Expand Up @@ -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()));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 3e964c2

Please sign in to comment.