Skip to content

Commit 541a1e4

Browse files
committed
Add OpenSamlAssertingPartyDetails
Closes gh-10781
1 parent 4a3654a commit 541a1e4

File tree

6 files changed

+151
-43
lines changed

6 files changed

+151
-43
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2002-2022 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 org.opensaml.saml.saml2.metadata.EntityDescriptor;
20+
21+
/**
22+
* A {@link RelyingPartyRegistration.AssertingPartyDetails} that contains
23+
* OpenSAML-specific members
24+
*
25+
* @author Josh Cummings
26+
* @since 5.7
27+
*/
28+
public final class OpenSamlAssertingPartyDetails extends RelyingPartyRegistration.AssertingPartyDetails {
29+
30+
private final EntityDescriptor descriptor;
31+
32+
OpenSamlAssertingPartyDetails(RelyingPartyRegistration.AssertingPartyDetails details, EntityDescriptor descriptor) {
33+
super(details.getEntityId(), details.getWantAuthnRequestsSigned(), details.getSigningAlgorithms(),
34+
details.getVerificationX509Credentials(), details.getEncryptionX509Credentials(),
35+
details.getSingleSignOnServiceLocation(), details.getSingleSignOnServiceBinding(),
36+
details.getSingleLogoutServiceLocation(), details.getSingleLogoutServiceResponseLocation(),
37+
details.getSingleLogoutServiceBinding());
38+
this.descriptor = descriptor;
39+
}
40+
41+
/**
42+
* Get the {@link EntityDescriptor} that underlies this
43+
* {@link org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails}
44+
* @return the {@link EntityDescriptor}
45+
*/
46+
public EntityDescriptor getEntityDescriptor() {
47+
return this.descriptor;
48+
}
49+
50+
/**
51+
* Use this {@link EntityDescriptor} to begin building an
52+
* {@link org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails}
53+
* @param entity the {@link EntityDescriptor} to use
54+
* @return the
55+
* {@link org.springframework.security.saml2.provider.service.registration.OpenSamlAssertingPartyDetails.Builder}
56+
* for further configurations
57+
*/
58+
public static OpenSamlAssertingPartyDetails.Builder withEntityDescriptor(EntityDescriptor entity) {
59+
return new OpenSamlAssertingPartyDetails.Builder(entity);
60+
}
61+
62+
/**
63+
* An OpenSAML version of
64+
* {@link org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails.Builder}
65+
* that contains the underlying {@link EntityDescriptor}
66+
*/
67+
public static final class Builder extends RelyingPartyRegistration.AssertingPartyDetails.Builder {
68+
69+
private final EntityDescriptor descriptor;
70+
71+
private Builder(EntityDescriptor descriptor) {
72+
this.descriptor = descriptor;
73+
}
74+
75+
/**
76+
* Build an
77+
* {@link org.springframework.security.saml2.provider.service.registration.OpenSamlAssertingPartyDetails}
78+
* @return
79+
*/
80+
@Override
81+
public OpenSamlAssertingPartyDetails build() {
82+
return new OpenSamlAssertingPartyDetails(super.build(), this.descriptor);
83+
}
84+
85+
}
86+
87+
}
+16-20
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
import org.springframework.security.saml2.core.OpenSamlInitializationService;
4848
import org.springframework.security.saml2.core.Saml2X509Credential;
4949

50-
class OpenSamlAssertingPartyMetadataConverter {
50+
class OpenSamlMetadataAssertingPartyDetailsConverter {
5151

5252
static {
5353
OpenSamlInitializationService.initialize();
@@ -58,15 +58,15 @@ class OpenSamlAssertingPartyMetadataConverter {
5858
private final ParserPool parserPool;
5959

6060
/**
61-
* Creates a {@link OpenSamlAssertingPartyMetadataConverter}
61+
* Creates a {@link OpenSamlMetadataAssertingPartyDetailsConverter}
6262
*/
63-
OpenSamlAssertingPartyMetadataConverter() {
63+
OpenSamlMetadataAssertingPartyDetailsConverter() {
6464
this.registry = ConfigurationService.get(XMLObjectProviderRegistry.class);
6565
this.parserPool = this.registry.getParserPool();
6666
}
6767

68-
Collection<RelyingPartyRegistration.Builder> convert(InputStream inputStream) {
69-
List<RelyingPartyRegistration.Builder> builders = new ArrayList<>();
68+
Collection<RelyingPartyRegistration.AssertingPartyDetails.Builder> convert(InputStream inputStream) {
69+
List<RelyingPartyRegistration.AssertingPartyDetails.Builder> builders = new ArrayList<>();
7070
XMLObject xmlObject = xmlObject(inputStream);
7171
if (xmlObject instanceof EntitiesDescriptor) {
7272
EntitiesDescriptor descriptors = (EntitiesDescriptor) xmlObject;
@@ -82,7 +82,7 @@ Collection<RelyingPartyRegistration.Builder> convert(InputStream inputStream) {
8282
throw new Saml2Exception("Unsupported element of type " + xmlObject.getClass());
8383
}
8484

85-
RelyingPartyRegistration.Builder convert(EntityDescriptor descriptor) {
85+
RelyingPartyRegistration.AssertingPartyDetails.Builder convert(EntityDescriptor descriptor) {
8686
IDPSSODescriptor idpssoDescriptor = descriptor.getIDPSSODescriptor(SAMLConstants.SAML20P_NS);
8787
if (idpssoDescriptor == null) {
8888
throw new Saml2Exception("Metadata response is missing the necessary IDPSSODescriptor element");
@@ -114,15 +114,14 @@ RelyingPartyRegistration.Builder convert(EntityDescriptor descriptor) {
114114
throw new Saml2Exception(
115115
"Metadata response is missing verification certificates, necessary for verifying SAML assertions");
116116
}
117-
RelyingPartyRegistration.Builder builder = RelyingPartyRegistration.withRegistrationId(descriptor.getEntityID())
118-
.assertingPartyDetails((party) -> party.entityId(descriptor.getEntityID())
119-
.wantAuthnRequestsSigned(Boolean.TRUE.equals(idpssoDescriptor.getWantAuthnRequestsSigned()))
120-
.verificationX509Credentials((c) -> c.addAll(verification))
121-
.encryptionX509Credentials((c) -> c.addAll(encryption)));
117+
RelyingPartyRegistration.AssertingPartyDetails.Builder party = OpenSamlAssertingPartyDetails
118+
.withEntityDescriptor(descriptor).entityId(descriptor.getEntityID())
119+
.wantAuthnRequestsSigned(Boolean.TRUE.equals(idpssoDescriptor.getWantAuthnRequestsSigned()))
120+
.verificationX509Credentials((c) -> c.addAll(verification))
121+
.encryptionX509Credentials((c) -> c.addAll(encryption));
122122
List<SigningMethod> signingMethods = signingMethods(idpssoDescriptor);
123123
for (SigningMethod method : signingMethods) {
124-
builder.assertingPartyDetails(
125-
(party) -> party.signingAlgorithms((algorithms) -> algorithms.add(method.getAlgorithm())));
124+
party.signingAlgorithms((algorithms) -> algorithms.add(method.getAlgorithm()));
126125
}
127126
if (idpssoDescriptor.getSingleSignOnServices().isEmpty()) {
128127
throw new Saml2Exception(
@@ -139,9 +138,7 @@ else if (singleSignOnService.getBinding().equals(Saml2MessageBinding.REDIRECT.ge
139138
else {
140139
continue;
141140
}
142-
builder.assertingPartyDetails(
143-
(party) -> party.singleSignOnServiceLocation(singleSignOnService.getLocation())
144-
.singleSignOnServiceBinding(binding));
141+
party.singleSignOnServiceLocation(singleSignOnService.getLocation()).singleSignOnServiceBinding(binding);
145142
break;
146143
}
147144
for (SingleLogoutService singleLogoutService : idpssoDescriptor.getSingleLogoutServices()) {
@@ -157,12 +154,11 @@ else if (singleLogoutService.getBinding().equals(Saml2MessageBinding.REDIRECT.ge
157154
}
158155
String responseLocation = (singleLogoutService.getResponseLocation() == null)
159156
? singleLogoutService.getLocation() : singleLogoutService.getResponseLocation();
160-
builder.assertingPartyDetails(
161-
(party) -> party.singleLogoutServiceLocation(singleLogoutService.getLocation())
162-
.singleLogoutServiceResponseLocation(responseLocation).singleLogoutServiceBinding(binding));
157+
party.singleLogoutServiceLocation(singleLogoutService.getLocation())
158+
.singleLogoutServiceResponseLocation(responseLocation).singleLogoutServiceBinding(binding);
163159
break;
164160
}
165-
return builder;
161+
return party;
166162
}
167163

168164
private List<X509Certificate> certificates(KeyDescriptor keyDescriptor) {

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter
6262
OpenSamlInitializationService.initialize();
6363
}
6464

65-
private final OpenSamlAssertingPartyMetadataConverter converter;
65+
private final OpenSamlMetadataAssertingPartyDetailsConverter converter;
6666

6767
/**
6868
* Creates a {@link OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter}
6969
*/
7070
public OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter() {
71-
this.converter = new OpenSamlAssertingPartyMetadataConverter();
71+
this.converter = new OpenSamlMetadataAssertingPartyDetailsConverter();
7272
}
7373

7474
@Override
@@ -89,7 +89,8 @@ public List<MediaType> getSupportedMediaTypes() {
8989
@Override
9090
public RelyingPartyRegistration.Builder read(Class<? extends RelyingPartyRegistration.Builder> clazz,
9191
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
92-
return this.converter.convert(inputMessage.getBody()).iterator().next();
92+
return RelyingPartyRegistration
93+
.withAssertingPartyDetails(this.converter.convert(inputMessage.getBody()).iterator().next().build());
9394
}
9495

9596
@Override

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

+20-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -422,6 +422,21 @@ public static Builder withRegistrationId(String registrationId) {
422422
return new Builder(registrationId);
423423
}
424424

425+
public static Builder withAssertingPartyDetails(AssertingPartyDetails assertingPartyDetails) {
426+
Assert.notNull(assertingPartyDetails, "assertingPartyDetails cannot be null");
427+
return withRegistrationId(assertingPartyDetails.getEntityId()).assertingPartyDetails((party) -> party
428+
.entityId(assertingPartyDetails.getEntityId())
429+
.wantAuthnRequestsSigned(assertingPartyDetails.getWantAuthnRequestsSigned())
430+
.signingAlgorithms((algorithms) -> algorithms.addAll(assertingPartyDetails.getSigningAlgorithms()))
431+
.verificationX509Credentials((c) -> c.addAll(assertingPartyDetails.getVerificationX509Credentials()))
432+
.encryptionX509Credentials((c) -> c.addAll(assertingPartyDetails.getEncryptionX509Credentials()))
433+
.singleSignOnServiceLocation(assertingPartyDetails.getSingleSignOnServiceLocation())
434+
.singleSignOnServiceBinding(assertingPartyDetails.getSingleSignOnServiceBinding())
435+
.singleLogoutServiceLocation(assertingPartyDetails.getSingleLogoutServiceLocation())
436+
.singleLogoutServiceResponseLocation(assertingPartyDetails.getSingleLogoutServiceResponseLocation())
437+
.singleLogoutServiceBinding(assertingPartyDetails.getSingleLogoutServiceBinding()));
438+
}
439+
425440
/**
426441
* Creates a {@code RelyingPartyRegistration} {@link Builder} based on an existing
427442
* object
@@ -510,7 +525,7 @@ private static org.springframework.security.saml2.credentials.Saml2X509Credentia
510525
*
511526
* @since 5.4
512527
*/
513-
public static final class AssertingPartyDetails {
528+
public static class AssertingPartyDetails {
514529

515530
private final String entityId;
516531

@@ -532,7 +547,7 @@ public static final class AssertingPartyDetails {
532547

533548
private final Saml2MessageBinding singleLogoutServiceBinding;
534549

535-
private AssertingPartyDetails(String entityId, boolean wantAuthnRequestsSigned, List<String> signingAlgorithms,
550+
AssertingPartyDetails(String entityId, boolean wantAuthnRequestsSigned, List<String> signingAlgorithms,
536551
Collection<Saml2X509Credential> verificationX509Credentials,
537552
Collection<Saml2X509Credential> encryptionX509Credentials, String singleSignOnServiceLocation,
538553
Saml2MessageBinding singleSignOnServiceBinding, String singleLogoutServiceLocation,
@@ -701,7 +716,7 @@ public Saml2MessageBinding getSingleLogoutServiceBinding() {
701716
return this.singleLogoutServiceBinding;
702717
}
703718

704-
public static final class Builder {
719+
public static class Builder {
705720

706721
private String entityId;
707722

@@ -951,7 +966,7 @@ public Saml2MessageBinding getBinding() {
951966
@Deprecated
952967
public static final class Builder {
953968

954-
private final AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
969+
private AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
955970

956971
/**
957972
* Set the asserting party's <a href=

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

+9-3
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818

1919
import java.io.IOException;
2020
import java.io.InputStream;
21+
import java.util.ArrayList;
2122
import java.util.Collection;
2223

2324
import org.springframework.core.io.DefaultResourceLoader;
2425
import org.springframework.core.io.ResourceLoader;
2526
import org.springframework.security.saml2.Saml2Exception;
27+
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails;
2628

2729
/**
2830
* A utility class for constructing instances of {@link RelyingPartyRegistration}
@@ -34,7 +36,7 @@
3436
*/
3537
public final class RelyingPartyRegistrations {
3638

37-
private static final OpenSamlAssertingPartyMetadataConverter assertingPartyMetadataConverter = new OpenSamlAssertingPartyMetadataConverter();
39+
private static final OpenSamlMetadataAssertingPartyDetailsConverter assertingPartyMetadataConverter = new OpenSamlMetadataAssertingPartyDetailsConverter();
3840

3941
private static final ResourceLoader resourceLoader = new DefaultResourceLoader();
4042

@@ -123,7 +125,7 @@ public static RelyingPartyRegistration.Builder fromMetadataLocation(String metad
123125
* @since 5.6
124126
*/
125127
public static RelyingPartyRegistration.Builder fromMetadata(InputStream source) {
126-
return assertingPartyMetadataConverter.convert(source).iterator().next();
128+
return collectionFromMetadata(source).iterator().next();
127129
}
128130

129131
/**
@@ -213,7 +215,11 @@ public static Collection<RelyingPartyRegistration.Builder> collectionFromMetadat
213215
* @since 5.7
214216
*/
215217
public static Collection<RelyingPartyRegistration.Builder> collectionFromMetadata(InputStream source) {
216-
return assertingPartyMetadataConverter.convert(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;
217223
}
218224

219225
}

0 commit comments

Comments
 (0)