Pārlūkot izejas kodu

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
Édouard Hue 6 gadi atpakaļ
vecāks
revīzija
e8dd1325fd

+ 8 - 10
config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java

@@ -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) {

+ 9 - 44
oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/access/BearerTokenAccessDeniedHandler.java

@@ -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()) {

+ 10 - 42
oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/access/server/BearerTokenServerAccessDeniedHandler.java

@@ -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()) {

+ 5 - 130
oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/access/BearerTokenAccessDeniedHandlerTests.java

@@ -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_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_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 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))

+ 7 - 120
oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/access/server/BearerTokenServerAccessDeniedHandlerTests.java

@@ -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_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_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 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))