Skip to content

Ensure access token isn't resolved from query for form-encoded requests #12990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import javax.servlet.http.HttpServletRequest;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.server.resource.BearerTokenError;
import org.springframework.security.oauth2.server.resource.BearerTokenErrorCodes;
Expand All @@ -36,6 +38,8 @@
*/
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-._~+/]+)=*$");

private boolean allowFormEncodedBodyParameter = false;
Expand Down Expand Up @@ -104,7 +108,7 @@ private static String resolveFromAuthorizationHeader(HttpServletRequest request)
}

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;
}
Expand All @@ -121,7 +125,20 @@ private static String resolveFromRequestParameters(HttpServletRequest request) {
}

private boolean isParameterTokenSupportedForRequest(HttpServletRequest request) {
return ((this.allowFormEncodedBodyParameter && "POST".equals(request.getMethod()))
|| (this.allowUriQueryParameter && "GET".equals(request.getMethod())));
return ((this.allowFormEncodedBodyParameter && isFormEncodedRequest(request) && !isGetRequest(request)
&& !hasAccessTokenInQueryString(request)) || (this.allowUriQueryParameter && isGetRequest(request)));
}

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);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public void resolveWhenValidHeaderIsPresentTogetherWithQueryParameterThenAuthent
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);

assertThatCode(() -> this.resolver.resolve(request)).isInstanceOf(OAuth2AuthenticationException.class)
Expand All @@ -117,7 +118,7 @@ public void resolveWhenRequestContainsTwoAccessTokenParametersThenAuthentication
}

@Test
public void resolveWhenFormParameterIsPresentAndSupportedThenTokenIsResolved() {
public void resolveWhenPostAndFormParameterIsPresentAndSupportedThenTokenIsResolved() {
this.resolver.setAllowFormEncodedBodyParameter(true);

MockHttpServletRequest request = new MockHttpServletRequest();
Expand All @@ -128,6 +129,67 @@ public void resolveWhenFormParameterIsPresentAndSupportedThenTokenIsResolved() {
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();
Expand All @@ -144,6 +206,7 @@ public void resolveWhenQueryParameterIsPresentAndSupportedThenTokenIsResolved()

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);
Expand All @@ -153,8 +216,10 @@ public void resolveWhenQueryParameterIsPresentAndSupportedThenTokenIsResolved()
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();
}

}