Polish "Configure SAML 2.0 Service Provider via Metadata"

See gh-23045
pull/23173/head
Stephane Nicoll 4 years ago
parent 5187c01e39
commit 681abcc185

@ -141,7 +141,7 @@ public class Saml2RelyingPartyProperties {
private String entityId; private String entityId;
/** /**
* Endpoint for discovery-based configuration. * URI to the metadata endpoint for discovery-based configuration.
*/ */
private String metadataUri; private String metadataUri;

@ -22,6 +22,7 @@ import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPrivateKey;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -37,6 +38,8 @@ import org.springframework.security.converter.RsaKeyConverters;
import org.springframework.security.saml2.core.Saml2X509Credential; import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.Builder;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter; import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
@ -67,26 +70,13 @@ class Saml2RelyingPartyRegistrationConfiguration {
} }
private RelyingPartyRegistration asRegistration(String id, Registration properties) { private RelyingPartyRegistration asRegistration(String id, Registration properties) {
RelyingPartyRegistration.Builder builder;
boolean usingMetadata = StringUtils.hasText(properties.getIdentityprovider().getMetadataUri()); boolean usingMetadata = StringUtils.hasText(properties.getIdentityprovider().getMetadataUri());
if (usingMetadata) { Builder builder = (usingMetadata) ? RelyingPartyRegistrations
builder = RelyingPartyRegistrations.fromMetadataLocation(properties.getIdentityprovider().getMetadataUri()) .fromMetadataLocation(properties.getIdentityprovider().getMetadataUri()).registrationId(id)
.registrationId(id); : RelyingPartyRegistration.withRegistrationId(id);
}
else {
builder = RelyingPartyRegistration.withRegistrationId(id);
}
builder.assertionConsumerServiceLocation( builder.assertionConsumerServiceLocation(
"{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI); "{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI);
Saml2RelyingPartyProperties.Identityprovider identityprovider = properties.getIdentityprovider(); builder.assertingPartyDetails(mapIdentityProvider(properties, usingMetadata));
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
builder.assertingPartyDetails((details) -> {
map.from(identityprovider::getEntityId).to(details::entityId);
map.from(identityprovider.getSinglesignon()::getBinding).to(details::singleSignOnServiceBinding);
map.from(identityprovider.getSinglesignon()::getUrl).to(details::singleSignOnServiceLocation);
map.from(identityprovider.getSinglesignon()::isSignRequest).when((signRequest) -> !usingMetadata)
.to(details::wantAuthnRequestsSigned);
});
builder.signingX509Credentials((credentials) -> properties.getSigning().getCredentials().stream() builder.signingX509Credentials((credentials) -> properties.getSigning().getCredentials().stream()
.map(this::asSigningCredential).forEach(credentials::add)); .map(this::asSigningCredential).forEach(credentials::add));
builder.assertingPartyDetails((details) -> details builder.assertingPartyDetails((details) -> details
@ -99,6 +89,19 @@ class Saml2RelyingPartyRegistrationConfiguration {
return registration; return registration;
} }
private Consumer<AssertingPartyDetails.Builder> mapIdentityProvider(Registration properties,
boolean usingMetadata) {
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
Saml2RelyingPartyProperties.Identityprovider identityprovider = properties.getIdentityprovider();
return (details) -> {
map.from(identityprovider::getEntityId).to(details::entityId);
map.from(identityprovider.getSinglesignon()::getBinding).to(details::singleSignOnServiceBinding);
map.from(identityprovider.getSinglesignon()::getUrl).to(details::singleSignOnServiceLocation);
map.from(identityprovider.getSinglesignon()::isSignRequest).when((signRequest) -> !usingMetadata)
.to(details::wantAuthnRequestsSigned);
};
}
private void validateSigningCredentials(Registration properties, boolean signRequest) { private void validateSigningCredentials(Registration properties, boolean signRequest) {
if (signRequest) { if (signRequest) {
Assert.state(!properties.getSigning().getCredentials().isEmpty(), Assert.state(!properties.getSigning().getCredentials().isEmpty(),

@ -35,6 +35,7 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.config.BeanIds; import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@ -122,7 +123,7 @@ class Saml2RelyingPartyAutoConfigurationTests {
try (MockWebServer server = new MockWebServer()) { try (MockWebServer server = new MockWebServer()) {
server.start(); server.start();
String metadataUrl = server.url("").toString(); String metadataUrl = server.url("").toString();
setupMockResponse(server); setupMockResponse(server, new ClassPathResource("saml/idp-metadata"));
this.contextRunner.withPropertyValues(PREFIX + ".foo.identityprovider.metadata-uri=" + metadataUrl) this.contextRunner.withPropertyValues(PREFIX + ".foo.identityprovider.metadata-uri=" + metadataUrl)
.run((context) -> { .run((context) -> {
assertThat(context).hasSingleBean(RelyingPartyRegistrationRepository.class); assertThat(context).hasSingleBean(RelyingPartyRegistrationRepository.class);
@ -195,8 +196,8 @@ class Saml2RelyingPartyAutoConfigurationTests {
return filters.stream().anyMatch(filter::isInstance); return filters.stream().anyMatch(filter::isInstance);
} }
private void setupMockResponse(MockWebServer server) throws Exception { private void setupMockResponse(MockWebServer server, Resource resourceBody) throws Exception {
try (InputStream metadataSource = new ClassPathResource("saml/idp-metadata").getInputStream()) { try (InputStream metadataSource = resourceBody.getInputStream()) {
Buffer metadataBuffer = new Buffer().readFrom(metadataSource); Buffer metadataBuffer = new Buffer().readFrom(metadataSource);
MockResponse metadataResponse = new MockResponse().setBody(metadataBuffer); MockResponse metadataResponse = new MockResponse().setBody(metadataBuffer);
server.enqueue(metadataResponse); server.enqueue(metadataResponse);

@ -103,7 +103,7 @@ class Saml2RelyingPartyPropertiesTests {
} }
@Test @Test
void customizeIdentityProviderMetadataUrl() { void customizeIdentityProviderMetadataUri() {
bind("spring.security.saml2.relyingparty.registration.simplesamlphp.identityprovider.metadata-uri", bind("spring.security.saml2.relyingparty.registration.simplesamlphp.identityprovider.metadata-uri",
"https://idp.example.org/metadata"); "https://idp.example.org/metadata");
assertThat(this.properties.getRegistration().get("simplesamlphp").getIdentityprovider().getMetadataUri()) assertThat(this.properties.getRegistration().get("simplesamlphp").getIdentityprovider().getMetadataUri())

@ -39,4 +39,4 @@
<md:ContactPerson contactType="technical"> <md:ContactPerson contactType="technical">
<md:EmailAddress>mailto:technical.contact@example.com</md:EmailAddress> <md:EmailAddress>mailto:technical.contact@example.com</md:EmailAddress>
</md:ContactPerson> </md:ContactPerson>
</md:EntityDescriptor> </md:EntityDescriptor>

Loading…
Cancel
Save