Fixed misleading OAuth2 error messages
Error messages sent by BearerTokenAccessDeniedHandler included information about the scopes of the rejected token instead of the scopes required by the resource. * Removal of token scopes from error_description attribute. * Removal of scope attribute from WWW-Authenticate response header. Fixes gh-7089
This commit is contained in:
parent
b153d92b23
commit
e8dd1325fd
|
@ -108,7 +108,6 @@ import org.springframework.test.web.servlet.ResultMatcher;
|
|||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -397,7 +396,7 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
this.mvc.perform(get("/requires-read-scope")
|
||||
.with(bearerToken(token)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(insufficientScopeHeader(""));
|
||||
.andExpect(insufficientScopeHeader());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -411,7 +410,7 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
this.mvc.perform(get("/requires-read-scope")
|
||||
.with(bearerToken(token)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(insufficientScopeHeader("message:write"));
|
||||
.andExpect(insufficientScopeHeader());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -497,7 +496,7 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
this.mvc.perform(get("/ms-requires-read-scope")
|
||||
.with(bearerToken(token)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(insufficientScopeHeader(""));
|
||||
.andExpect(insufficientScopeHeader());
|
||||
|
||||
}
|
||||
|
||||
|
@ -512,7 +511,7 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
this.mvc.perform(get("/ms-requires-read-scope")
|
||||
.with(bearerToken(token)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(insufficientScopeHeader("message:write"));
|
||||
.andExpect(insufficientScopeHeader());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -526,7 +525,7 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
this.mvc.perform(get("/ms-deny")
|
||||
.with(bearerToken(token)))
|
||||
.andExpect(status().isForbidden())
|
||||
.andExpect(insufficientScopeHeader("message:read"));
|
||||
.andExpect(insufficientScopeHeader());
|
||||
}
|
||||
|
||||
// -- Resource Server should not engage csrf
|
||||
|
@ -2230,12 +2229,11 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
);
|
||||
}
|
||||
|
||||
private static ResultMatcher insufficientScopeHeader(String scope) {
|
||||
private static ResultMatcher insufficientScopeHeader() {
|
||||
return header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer " +
|
||||
"error=\"insufficient_scope\"" +
|
||||
", error_description=\"The token provided has insufficient scope [" + scope + "] for this request\"" +
|
||||
", error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"" +
|
||||
(StringUtils.hasText(scope) ? ", scope=\"" + scope + "\"" : ""));
|
||||
", error_description=\"The request requires higher privileges than provided by the access token.\"" +
|
||||
", error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
|
||||
}
|
||||
|
||||
private void mockWebServer(String response) {
|
||||
|
|
|
@ -16,16 +16,6 @@
|
|||
|
||||
package org.springframework.security.oauth2.server.resource.web.access;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
|
@ -33,7 +23,14 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Translates any {@link AccessDeniedException} into an HTTP response in accordance with
|
||||
|
@ -48,9 +45,6 @@ import org.springframework.util.StringUtils;
|
|||
*/
|
||||
public final class BearerTokenAccessDeniedHandler implements AccessDeniedHandler {
|
||||
|
||||
private static final Collection<String> WELL_KNOWN_SCOPE_ATTRIBUTE_NAMES =
|
||||
Arrays.asList("scope", "scp");
|
||||
|
||||
private String realmName;
|
||||
|
||||
/**
|
||||
|
@ -75,19 +69,9 @@ public final class BearerTokenAccessDeniedHandler implements AccessDeniedHandler
|
|||
}
|
||||
|
||||
if (request.getUserPrincipal() instanceof AbstractOAuth2TokenAuthenticationToken) {
|
||||
AbstractOAuth2TokenAuthenticationToken token =
|
||||
(AbstractOAuth2TokenAuthenticationToken) request.getUserPrincipal();
|
||||
|
||||
String scope = getScope(token);
|
||||
|
||||
parameters.put("error", BearerTokenErrorCodes.INSUFFICIENT_SCOPE);
|
||||
parameters.put("error_description",
|
||||
String.format("The token provided has insufficient scope [%s] for this request", scope));
|
||||
parameters.put("error_description", "The request requires higher privileges than provided by the access token.");
|
||||
parameters.put("error_uri", "https://tools.ietf.org/html/rfc6750#section-3.1");
|
||||
|
||||
if (StringUtils.hasText(scope)) {
|
||||
parameters.put("scope", scope);
|
||||
}
|
||||
}
|
||||
|
||||
String wwwAuthenticate = computeWWWAuthenticateHeaderValue(parameters);
|
||||
|
@ -105,25 +89,6 @@ public final class BearerTokenAccessDeniedHandler implements AccessDeniedHandler
|
|||
this.realmName = realmName;
|
||||
}
|
||||
|
||||
private static String getScope(AbstractOAuth2TokenAuthenticationToken token) {
|
||||
|
||||
Map<String, Object> attributes = token.getTokenAttributes();
|
||||
|
||||
for (String attributeName : WELL_KNOWN_SCOPE_ATTRIBUTE_NAMES) {
|
||||
Object scopes = attributes.get(attributeName);
|
||||
if (scopes instanceof String) {
|
||||
return (String) scopes;
|
||||
} else if (scopes instanceof Collection) {
|
||||
Collection coll = (Collection) scopes;
|
||||
return (String) coll.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String computeWWWAuthenticateHeaderValue(Map<String, String> parameters) {
|
||||
String wwwAuthenticate = "Bearer";
|
||||
if (!parameters.isEmpty()) {
|
||||
|
|
|
@ -16,14 +16,6 @@
|
|||
|
||||
package org.springframework.security.oauth2.server.resource.web.access.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
|
@ -31,8 +23,14 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
|
||||
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Translates any {@link AccessDeniedException} into an HTTP response in accordance with
|
||||
|
@ -63,8 +61,7 @@ public class BearerTokenServerAccessDeniedHandler implements ServerAccessDeniedH
|
|||
|
||||
return exchange.getPrincipal()
|
||||
.filter(AbstractOAuth2TokenAuthenticationToken.class::isInstance)
|
||||
.cast(AbstractOAuth2TokenAuthenticationToken.class)
|
||||
.map(token -> errorMessageParameters(token, parameters))
|
||||
.map(token -> errorMessageParameters(parameters))
|
||||
.switchIfEmpty(Mono.just(parameters))
|
||||
.flatMap(params -> respond(exchange, params));
|
||||
}
|
||||
|
@ -78,21 +75,11 @@ public class BearerTokenServerAccessDeniedHandler implements ServerAccessDeniedH
|
|||
this.realmName = realmName;
|
||||
}
|
||||
|
||||
private static Map<String, String> errorMessageParameters(
|
||||
AbstractOAuth2TokenAuthenticationToken token,
|
||||
Map<String, String> parameters) {
|
||||
|
||||
String scope = getScope(token);
|
||||
|
||||
private static Map<String, String> errorMessageParameters(Map<String, String> parameters) {
|
||||
parameters.put("error", BearerTokenErrorCodes.INSUFFICIENT_SCOPE);
|
||||
parameters.put("error_description",
|
||||
String.format("The token provided has insufficient scope [%s] for this request", scope));
|
||||
parameters.put("error_description", "The request requires higher privileges than provided by the access token.");
|
||||
parameters.put("error_uri", "https://tools.ietf.org/html/rfc6750#section-3.1");
|
||||
|
||||
if (StringUtils.hasText(scope)) {
|
||||
parameters.put("scope", scope);
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
@ -103,25 +90,6 @@ public class BearerTokenServerAccessDeniedHandler implements ServerAccessDeniedH
|
|||
return exchange.getResponse().setComplete();
|
||||
}
|
||||
|
||||
private static String getScope(AbstractOAuth2TokenAuthenticationToken token) {
|
||||
|
||||
Map<String, Object> attributes = token.getTokenAttributes();
|
||||
|
||||
for (String attributeName : WELL_KNOWN_SCOPE_ATTRIBUTE_NAMES) {
|
||||
Object scopes = attributes.get(attributeName);
|
||||
if (scopes instanceof String) {
|
||||
return (String) scopes;
|
||||
} else if (scopes instanceof Collection) {
|
||||
Collection coll = (Collection) scopes;
|
||||
return (String) coll.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String computeWWWAuthenticateHeaderValue(Map<String, String> parameters) {
|
||||
String wwwAuthenticate = "Bearer";
|
||||
if (!parameters.isEmpty()) {
|
||||
|
|
|
@ -16,14 +16,8 @@
|
|||
|
||||
package org.springframework.security.oauth2.server.resource.web.access;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.assertj.core.util.Maps;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
|
@ -31,6 +25,9 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
|
||||
|
@ -81,7 +78,7 @@ public class BearerTokenAccessDeniedHandlerTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasNoScopesThenInsufficientScopeError()
|
||||
public void handleWhenOAuth2AuthenticatedThenStatus403AndAuthHeaderWithInsufficientScopeErrorAttribute()
|
||||
throws Exception {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
@ -94,132 +91,10 @@ public class BearerTokenAccessDeniedHandlerTests {
|
|||
|
||||
assertThat(response.getStatus()).isEqualTo(403);
|
||||
assertThat(response.getHeader("WWW-Authenticate")).isEqualTo("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [] for this request\", " +
|
||||
"error_description=\"The request requires higher privileges than provided by the access token.\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasScopeAttributeThenInsufficientScopeErrorWithScopes()
|
||||
throws Exception {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Map<String, Object> attributes = Maps.newHashMap("scope", "message:read message:write");
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
request.setUserPrincipal(token);
|
||||
|
||||
this.accessDeniedHandler.handle(request, response, null);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(403);
|
||||
assertThat(response.getHeader("WWW-Authenticate")).isEqualTo("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [message:read message:write] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\", " +
|
||||
"scope=\"message:read message:write\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasEmptyScopeAttributeThenInsufficientScopeError()
|
||||
throws Exception {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Map<String, Object> attributes = Maps.newHashMap("scope", "");
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
request.setUserPrincipal(token);
|
||||
|
||||
this.accessDeniedHandler.handle(request, response, null);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(403);
|
||||
assertThat(response.getHeader("WWW-Authenticate")).isEqualTo("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasScpAttributeThenInsufficientScopeErrorWithScopes()
|
||||
throws Exception {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Map<String, Object> attributes = Maps.newHashMap("scp", Arrays.asList("message:read", "message:write"));
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
request.setUserPrincipal(token);
|
||||
|
||||
this.accessDeniedHandler.handle(request, response, null);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(403);
|
||||
assertThat(response.getHeader("WWW-Authenticate")).isEqualTo("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [message:read message:write] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\", " +
|
||||
"scope=\"message:read message:write\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasEmptyScpAttributeThenInsufficientScopeError()
|
||||
throws Exception {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Map<String, Object> attributes = Maps.newHashMap("scp", Collections.emptyList());
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
request.setUserPrincipal(token);
|
||||
|
||||
this.accessDeniedHandler.handle(request, response, null);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(403);
|
||||
assertThat(response.getHeader("WWW-Authenticate")).isEqualTo("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasBothScopeAndScpAttributesTheInsufficientErrorBasedOnScopeAttribute()
|
||||
throws Exception {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Map<String, Object> attributes = Maps.newHashMap("scp", Arrays.asList("message:read", "message:write"));
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
request.setUserPrincipal(token);
|
||||
attributes.put("scope", "missive:read missive:write");
|
||||
|
||||
this.accessDeniedHandler.handle(request, response, null);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(403);
|
||||
assertThat(response.getHeader("WWW-Authenticate")).isEqualTo("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [missive:read missive:write] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\", " +
|
||||
"scope=\"missive:read missive:write\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasScopeAttributeAndRealmIsSetThenInsufficientScopeErrorWithScopesAndRealm()
|
||||
throws Exception {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Map<String, Object> attributes = Maps.newHashMap("scope", "message:read message:write");
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
request.setUserPrincipal(token);
|
||||
|
||||
this.accessDeniedHandler.setRealmName("test");
|
||||
this.accessDeniedHandler.handle(request, response, null);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(403);
|
||||
assertThat(response.getHeader("WWW-Authenticate")).isEqualTo("Bearer realm=\"test\", " +
|
||||
"error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [message:read message:write] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\", " +
|
||||
"scope=\"message:read message:write\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRealmNameWhenNullRealmNameThenNoExceptionThrown() {
|
||||
assertThatCode(() -> this.accessDeniedHandler.setRealmName(null))
|
||||
|
|
|
@ -16,15 +16,8 @@
|
|||
|
||||
package org.springframework.security.oauth2.server.resource.web.access.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.assertj.core.util.Maps;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpResponse;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
|
@ -32,6 +25,11 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
|
@ -78,7 +76,7 @@ public class BearerTokenServerAccessDeniedHandlerTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasNoScopesThenInsufficientScopeError() {
|
||||
public void handleWhenOAuth2AuthenticatedThenStatus403AndAuthHeaderWithInsufficientScopeErrorAttribute() {
|
||||
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(Collections.emptyMap());
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
|
@ -90,121 +88,10 @@ public class BearerTokenServerAccessDeniedHandlerTests {
|
|||
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
assertThat(exchange.getResponse().getHeaders().get("WWW-Authenticate")).isEqualTo(
|
||||
Arrays.asList("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [] for this request\", " +
|
||||
"error_description=\"The request requires higher privileges than provided by the access token.\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\""));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasScopeAttributeThenInsufficientScopeErrorWithScopes() {
|
||||
Map<String, Object> attributes = Maps.newHashMap("scope", "message:read message:write");
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
when(exchange.getPrincipal()).thenReturn(Mono.just(token));
|
||||
when(exchange.getResponse()).thenReturn(new MockServerHttpResponse());
|
||||
|
||||
this.accessDeniedHandler.handle(exchange, null).block();
|
||||
|
||||
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
assertThat(exchange.getResponse().getHeaders().get("WWW-Authenticate")).isEqualTo(
|
||||
Arrays.asList("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [message:read message:write] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\", " +
|
||||
"scope=\"message:read message:write\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasEmptyScopeAttributeThenInsufficientScopeError() {
|
||||
Map<String, Object> attributes = Maps.newHashMap("scope", "");
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
when(exchange.getPrincipal()).thenReturn(Mono.just(token));
|
||||
when(exchange.getResponse()).thenReturn(new MockServerHttpResponse());
|
||||
|
||||
this.accessDeniedHandler.handle(exchange, null).block();
|
||||
|
||||
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
assertThat(exchange.getResponse().getHeaders().get("WWW-Authenticate")).isEqualTo(
|
||||
Arrays.asList("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasScpAttributeThenInsufficientScopeErrorWithScopes() {
|
||||
Map<String, Object> attributes = Maps.newHashMap("scp", Arrays.asList("message:read", "message:write"));
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
when(exchange.getPrincipal()).thenReturn(Mono.just(token));
|
||||
when(exchange.getResponse()).thenReturn(new MockServerHttpResponse());
|
||||
|
||||
this.accessDeniedHandler.handle(exchange, null).block();
|
||||
|
||||
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
assertThat(exchange.getResponse().getHeaders().get("WWW-Authenticate")).isEqualTo(
|
||||
Arrays.asList("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [message:read message:write] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\", " +
|
||||
"scope=\"message:read message:write\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasEmptyScpAttributeThenInsufficientScopeError() {
|
||||
|
||||
Map<String, Object> attributes = Maps.newHashMap("scp", Collections.emptyList());
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
when(exchange.getPrincipal()).thenReturn(Mono.just(token));
|
||||
when(exchange.getResponse()).thenReturn(new MockServerHttpResponse());
|
||||
|
||||
this.accessDeniedHandler.handle(exchange, null).block();
|
||||
|
||||
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
assertThat(exchange.getResponse().getHeaders().get("WWW-Authenticate")).isEqualTo(
|
||||
Arrays.asList("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasBothScopeAndScpAttributesTheInsufficientErrorBasedOnScopeAttribute() {
|
||||
Map<String, Object> attributes = Maps.newHashMap("scp", Arrays.asList("message:read", "message:write"));
|
||||
attributes.put("scope", "missive:read missive:write");
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
when(exchange.getPrincipal()).thenReturn(Mono.just(token));
|
||||
when(exchange.getResponse()).thenReturn(new MockServerHttpResponse());
|
||||
|
||||
this.accessDeniedHandler.handle(exchange, null).block();
|
||||
|
||||
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
assertThat(exchange.getResponse().getHeaders().get("WWW-Authenticate")).isEqualTo(
|
||||
Arrays.asList("Bearer error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [missive:read missive:write] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\", " +
|
||||
"scope=\"missive:read missive:write\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleWhenTokenHasScopeAttributeAndRealmIsSetThenInsufficientScopeErrorWithScopesAndRealm() {
|
||||
Map<String, Object> attributes = Maps.newHashMap("scope", "message:read message:write");
|
||||
Authentication token = new TestingOAuth2TokenAuthenticationToken(attributes);
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
when(exchange.getPrincipal()).thenReturn(Mono.just(token));
|
||||
when(exchange.getResponse()).thenReturn(new MockServerHttpResponse());
|
||||
|
||||
this.accessDeniedHandler.setRealmName("test");
|
||||
this.accessDeniedHandler.handle(exchange, null).block();
|
||||
|
||||
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
assertThat(exchange.getResponse().getHeaders().get("WWW-Authenticate"))
|
||||
.isEqualTo(Arrays.asList("Bearer realm=\"test\", " +
|
||||
"error=\"insufficient_scope\", " +
|
||||
"error_description=\"The token provided has insufficient scope [message:read message:write] for this request\", " +
|
||||
"error_uri=\"https://tools.ietf.org/html/rfc6750#section-3.1\", " +
|
||||
"scope=\"message:read message:write\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setRealmNameWhenNullRealmNameThenNoExceptionThrown() {
|
||||
assertThatCode(() -> this.accessDeniedHandler.setRealmName(null))
|
||||
|
|
Loading…
Reference in New Issue