diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java index 91517d640a..d9ae09f329 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java @@ -37,6 +37,7 @@ import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; import org.springframework.util.Assert; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; /** @@ -211,13 +212,18 @@ public final class ClientRegistrations { }; } - private static Supplier oidcRfc8414(URI issuer) { + private static Supplier oidcRfc8414(String issuer) { + URI uri = oidcRfc8414Uri(issuer); + return getRfc8414Builder(issuer, uri); + } + + static URI oidcRfc8414Uri(String issuer) { + UriComponents uri = UriComponentsBuilder.fromUriString(issuer).build(); // @formatter:off - URI uri = UriComponentsBuilder.fromUri(issuer) - .replacePath(OIDC_METADATA_PATH + issuer.getPath()) + return UriComponentsBuilder.newInstance().uriComponents(uri) + .replacePath(OIDC_METADATA_PATH + uri.getPath()) .build(Collections.emptyMap()); // @formatter:on - return getRfc8414Builder(issuer, uri); } private static Supplier oauth(URI issuer) { diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtils.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtils.java index cfe0d0e538..d901743e37 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtils.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtils.java @@ -16,8 +16,6 @@ package org.springframework.security.oauth2.jwt; -import java.net.URI; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -83,13 +81,11 @@ final class JwtDecoderProviderConfigurationUtils { } static Map getConfigurationForOidcIssuerLocation(String oidcIssuerLocation) { - UriComponents uri = UriComponentsBuilder.fromUriString(oidcIssuerLocation).build(); - return getConfiguration(oidcIssuerLocation, rest, oidc(uri)); + return getConfiguration(oidcIssuerLocation, rest, oidc(oidcIssuerLocation)); } static Map getConfigurationForIssuerLocation(String issuer, RestOperations rest) { - UriComponents uri = UriComponentsBuilder.fromUriString(issuer).build(); - return getConfiguration(issuer, rest, oidc(uri), oidcRfc8414(uri), oauth(uri)); + return getConfiguration(issuer, rest, oidc(issuer), oidcRfc8414(issuer), oauth(issuer)); } static Map getConfigurationForIssuerLocation(String issuer) { @@ -161,11 +157,11 @@ final class JwtDecoderProviderConfigurationUtils { return "(unavailable)"; } - private static Map getConfiguration(String issuer, RestOperations rest, URI... uris) { + private static Map getConfiguration(String issuer, RestOperations rest, UriComponents... uris) { String errorMessage = "Unable to resolve the Configuration with the provided Issuer of " + "\"" + issuer + "\""; - for (URI uri : uris) { + for (UriComponents uri : uris) { try { - RequestEntity request = RequestEntity.get(uri).build(); + RequestEntity request = RequestEntity.get(uri.toUriString()).build(); ResponseEntity> response = rest.exchange(request, STRING_OBJECT_MAP); Map configuration = response.getBody(); Assert.isTrue(configuration.get("jwks_uri") != null, "The public JWK set URI must not be null"); @@ -185,27 +181,30 @@ final class JwtDecoderProviderConfigurationUtils { throw new IllegalArgumentException(errorMessage); } - private static URI oidc(UriComponents issuer) { + static UriComponents oidc(String issuer) { + UriComponents uri = UriComponentsBuilder.fromUriString(issuer).build(); // @formatter:off - return UriComponentsBuilder.newInstance().uriComponents(issuer) - .replacePath(issuer.getPath() + OIDC_METADATA_PATH) - .build(Collections.emptyMap()); + return UriComponentsBuilder.newInstance().uriComponents(uri) + .replacePath(uri.getPath() + OIDC_METADATA_PATH) + .build(); // @formatter:on } - private static URI oidcRfc8414(UriComponents issuer) { + static UriComponents oidcRfc8414(String issuer) { + UriComponents uri = UriComponentsBuilder.fromUriString(issuer).build(); // @formatter:off - return UriComponentsBuilder.newInstance().uriComponents(issuer) - .replacePath(OIDC_METADATA_PATH + issuer.getPath()) - .build(Collections.emptyMap()); + return UriComponentsBuilder.newInstance().uriComponents(uri) + .replacePath(OIDC_METADATA_PATH + uri.getPath()) + .build(); // @formatter:on } - private static URI oauth(UriComponents issuer) { + static UriComponents oauth(String issuer) { + UriComponents uri = UriComponentsBuilder.fromUriString(issuer).build(); // @formatter:off - return UriComponentsBuilder.newInstance().uriComponents(issuer) - .replacePath(OAUTH_METADATA_PATH + issuer.getPath()) - .build(Collections.emptyMap()); + return UriComponentsBuilder.newInstance().uriComponents(uri) + .replacePath(OAUTH_METADATA_PATH + uri.getPath()) + .build(); // @formatter:on } diff --git a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecoderProviderConfigurationUtils.java b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecoderProviderConfigurationUtils.java index bda44358a3..d9506d900d 100644 --- a/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecoderProviderConfigurationUtils.java +++ b/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecoderProviderConfigurationUtils.java @@ -16,8 +16,6 @@ package org.springframework.security.oauth2.jwt; -import java.net.URI; -import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -94,38 +92,40 @@ final class ReactiveJwtDecoderProviderConfigurationUtils { } static Mono> getConfigurationForIssuerLocation(String issuer, WebClient web) { - UriComponents uri = UriComponentsBuilder.fromUriString(issuer).build(); - return getConfiguration(issuer, web, oidc(uri), oidcRfc8414(uri), oauth(uri)); + return getConfiguration(issuer, web, oidc(issuer), oidcRfc8414(issuer), oauth(issuer)); } - private static URI oidc(UriComponents issuer) { + static UriComponents oidc(String issuer) { + UriComponents uri = UriComponentsBuilder.fromUriString(issuer).build(); // @formatter:off - return UriComponentsBuilder.newInstance().uriComponents(issuer) - .replacePath(issuer.getPath() + OIDC_METADATA_PATH) - .build(Collections.emptyMap()); + return UriComponentsBuilder.newInstance().uriComponents(uri) + .replacePath(uri.getPath() + OIDC_METADATA_PATH) + .build(); // @formatter:on } - private static URI oidcRfc8414(UriComponents issuer) { + static UriComponents oidcRfc8414(String issuer) { + UriComponents uri = UriComponentsBuilder.fromUriString(issuer).build(); // @formatter:off - return UriComponentsBuilder.newInstance().uriComponents(issuer) - .replacePath(OIDC_METADATA_PATH + issuer.getPath()) - .build(Collections.emptyMap()); + return UriComponentsBuilder.newInstance().uriComponents(uri) + .replacePath(OIDC_METADATA_PATH + uri.getPath()) + .build(); // @formatter:on } - private static URI oauth(UriComponents issuer) { + static UriComponents oauth(String issuer) { + UriComponents uri = UriComponentsBuilder.fromUriString(issuer).build(); // @formatter:off - return UriComponentsBuilder.newInstance().uriComponents(issuer) - .replacePath(OAUTH_METADATA_PATH + issuer.getPath()) - .build(Collections.emptyMap()); + return UriComponentsBuilder.newInstance().uriComponents(uri) + .replacePath(OAUTH_METADATA_PATH + uri.getPath()) + .build(); // @formatter:on } - private static Mono> getConfiguration(String issuer, WebClient web, URI... uris) { + private static Mono> getConfiguration(String issuer, WebClient web, UriComponents... uris) { String errorMessage = "Unable to resolve the Configuration with the provided Issuer of " + "\"" + issuer + "\""; return Flux.just(uris) - .concatMap((uri) -> web.get().uri(uri).retrieve().bodyToMono(STRING_OBJECT_MAP)) + .concatMap((uri) -> web.get().uri(uri.toUriString()).retrieve().bodyToMono(STRING_OBJECT_MAP)) .flatMap((configuration) -> { if (configuration.get("jwks_uri") == null) { return Mono.error(() -> new IllegalArgumentException("The public JWK set URI must not be null")); diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtilsTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtilsTests.java index 1b88d6f3f3..ec87e7a1de 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtilsTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/JwtDecoderProviderConfigurationUtilsTests.java @@ -35,6 +35,7 @@ import org.junit.jupiter.api.Test; import org.springframework.security.oauth2.jose.TestKeys; import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; +import org.springframework.web.util.UriComponents; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -90,4 +91,16 @@ public class JwtDecoderProviderConfigurationUtilsTests { assertThat(algorithms).containsOnly(SignatureAlgorithm.RS256); } + // gh-15852 + @Test + public void oidcWhenHostContainsUnderscoreThenRetains() { + UriComponents oidc = JwtDecoderProviderConfigurationUtils.oidc("https://elated_sutherland:8080/path"); + assertThat(oidc.getHost()).isEqualTo("elated_sutherland"); + UriComponents oauth = JwtDecoderProviderConfigurationUtils.oauth("https://elated_sutherland:8080/path"); + assertThat(oauth.getHost()).isEqualTo("elated_sutherland"); + UriComponents oidcRfc8414 = JwtDecoderProviderConfigurationUtils + .oidcRfc8414("https://elated_sutherland:8080/path"); + assertThat(oidcRfc8414.getHost()).isEqualTo("elated_sutherland"); + } + } diff --git a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecoderProviderConfigurationUtilsTests.java b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecoderProviderConfigurationUtilsTests.java index 30a0affd14..12ccd7c46f 100644 --- a/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecoderProviderConfigurationUtilsTests.java +++ b/oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecoderProviderConfigurationUtilsTests.java @@ -37,6 +37,7 @@ import org.junit.jupiter.api.Test; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import static org.assertj.core.api.Assertions.assertThat; @@ -227,6 +228,18 @@ public class ReactiveJwtDecoderProviderConfigurationUtilsTests { // @formatter:on } + // gh-15852 + @Test + public void oidcWhenHostContainsUnderscoreThenRetains() { + UriComponents oidc = ReactiveJwtDecoderProviderConfigurationUtils.oidc("https://elated_sutherland:8080/path"); + assertThat(oidc.getHost()).isEqualTo("elated_sutherland"); + UriComponents oauth = ReactiveJwtDecoderProviderConfigurationUtils.oauth("https://elated_sutherland:8080/path"); + assertThat(oauth.getHost()).isEqualTo("elated_sutherland"); + UriComponents oidcRfc8414 = ReactiveJwtDecoderProviderConfigurationUtils + .oidcRfc8414("https://elated_sutherland:8080/path"); + assertThat(oidcRfc8414.getHost()).isEqualTo("elated_sutherland"); + } + private void prepareConfigurationResponse() { String body = String.format(DEFAULT_RESPONSE_TEMPLATE, this.issuer, this.issuer); prepareConfigurationResponse(body);