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 7fb2b889f7..1f698416d0 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 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. @@ -17,6 +17,7 @@ package org.springframework.security.oauth2.client.registration; import java.net.URI; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -49,6 +50,7 @@ import org.springframework.web.util.UriComponentsBuilder; * @author Rob Winch * @author Josh Cummings * @author Rafiullah Hamedy + * @author Evgeniy Cheban * @since 5.1 */ public final class ClientRegistrations { @@ -211,6 +213,7 @@ public final class ClientRegistrations { private static ClientRegistration.Builder getBuilder(String issuer, Supplier... suppliers) { String errorMessage = "Unable to resolve Configuration with the provided Issuer of \"" + issuer + "\""; + List errors = new ArrayList<>(); for (Supplier supplier : suppliers) { try { return supplier.get(); @@ -219,6 +222,7 @@ public final class ClientRegistrations { if (!ex.getStatusCode().is4xxClientError()) { throw ex; } + errors.add(ex.getMessage()); // else try another endpoint } catch (IllegalArgumentException | IllegalStateException ex) { @@ -228,6 +232,9 @@ public final class ClientRegistrations { throw new IllegalArgumentException(errorMessage, ex); } } + if (!errors.isEmpty()) { + throw new IllegalArgumentException(errorMessage + ", errors: " + errors); + } throw new IllegalArgumentException(errorMessage); } diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java index b3b74e805d..62954a2599 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/ClientRegistrationsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2025 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. @@ -36,12 +36,14 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; /** * @author Rob Winch * @author Rafiullah Hamedy + * @author Evgeniy Cheban * @since 5.1 */ public class ClientRegistrationsTests { @@ -455,6 +457,31 @@ public class ClientRegistrationsTests { // @formatter:on } + @Test + public void issuerWhenAllEndpointsFailedThenExceptionIncludesFailureInformation() { + this.issuer = createIssuerFromServer("issuer1"); + this.server.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest request) { + int responseCode = switch (request.getPath()) { + case "/issuer1/.well-known/openid-configuration" -> 405; + case "/.well-known/openid-configuration/issuer1" -> 400; + default -> 404; + }; + return new MockResponse().setResponseCode(responseCode); + } + }); + String message = """ + Unable to resolve Configuration with the provided Issuer of "%s", errors: [\ + 405 Client Error: [no body], \ + 400 Client Error: [no body], \ + 404 Client Error: [no body]]\ + """.formatted(this.issuer); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> ClientRegistrations.fromIssuerLocation(this.issuer).build()) + .withMessage(message); + } + private ClientRegistration.Builder registration(String path) throws Exception { this.issuer = createIssuerFromServer(path); this.response.put("issuer", this.issuer);