Skip to content

Commit 41fadae

Browse files
committed
Merge branch '6.0.x'
Closes gh-12800
2 parents aedabf5 + e28ea6d commit 41fadae

File tree

6 files changed

+146
-23
lines changed

6 files changed

+146
-23
lines changed

docs/modules/ROOT/pages/servlet/saml2/metadata.adoc

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
[[servlet-saml2login-metadata]]
2-
= Producing `<saml2:SPSSODescriptor>` Metadata
2+
= Saml 2.0 Metadata
3+
4+
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.
5+
6+
[[parsing-asserting-party-metadata]]
7+
== Parsing `<saml2:IDPSSODescriptor>` metadata
8+
9+
You can parse an asserting party's metadata xref:servlet/saml2/login/overview.adoc#servlet-saml2login-relyingpartyregistrationrepository[using `RelyingPartyRegistrations`].
10+
11+
When using the OpenSAML vendor support, the resulting `AssertingPartyDetails` will be of type `OpenSamlAssertingPartyDetails`.
12+
This means you'll be able to do get the underlying OpenSAML XMLObject by doing the following:
13+
14+
====
15+
.Java
16+
[source,java,role="primary"]
17+
----
18+
OpenSamlAssertingPartyDetails details = (OpenSamlAssertingPartyDetails)
19+
registration.getAssertingPartyDetails();
20+
EntityDescriptor openSamlEntityDescriptor = details.getEntityDescriptor();
21+
----
22+
23+
.Kotlin
24+
[source,kotlin,role="secondary"]
25+
----
26+
val details: OpenSamlAssertingPartyDetails =
27+
registration.getAssertingPartyDetails() as OpenSamlAssertingPartyDetails;
28+
val openSamlEntityDescriptor: EntityDescriptor = details.getEntityDescriptor();
29+
----
30+
====
31+
32+
[[publishing-relying-party-metadata]]
33+
== Producing `<saml2:SPSSODescriptor>` Metadata
334

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

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.saml2.provider.service.registration;
18+
19+
import java.io.InputStream;
20+
import java.util.ArrayList;
21+
import java.util.Collection;
22+
23+
class OpenSamlMetadataRelyingPartyRegistrationConverter {
24+
25+
private final OpenSamlMetadataAssertingPartyDetailsConverter converter = new OpenSamlMetadataAssertingPartyDetailsConverter();
26+
27+
Collection<RelyingPartyRegistration.Builder> convert(InputStream source) {
28+
Collection<RelyingPartyRegistration.Builder> builders = new ArrayList<>();
29+
for (RelyingPartyRegistration.AssertingPartyDetails.Builder builder : this.converter.convert(source)) {
30+
builders.add(new RelyingPartyRegistration.Builder(builder));
31+
}
32+
return builders;
33+
}
34+
35+
}

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -89,8 +89,7 @@ public List<MediaType> getSupportedMediaTypes() {
8989
@Override
9090
public RelyingPartyRegistration.Builder read(Class<? extends RelyingPartyRegistration.Builder> clazz,
9191
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
92-
return RelyingPartyRegistration
93-
.withAssertingPartyDetails(this.converter.convert(inputMessage.getBody()).iterator().next().build());
92+
return new RelyingPartyRegistration.Builder(this.converter.convert(inputMessage.getBody()).iterator().next());
9493
}
9594

9695
@Override

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistration.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
2626

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

29+
import org.springframework.core.convert.converter.Converter;
2930
import org.springframework.security.saml2.core.Saml2X509Credential;
3031
import org.springframework.util.Assert;
3132
import org.springframework.util.CollectionUtils;
@@ -737,7 +738,7 @@ public AssertingPartyDetails build() {
737738

738739
public static final class Builder {
739740

740-
private String registrationId;
741+
private Converter<AssertingPartyDetails, String> registrationId = AssertingPartyDetails::getEntityId;
741742

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

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

758759
private String nameIdFormat = null;
759760

760-
private AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
761+
private AssertingPartyDetails.Builder assertingPartyDetailsBuilder;
761762

762763
private Builder(String registrationId) {
763-
this.registrationId = registrationId;
764+
this.registrationId = (party) -> registrationId;
765+
this.assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
766+
}
767+
768+
Builder(AssertingPartyDetails.Builder builder) {
769+
this.assertingPartyDetailsBuilder = builder;
764770
}
765771

766772
/**
@@ -769,7 +775,7 @@ private Builder(String registrationId) {
769775
* @return this object
770776
*/
771777
public Builder registrationId(String id) {
772-
this.registrationId = id;
778+
this.registrationId = (party) -> id;
773779
return this;
774780
}
775781

@@ -967,11 +973,12 @@ public RelyingPartyRegistration build() {
967973
this.singleLogoutServiceBindings.add(Saml2MessageBinding.POST);
968974
}
969975

970-
return new RelyingPartyRegistration(this.registrationId, this.entityId,
971-
this.assertionConsumerServiceLocation, this.assertionConsumerServiceBinding,
972-
this.singleLogoutServiceLocation, this.singleLogoutServiceResponseLocation,
973-
this.singleLogoutServiceBindings, this.assertingPartyDetailsBuilder.build(), this.nameIdFormat,
974-
this.decryptionX509Credentials, this.signingX509Credentials);
976+
AssertingPartyDetails party = this.assertingPartyDetailsBuilder.build();
977+
String registrationId = this.registrationId.convert(party);
978+
return new RelyingPartyRegistration(registrationId, this.entityId, this.assertionConsumerServiceLocation,
979+
this.assertionConsumerServiceBinding, this.singleLogoutServiceLocation,
980+
this.singleLogoutServiceResponseLocation, this.singleLogoutServiceBindings, party,
981+
this.nameIdFormat, this.decryptionX509Credentials, this.signingX509Credentials);
975982
}
976983

977984
}

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/registration/RelyingPartyRegistrations.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,13 +18,11 @@
1818

1919
import java.io.IOException;
2020
import java.io.InputStream;
21-
import java.util.ArrayList;
2221
import java.util.Collection;
2322

2423
import org.springframework.core.io.DefaultResourceLoader;
2524
import org.springframework.core.io.ResourceLoader;
2625
import org.springframework.security.saml2.Saml2Exception;
27-
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails;
2826

2927
/**
3028
* A utility class for constructing instances of {@link RelyingPartyRegistration}
@@ -36,7 +34,7 @@
3634
*/
3735
public final class RelyingPartyRegistrations {
3836

39-
private static final OpenSamlMetadataAssertingPartyDetailsConverter assertingPartyMetadataConverter = new OpenSamlMetadataAssertingPartyDetailsConverter();
37+
private static final OpenSamlMetadataRelyingPartyRegistrationConverter relyingPartyRegistrationConverter = new OpenSamlMetadataRelyingPartyRegistrationConverter();
4038

4139
private static final ResourceLoader resourceLoader = new DefaultResourceLoader();
4240

@@ -215,11 +213,7 @@ public static Collection<RelyingPartyRegistration.Builder> collectionFromMetadat
215213
* @since 5.7
216214
*/
217215
public static Collection<RelyingPartyRegistration.Builder> collectionFromMetadata(InputStream source) {
218-
Collection<RelyingPartyRegistration.Builder> builders = new ArrayList<>();
219-
for (AssertingPartyDetails.Builder builder : assertingPartyMetadataConverter.convert(source)) {
220-
builders.add(RelyingPartyRegistration.withAssertingPartyDetails(builder.build()));
221-
}
222-
return builders;
216+
return relyingPartyRegistrationConverter.convert(source);
223217
}
224218

225219
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.saml2.provider.service.registration;
18+
19+
import java.io.BufferedReader;
20+
import java.io.ByteArrayInputStream;
21+
import java.io.InputStream;
22+
import java.io.InputStreamReader;
23+
import java.nio.charset.StandardCharsets;
24+
import java.util.stream.Collectors;
25+
26+
import org.junit.jupiter.api.BeforeEach;
27+
import org.junit.jupiter.api.Test;
28+
29+
import org.springframework.core.io.ClassPathResource;
30+
31+
import static org.assertj.core.api.Assertions.assertThat;
32+
33+
public class OpenSamlMetadataRelyingPartyRegistrationConverterTests {
34+
35+
private OpenSamlMetadataRelyingPartyRegistrationConverter converter = new OpenSamlMetadataRelyingPartyRegistrationConverter();
36+
37+
private String metadata;
38+
39+
@BeforeEach
40+
public void setup() throws Exception {
41+
ClassPathResource resource = new ClassPathResource("test-metadata.xml");
42+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
43+
this.metadata = reader.lines().collect(Collectors.joining());
44+
}
45+
}
46+
47+
// gh-12667
48+
@Test
49+
public void convertWhenDefaultsThenAssertingPartyInstanceOfOpenSaml() throws Exception {
50+
try (InputStream source = new ByteArrayInputStream(this.metadata.getBytes(StandardCharsets.UTF_8))) {
51+
this.converter.convert(source)
52+
.forEach((registration) -> assertThat(registration.build().getAssertingPartyDetails())
53+
.isInstanceOf(OpenSamlAssertingPartyDetails.class));
54+
}
55+
}
56+
57+
}

0 commit comments

Comments
 (0)