Ensure access token isn't resolved from query for form-encoded requests
Closes gh-5668
This commit is contained in:
parent
20b0156d5a
commit
6f8ec3df60
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -22,6 +22,7 @@ import java.util.regex.Pattern;
|
|||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenError;
|
||||
|
@ -38,6 +39,8 @@ import org.springframework.util.StringUtils;
|
|||
*/
|
||||
public final class DefaultBearerTokenResolver implements BearerTokenResolver {
|
||||
|
||||
private static final String ACCESS_TOKEN_PARAMETER_NAME = "access_token";
|
||||
|
||||
private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?<token>[a-zA-Z0-9-._~+/]+=*)$",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
|
@ -115,7 +118,7 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver {
|
|||
}
|
||||
|
||||
private static String resolveFromRequestParameters(HttpServletRequest request) {
|
||||
String[] values = request.getParameterValues("access_token");
|
||||
String[] values = request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME);
|
||||
if (values == null || values.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -127,15 +130,24 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver {
|
|||
}
|
||||
|
||||
private boolean isParameterTokenSupportedForRequest(final HttpServletRequest request) {
|
||||
return (("POST".equals(request.getMethod())
|
||||
&& MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType()))
|
||||
|| "GET".equals(request.getMethod()));
|
||||
return isFormEncodedRequest(request) || isGetRequest(request);
|
||||
}
|
||||
|
||||
private boolean isParameterTokenEnabledForRequest(final HttpServletRequest request) {
|
||||
return ((this.allowFormEncodedBodyParameter && "POST".equals(request.getMethod())
|
||||
&& MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType()))
|
||||
|| (this.allowUriQueryParameter && "GET".equals(request.getMethod())));
|
||||
private static boolean isGetRequest(HttpServletRequest request) {
|
||||
return HttpMethod.GET.name().equals(request.getMethod());
|
||||
}
|
||||
|
||||
private static boolean isFormEncodedRequest(HttpServletRequest request) {
|
||||
return MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType());
|
||||
}
|
||||
|
||||
private static boolean hasAccessTokenInQueryString(HttpServletRequest request) {
|
||||
return (request.getQueryString() != null) && request.getQueryString().contains(ACCESS_TOKEN_PARAMETER_NAME);
|
||||
}
|
||||
|
||||
private boolean isParameterTokenEnabledForRequest(HttpServletRequest request) {
|
||||
return ((this.allowFormEncodedBodyParameter && isFormEncodedRequest(request) && !isGetRequest(request)
|
||||
&& !hasAccessTokenInQueryString(request)) || (this.allowUriQueryParameter && isGetRequest(request)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -121,6 +121,7 @@ public class DefaultBearerTokenResolverTests {
|
|||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader("Authorization", "Bearer " + TEST_TOKEN);
|
||||
request.setMethod("GET");
|
||||
request.setQueryString("access_token=" + TEST_TOKEN);
|
||||
request.addParameter("access_token", TEST_TOKEN);
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.resolver.resolve(request))
|
||||
.withMessageContaining("Found multiple bearer tokens in the request");
|
||||
|
@ -159,7 +160,7 @@ public class DefaultBearerTokenResolverTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenFormParameterIsPresentAndSupportedThenTokenIsResolved() {
|
||||
public void resolveWhenPostAndFormParameterIsPresentAndSupportedThenTokenIsResolved() {
|
||||
this.resolver.setAllowFormEncodedBodyParameter(true);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("POST");
|
||||
|
@ -168,6 +169,67 @@ public class DefaultBearerTokenResolverTests {
|
|||
assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenPutAndFormParameterIsPresentAndSupportedThenTokenIsResolved() {
|
||||
this.resolver.setAllowFormEncodedBodyParameter(true);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("PUT");
|
||||
request.setContentType("application/x-www-form-urlencoded");
|
||||
request.addParameter("access_token", TEST_TOKEN);
|
||||
|
||||
assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenPatchAndFormParameterIsPresentAndSupportedThenTokenIsResolved() {
|
||||
this.resolver.setAllowFormEncodedBodyParameter(true);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("PATCH");
|
||||
request.setContentType("application/x-www-form-urlencoded");
|
||||
request.addParameter("access_token", TEST_TOKEN);
|
||||
|
||||
assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenDeleteAndFormParameterIsPresentAndSupportedThenTokenIsResolved() {
|
||||
this.resolver.setAllowFormEncodedBodyParameter(true);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("DELETE");
|
||||
request.setContentType("application/x-www-form-urlencoded");
|
||||
request.addParameter("access_token", TEST_TOKEN);
|
||||
|
||||
assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenGetAndFormParameterIsPresentAndSupportedThenTokenIsNotResolved() {
|
||||
this.resolver.setAllowFormEncodedBodyParameter(true);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("GET");
|
||||
request.setContentType("application/x-www-form-urlencoded");
|
||||
request.addParameter("access_token", TEST_TOKEN);
|
||||
|
||||
assertThat(this.resolver.resolve(request)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenPostAndFormParameterIsSupportedAndQueryParameterIsPresentThenTokenIsNotResolved() {
|
||||
this.resolver.setAllowFormEncodedBodyParameter(true);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("POST");
|
||||
request.setContentType("application/x-www-form-urlencoded");
|
||||
request.setQueryString("access_token=" + TEST_TOKEN);
|
||||
request.addParameter("access_token", TEST_TOKEN);
|
||||
|
||||
assertThat(this.resolver.resolve(request)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWhenFormParameterIsPresentAndNotSupportedThenTokenIsNotResolved() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
@ -182,6 +244,7 @@ public class DefaultBearerTokenResolverTests {
|
|||
this.resolver.setAllowUriQueryParameter(true);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("GET");
|
||||
request.setQueryString("access_token=" + TEST_TOKEN);
|
||||
request.addParameter("access_token", TEST_TOKEN);
|
||||
assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN);
|
||||
}
|
||||
|
@ -190,6 +253,7 @@ public class DefaultBearerTokenResolverTests {
|
|||
public void resolveWhenQueryParameterIsPresentAndNotSupportedThenTokenIsNotResolved() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("GET");
|
||||
request.setQueryString("access_token=" + TEST_TOKEN);
|
||||
request.addParameter("access_token", TEST_TOKEN);
|
||||
assertThat(this.resolver.resolve(request)).isNull();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue