Skip to content

Commit

Permalink
Merge branch '6.0.x'
Browse files Browse the repository at this point in the history
Closes gh-12800
  • Loading branch information
jzheaux committed Feb 28, 2023
2 parents aedabf5 + e28ea6d commit 41fadae
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 23 deletions.
33 changes: 32 additions & 1 deletion docs/modules/ROOT/pages/servlet/saml2/metadata.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
[[servlet-saml2login-metadata]]
= Producing `<saml2:SPSSODescriptor>` Metadata
= Saml 2.0 Metadata

Spring Security can <<parsing-asserting-party-metadata,parse asserting party metadata>> to produce an `AssertingPartyDetails` instance as well as <<publishing-relying-party-metadata,publish relying party metadata>> from a `RelyingPartyRegistration` instance.

[[parsing-asserting-party-metadata]]
== Parsing `<saml2:IDPSSODescriptor>` metadata

You can parse an asserting party's metadata xref:servlet/saml2/login/overview.adoc#servlet-saml2login-relyingpartyregistrationrepository[using `RelyingPartyRegistrations`].

When using the OpenSAML vendor support, the resulting `AssertingPartyDetails` will be of type `OpenSamlAssertingPartyDetails`.
This means you'll be able to do get the underlying OpenSAML XMLObject by doing the following:

====
.Java
[source,java,role="primary"]
----
OpenSamlAssertingPartyDetails details = (OpenSamlAssertingPartyDetails)
registration.getAssertingPartyDetails();
EntityDescriptor openSamlEntityDescriptor = details.getEntityDescriptor();
----
.Kotlin
[source,kotlin,role="secondary"]
----
val details: OpenSamlAssertingPartyDetails =
registration.getAssertingPartyDetails() as OpenSamlAssertingPartyDetails;
val openSamlEntityDescriptor: EntityDescriptor = details.getEntityDescriptor();
----
====

[[publishing-relying-party-metadata]]
== Producing `<saml2:SPSSODescriptor>` Metadata

You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain, as you'll see below:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2002-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.security.saml2.provider.service.registration;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;

class OpenSamlMetadataRelyingPartyRegistrationConverter {

private final OpenSamlMetadataAssertingPartyDetailsConverter converter = new OpenSamlMetadataAssertingPartyDetailsConverter();

Collection<RelyingPartyRegistration.Builder> convert(InputStream source) {
Collection<RelyingPartyRegistration.Builder> builders = new ArrayList<>();
for (RelyingPartyRegistration.AssertingPartyDetails.Builder builder : this.converter.convert(source)) {
builders.add(new RelyingPartyRegistration.Builder(builder));
}
return builders;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
Expand Down Expand Up @@ -89,8 +89,7 @@ public List<MediaType> getSupportedMediaTypes() {
@Override
public RelyingPartyRegistration.Builder read(Class<? extends RelyingPartyRegistration.Builder> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return RelyingPartyRegistration
.withAssertingPartyDetails(this.converter.convert(inputMessage.getBody()).iterator().next().build());
return new RelyingPartyRegistration.Builder(this.converter.convert(inputMessage.getBody()).iterator().next());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
Expand All @@ -26,6 +26,7 @@

import org.opensaml.xmlsec.signature.support.SignatureConstants;

import org.springframework.core.convert.converter.Converter;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
Expand Down Expand Up @@ -737,7 +738,7 @@ public AssertingPartyDetails build() {

public static final class Builder {

private String registrationId;
private Converter<AssertingPartyDetails, String> registrationId = AssertingPartyDetails::getEntityId;

private String entityId = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";

Expand All @@ -757,10 +758,15 @@ public static final class Builder {

private String nameIdFormat = null;

private AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
private AssertingPartyDetails.Builder assertingPartyDetailsBuilder;

private Builder(String registrationId) {
this.registrationId = registrationId;
this.registrationId = (party) -> registrationId;
this.assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
}

Builder(AssertingPartyDetails.Builder builder) {
this.assertingPartyDetailsBuilder = builder;
}

/**
Expand All @@ -769,7 +775,7 @@ private Builder(String registrationId) {
* @return this object
*/
public Builder registrationId(String id) {
this.registrationId = id;
this.registrationId = (party) -> id;
return this;
}

Expand Down Expand Up @@ -967,11 +973,12 @@ public RelyingPartyRegistration build() {
this.singleLogoutServiceBindings.add(Saml2MessageBinding.POST);
}

return new RelyingPartyRegistration(this.registrationId, this.entityId,
this.assertionConsumerServiceLocation, this.assertionConsumerServiceBinding,
this.singleLogoutServiceLocation, this.singleLogoutServiceResponseLocation,
this.singleLogoutServiceBindings, this.assertingPartyDetailsBuilder.build(), this.nameIdFormat,
this.decryptionX509Credentials, this.signingX509Credentials);
AssertingPartyDetails party = this.assertingPartyDetailsBuilder.build();
String registrationId = this.registrationId.convert(party);
return new RelyingPartyRegistration(registrationId, this.entityId, this.assertionConsumerServiceLocation,
this.assertionConsumerServiceBinding, this.singleLogoutServiceLocation,
this.singleLogoutServiceResponseLocation, this.singleLogoutServiceBindings, party,
this.nameIdFormat, this.decryptionX509Credentials, this.signingX509Credentials);
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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.
Expand All @@ -18,13 +18,11 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;

import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.security.saml2.Saml2Exception;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails;

/**
* A utility class for constructing instances of {@link RelyingPartyRegistration}
Expand All @@ -36,7 +34,7 @@
*/
public final class RelyingPartyRegistrations {

private static final OpenSamlMetadataAssertingPartyDetailsConverter assertingPartyMetadataConverter = new OpenSamlMetadataAssertingPartyDetailsConverter();
private static final OpenSamlMetadataRelyingPartyRegistrationConverter relyingPartyRegistrationConverter = new OpenSamlMetadataRelyingPartyRegistrationConverter();

private static final ResourceLoader resourceLoader = new DefaultResourceLoader();

Expand Down Expand Up @@ -215,11 +213,7 @@ public static Collection<RelyingPartyRegistration.Builder> collectionFromMetadat
* @since 5.7
*/
public static Collection<RelyingPartyRegistration.Builder> collectionFromMetadata(InputStream source) {
Collection<RelyingPartyRegistration.Builder> builders = new ArrayList<>();
for (AssertingPartyDetails.Builder builder : assertingPartyMetadataConverter.convert(source)) {
builders.add(RelyingPartyRegistration.withAssertingPartyDetails(builder.build()));
}
return builders;
return relyingPartyRegistrationConverter.convert(source);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2002-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.security.saml2.provider.service.registration;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.springframework.core.io.ClassPathResource;

import static org.assertj.core.api.Assertions.assertThat;

public class OpenSamlMetadataRelyingPartyRegistrationConverterTests {

private OpenSamlMetadataRelyingPartyRegistrationConverter converter = new OpenSamlMetadataRelyingPartyRegistrationConverter();

private String metadata;

@BeforeEach
public void setup() throws Exception {
ClassPathResource resource = new ClassPathResource("test-metadata.xml");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
this.metadata = reader.lines().collect(Collectors.joining());
}
}

// gh-12667
@Test
public void convertWhenDefaultsThenAssertingPartyInstanceOfOpenSaml() throws Exception {
try (InputStream source = new ByteArrayInputStream(this.metadata.getBytes(StandardCharsets.UTF_8))) {
this.converter.convert(source)
.forEach((registration) -> assertThat(registration.build().getAssertingPartyDetails())
.isInstanceOf(OpenSamlAssertingPartyDetails.class));
}
}

}

0 comments on commit 41fadae

Please sign in to comment.