diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java index 2053bc1cb5..886ad9a5ac 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java @@ -88,9 +88,14 @@ class Saml2RelyingPartyRegistrationConfiguration { private RelyingPartyRegistration asRegistration(String id, Registration properties) { AssertingPartyProperties assertingParty = new AssertingPartyProperties(properties, id); boolean usingMetadata = StringUtils.hasText(assertingParty.getMetadataUri()); - Builder builder = (usingMetadata) - ? RelyingPartyRegistrations.fromMetadataLocation(assertingParty.getMetadataUri()).registrationId(id) - : RelyingPartyRegistration.withRegistrationId(id); + Builder builder = (usingMetadata) ? RelyingPartyRegistrations + .collectionFromMetadataLocation(properties.getAssertingparty().getMetadataUri()) + .stream() + .filter(b -> entityIdsMatch(properties, b)) + .findFirst() + .orElseThrow(() -> new IllegalStateException( + "No relying party with entity-id " + properties.getEntityId() + " found.")) + .registrationId(id) : RelyingPartyRegistration.withRegistrationId(id); builder.assertionConsumerServiceLocation(properties.getAcs().getLocation()); builder.assertionConsumerServiceBinding(properties.getAcs().getBinding()); builder.assertingPartyDetails(mapAssertingParty(properties, id, usingMetadata)); @@ -119,6 +124,19 @@ class Saml2RelyingPartyRegistrationConfiguration { return registration; } + /** + * Tests if the builder would have the correct entity-id. If no entity-id is given in + * properties, any builder passes the test. + * @param properties the properties + * @param b the builder + * @return true if the builder passes the test + */ + private boolean entityIdsMatch(Registration properties, Builder b) { + RelyingPartyRegistration rpr = b.build(); + return properties.getAssertingparty().getEntityId() == null + || properties.getAssertingparty().getEntityId().equals(rpr.getAssertingPartyDetails().getEntityId()); + } + private Consumer mapAssertingParty(Registration registration, String id, boolean usingMetadata) { return (details) -> { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java index 32ad6d0d23..37d407d3ed 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java @@ -402,6 +402,43 @@ class Saml2RelyingPartyAutoConfigurationTests { this.contextRunner.withPropertyValues(getPropertyValues(false)) .run((context) -> assertThat(hasFilter(context, Saml2LogoutRequestFilter.class)).isTrue()); } + + @Test + void autoconfigurationShouldWorkWithMultipleProvidersWithNoEntityId() throws Exception { + try (MockWebServer server = new MockWebServer()) { + server.start(); + String metadataUrl = server.url("").toString(); + setupMockResponse(server, new ClassPathResource("saml/idp-metadata-with-multiple-providers")); + this.contextRunner.withPropertyValues(PREFIX + ".foo.assertingparty.metadata-uri=" + metadataUrl) + .run((context) -> { + assertThat(context).hasSingleBean(RelyingPartyRegistrationRepository.class); + assertThat(server.getRequestCount()).isOne(); + RelyingPartyRegistrationRepository repository = context.getBean(RelyingPartyRegistrationRepository.class); + RelyingPartyRegistration registration = repository.findByRegistrationId("foo"); + assertThat(registration.getAssertingPartyDetails().getEntityId()) + .isEqualTo("https://idp.example.com/idp/shibboleth"); + }); + } + } + + @Test + void autoconfigurationShouldWorkWithMultipleProviders() throws Exception { + try (MockWebServer server = new MockWebServer()) { + server.start(); + String metadataUrl = server.url("").toString(); + setupMockResponse(server, new ClassPathResource("saml/idp-metadata-with-multiple-providers")); + this.contextRunner.withPropertyValues(PREFIX + ".foo.assertingparty.metadata-uri=" + metadataUrl, + PREFIX + ".foo.assertingparty.entity-id=https://idp2.example.com/idp/shibboleth") + .run((context) -> { + assertThat(context).hasSingleBean(RelyingPartyRegistrationRepository.class); + assertThat(server.getRequestCount()).isOne(); + RelyingPartyRegistrationRepository repository = context.getBean(RelyingPartyRegistrationRepository.class); + RelyingPartyRegistration registration = repository.findByRegistrationId("foo"); + assertThat(registration.getAssertingPartyDetails().getEntityId()) + .isEqualTo("https://idp2.example.com/idp/shibboleth"); + }); + } + } private String[] getPropertyValuesWithoutSigningCredentials(boolean signRequests, boolean useDeprecated) { String assertingParty = useDeprecated ? "identityprovider" : "assertingparty"; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/saml/idp-metadata-with-multiple-providers b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/saml/idp-metadata-with-multiple-providers new file mode 100644 index 0000000000..af40448589 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/saml/idp-metadata-with-multiple-providers @@ -0,0 +1,86 @@ + + + + + + + + MIIDZjCCAk6gAwIBAgIVAL9O+PA7SXtlwZZY8MVSE9On1cVWMA0GCSqGSIb3DQEB + BQUAMCkxJzAlBgNVBAMTHmlkZW0tcHVwYWdlbnQuZG16LWludC51bmltby5pdDAe + Fw0xMzA3MjQwMDQ0MTRaFw0zMzA3MjQwMDQ0MTRaMCkxJzAlBgNVBAMTHmlkZW0t + cHVwYWdlbnQuZG16LWludC51bmltby5pdDCCASIwDQYJKoZIhvcNAMIIDQADggEP + ADCCAQoCggEBAIAcp/VyzZGXUF99kwj4NvL/Rwv4YvBgLWzpCuoxqHZ/hmBwJtqS + v0y9METBPFbgsF3hCISnxbcmNVxf/D0MoeKtw1YPbsUmow/bFe+r72hZ+IVAcejN + iDJ7t5oTjsRN1t1SqvVVk6Ryk5AZhpFW+W9pE9N6c7kJ16Rp2/mbtax9OCzxpece + byi1eiLfIBmkcRawL/vCc2v6VLI18i6HsNVO3l2yGosKCbuSoGDx2fCdAOk/rgdz + cWOvFsIZSKuD+FVbSS/J9GVs7yotsS4PRl4iX9UMnfDnOMfO7bcBgbXtDl4SCU1v + dJrRw7IL/pLz34Rv9a8nYitrzrxtLOp3nYUCAwEAAaOBhDCBgTBgBgMIIDEEWTBX + gh5pZGVtLXB1cGFnZW50LmRtei1pbnQudW5pbW8uaXSGNWh0dHBzOi8vaWRlbS1w + dXBhZ2VudC5kbXotaW50LnVuaW1vLml0L2lkcC9zaGliYm9sZXRoMB0GA1UdDgQW + BBT8PANzz+adGnTRe8ldcyxAwe4VnzANBgkqhkiG9w0BAQUFAAOCAQEAOEnO8Clu + 9z/Lf/8XOOsTdxJbV29DIF3G8KoQsB3dBsLwPZVEAQIP6ceS32Xaxrl6FMTDDNkL + qUvvInUisw0+I5zZwYHybJQCletUWTnz58SC4C9G7FpuXHFZnOGtRcgGD1NOX4UU + duus/4nVcGSLhDjszZ70Xtj0gw2Sn46oQPHTJ81QZ3Y9ih+Aj1c9OtUSBwtWZFkU + yooAKoR8li68Yb21zN2N65AqV+ndL98M8xUYMKLONuAXStDeoVCipH6PJ09Z5U2p + V5p4IQRV6QBsNw9CISJFuHzkVYTH5ZxzN80Ru46vh4y2M0Nu8GQ9I085KoZkrf5e + Cq53OZt9ISjHEw== + + + + + + + + mailto:technical.contact@example.com + + + + + + + + + MIIDZjCCAk6gAwIBAgIVAL9O+PA7SXtlwZZY8MVSE9On1cVWMA0GCSqGSIb3DQEB + BQUAMCkxJzAlBgNVBAMTHmlkZW0tcHVwYWdlbnQuZG16LWludC51bmltby5pdDAe + Fw0xMzA3MjQwMDQ0MTRaFw0zMzA3MjQwMDQ0MTRaMCkxJzAlBgNVBAMTHmlkZW0t + cHVwYWdlbnQuZG16LWludC51bmltby5pdDCCASIwDQYJKoZIhvcNAMIIDQADggEP + ADCCAQoCggEBAIAcp/VyzZGXUF99kwj4NvL/Rwv4YvBgLWzpCuoxqHZ/hmBwJtqS + v0y9METBPFbgsF3hCISnxbcmNVxf/D0MoeKtw1YPbsUmow/bFe+r72hZ+IVAcejN + iDJ7t5oTjsRN1t1SqvVVk6Ryk5AZhpFW+W9pE9N6c7kJ16Rp2/mbtax9OCzxpece + byi1eiLfIBmkcRawL/vCc2v6VLI18i6HsNVO3l2yGosKCbuSoGDx2fCdAOk/rgdz + cWOvFsIZSKuD+FVbSS/J9GVs7yotsS4PRl4iX9UMnfDnOMfO7bcBgbXtDl4SCU1v + dJrRw7IL/pLz34Rv9a8nYitrzrxtLOp3nYUCAwEAAaOBhDCBgTBgBgMIIDEEWTBX + gh5pZGVtLXB1cGFnZW50LmRtei1pbnQudW5pbW8uaXSGNWh0dHBzOi8vaWRlbS1w + dXBhZ2VudC5kbXotaW50LnVuaW1vLml0L2lkcC9zaGliYm9sZXRoMB0GA1UdDgQW + BBT8PANzz+adGnTRe8ldcyxAwe4VnzANBgkqhkiG9w0BAQUFAAOCAQEAOEnO8Clu + 9z/Lf/8XOOsTdxJbV29DIF3G8KoQsB3dBsLwPZVEAQIP6ceS32Xaxrl6FMTDDNkL + qUvvInUisw0+I5zZwYHybJQCletUWTnz58SC4C9G7FpuXHFZnOGtRcgGD1NOX4UU + duus/4nVcGSLhDjszZ70Xtj0gw2Sn46oQPHTJ81QZ3Y9ih+Aj1c9OtUSBwtWZFkU + yooAKoR8li68Yb21zN2N65AqV+ndL98M8xUYMKLONuAXStDeoVCipH6PJ09Z5U2p + V5p4IQRV6QBsNw9CISJFuHzkVYTH5ZxzN80Ru46vh4y2M0Nu8GQ9I085KoZkrf5e + Cq53OZt9ISjHEw== + + + + + + + + mailto:technical.contact2@example.com + + + \ No newline at end of file