Merge branch '0.4.x' into 1.0.x
Closes gh-1150
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2020-2022 the original author or authors.
|
* Copyright 2020-2023 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -100,23 +100,8 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationValidator impleme
|
|||||||
authorizationCodeRequestAuthentication, registeredClient);
|
authorizationCodeRequestAuthentication, registeredClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
String requestedRedirectHost = requestedRedirect.getHost();
|
if (!isLoopbackAddress(requestedRedirect.getHost())) {
|
||||||
if (requestedRedirectHost == null || requestedRedirectHost.equals("localhost")) {
|
// As per https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-22#section-4.1.3
|
||||||
// As per https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07#section-9.7.1
|
|
||||||
// While redirect URIs using localhost (i.e., "http://localhost:{port}/{path}")
|
|
||||||
// function similarly to loopback IP redirects described in Section 10.3.3,
|
|
||||||
// the use of "localhost" is NOT RECOMMENDED.
|
|
||||||
OAuth2Error error = new OAuth2Error(
|
|
||||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
|
||||||
"localhost is not allowed for the redirect_uri (" + requestedRedirectUri + "). " +
|
|
||||||
"Use the IP literal (127.0.0.1) instead.",
|
|
||||||
"https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07#section-9.7.1");
|
|
||||||
throwError(error, OAuth2ParameterNames.REDIRECT_URI,
|
|
||||||
authorizationCodeRequestAuthentication, registeredClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isLoopbackAddress(requestedRedirectHost)) {
|
|
||||||
// As per https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07#section-9.7
|
|
||||||
// When comparing client redirect URIs against pre-registered URIs,
|
// When comparing client redirect URIs against pre-registered URIs,
|
||||||
// authorization servers MUST utilize exact string matching.
|
// authorization servers MUST utilize exact string matching.
|
||||||
if (!registeredClient.getRedirectUris().contains(requestedRedirectUri)) {
|
if (!registeredClient.getRedirectUris().contains(requestedRedirectUri)) {
|
||||||
@@ -124,7 +109,7 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationValidator impleme
|
|||||||
authorizationCodeRequestAuthentication, registeredClient);
|
authorizationCodeRequestAuthentication, registeredClient);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// As per https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07#section-10.3.3
|
// As per https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-08#section-8.4.2
|
||||||
// The authorization server MUST allow any port to be specified at the
|
// The authorization server MUST allow any port to be specified at the
|
||||||
// time of the request for loopback IP redirect URIs, to accommodate
|
// time of the request for loopback IP redirect URIs, to accommodate
|
||||||
// clients that obtain an available ephemeral port from the operating
|
// clients that obtain an available ephemeral port from the operating
|
||||||
@@ -157,6 +142,9 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationValidator impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isLoopbackAddress(String host) {
|
private static boolean isLoopbackAddress(String host) {
|
||||||
|
if (!StringUtils.hasText(host)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// IPv6 loopback address should either be "0:0:0:0:0:0:0:1" or "::1"
|
// IPv6 loopback address should either be "0:0:0:0:0:0:0:1" or "::1"
|
||||||
if ("[0:0:0:0:0:0:0:1]".equals(host) || "[::1]".equals(host)) {
|
if ("[0:0:0:0:0:0:0:1]".equals(host) || "[::1]".equals(host)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -181,27 +181,6 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// gh-243
|
|
||||||
@Test
|
|
||||||
public void authenticateWhenRedirectUriLocalhostThenThrowOAuth2AuthorizationCodeRequestAuthenticationException() {
|
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
|
||||||
when(this.registeredClientRepository.findByClientId(eq(registeredClient.getClientId())))
|
|
||||||
.thenReturn(registeredClient);
|
|
||||||
OAuth2AuthorizationCodeRequestAuthenticationToken authentication =
|
|
||||||
new OAuth2AuthorizationCodeRequestAuthenticationToken(
|
|
||||||
AUTHORIZATION_URI, registeredClient.getClientId(), principal,
|
|
||||||
"https://localhost:5000", STATE, registeredClient.getScopes(), null);
|
|
||||||
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
|
|
||||||
.isInstanceOf(OAuth2AuthorizationCodeRequestAuthenticationException.class)
|
|
||||||
.satisfies(ex ->
|
|
||||||
assertAuthenticationException((OAuth2AuthorizationCodeRequestAuthenticationException) ex,
|
|
||||||
OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI, null)
|
|
||||||
)
|
|
||||||
.extracting(ex -> ((OAuth2AuthorizationCodeRequestAuthenticationException) ex).getError())
|
|
||||||
.satisfies(error ->
|
|
||||||
assertThat(error.getDescription()).isEqualTo("localhost is not allowed for the redirect_uri (https://localhost:5000). Use the IP literal (127.0.0.1) instead."));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void authenticateWhenUnregisteredRedirectUriThenThrowOAuth2AuthorizationCodeRequestAuthenticationException() {
|
public void authenticateWhenUnregisteredRedirectUriThenThrowOAuth2AuthorizationCodeRequestAuthenticationException() {
|
||||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
|
||||||
|
|||||||
Reference in New Issue
Block a user