Skip to content

Commit dcf5cc9

Browse files
committed
Extract EntityDescriptor to AssertingPartyDetails Logic
Closes gh-15090
1 parent c885cee commit dcf5cc9

File tree

7 files changed

+231
-451
lines changed

7 files changed

+231
-451
lines changed

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

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,25 @@
1616

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

19+
import java.security.cert.CertificateException;
20+
import java.security.cert.X509Certificate;
21+
import java.util.ArrayList;
1922
import java.util.Collection;
2023
import java.util.List;
2124
import java.util.function.Consumer;
2225

26+
import org.opensaml.saml.common.xml.SAMLConstants;
27+
import org.opensaml.saml.ext.saml2alg.SigningMethod;
2328
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
29+
import org.opensaml.saml.saml2.metadata.Extensions;
30+
import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
31+
import org.opensaml.saml.saml2.metadata.KeyDescriptor;
32+
import org.opensaml.saml.saml2.metadata.SingleLogoutService;
33+
import org.opensaml.saml.saml2.metadata.SingleSignOnService;
34+
import org.opensaml.security.credential.UsageType;
35+
import org.opensaml.xmlsec.keyinfo.KeyInfoSupport;
2436

37+
import org.springframework.security.saml2.Saml2Exception;
2538
import org.springframework.security.saml2.core.Saml2X509Credential;
2639

2740
/**
@@ -62,7 +75,111 @@ public EntityDescriptor getEntityDescriptor() {
6275
* for further configurations
6376
*/
6477
public static OpenSamlAssertingPartyDetails.Builder withEntityDescriptor(EntityDescriptor entity) {
65-
return new OpenSamlAssertingPartyDetails.Builder(entity);
78+
IDPSSODescriptor idpssoDescriptor = entity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS);
79+
if (idpssoDescriptor == null) {
80+
throw new Saml2Exception("Metadata response is missing the necessary IDPSSODescriptor element");
81+
}
82+
List<Saml2X509Credential> verification = new ArrayList<>();
83+
List<Saml2X509Credential> encryption = new ArrayList<>();
84+
for (KeyDescriptor keyDescriptor : idpssoDescriptor.getKeyDescriptors()) {
85+
if (keyDescriptor.getUse().equals(UsageType.SIGNING)) {
86+
List<X509Certificate> certificates = certificates(keyDescriptor);
87+
for (X509Certificate certificate : certificates) {
88+
verification.add(Saml2X509Credential.verification(certificate));
89+
}
90+
}
91+
if (keyDescriptor.getUse().equals(UsageType.ENCRYPTION)) {
92+
List<X509Certificate> certificates = certificates(keyDescriptor);
93+
for (X509Certificate certificate : certificates) {
94+
encryption.add(Saml2X509Credential.encryption(certificate));
95+
}
96+
}
97+
if (keyDescriptor.getUse().equals(UsageType.UNSPECIFIED)) {
98+
List<X509Certificate> certificates = certificates(keyDescriptor);
99+
for (X509Certificate certificate : certificates) {
100+
verification.add(Saml2X509Credential.verification(certificate));
101+
encryption.add(Saml2X509Credential.encryption(certificate));
102+
}
103+
}
104+
}
105+
if (verification.isEmpty()) {
106+
throw new Saml2Exception(
107+
"Metadata response is missing verification certificates, necessary for verifying SAML assertions");
108+
}
109+
OpenSamlAssertingPartyDetails.Builder builder = new OpenSamlAssertingPartyDetails.Builder(entity)
110+
.entityId(entity.getEntityID())
111+
.wantAuthnRequestsSigned(Boolean.TRUE.equals(idpssoDescriptor.getWantAuthnRequestsSigned()))
112+
.verificationX509Credentials((c) -> c.addAll(verification))
113+
.encryptionX509Credentials((c) -> c.addAll(encryption));
114+
115+
List<SigningMethod> signingMethods = signingMethods(idpssoDescriptor);
116+
for (SigningMethod method : signingMethods) {
117+
builder.signingAlgorithms((algorithms) -> algorithms.add(method.getAlgorithm()));
118+
}
119+
if (idpssoDescriptor.getSingleSignOnServices().isEmpty()) {
120+
throw new Saml2Exception(
121+
"Metadata response is missing a SingleSignOnService, necessary for sending AuthnRequests");
122+
}
123+
for (SingleSignOnService singleSignOnService : idpssoDescriptor.getSingleSignOnServices()) {
124+
Saml2MessageBinding binding;
125+
if (singleSignOnService.getBinding().equals(Saml2MessageBinding.POST.getUrn())) {
126+
binding = Saml2MessageBinding.POST;
127+
}
128+
else if (singleSignOnService.getBinding().equals(Saml2MessageBinding.REDIRECT.getUrn())) {
129+
binding = Saml2MessageBinding.REDIRECT;
130+
}
131+
else {
132+
continue;
133+
}
134+
builder.singleSignOnServiceLocation(singleSignOnService.getLocation()).singleSignOnServiceBinding(binding);
135+
break;
136+
}
137+
for (SingleLogoutService singleLogoutService : idpssoDescriptor.getSingleLogoutServices()) {
138+
Saml2MessageBinding binding;
139+
if (singleLogoutService.getBinding().equals(Saml2MessageBinding.POST.getUrn())) {
140+
binding = Saml2MessageBinding.POST;
141+
}
142+
else if (singleLogoutService.getBinding().equals(Saml2MessageBinding.REDIRECT.getUrn())) {
143+
binding = Saml2MessageBinding.REDIRECT;
144+
}
145+
else {
146+
continue;
147+
}
148+
String responseLocation = (singleLogoutService.getResponseLocation() == null)
149+
? singleLogoutService.getLocation() : singleLogoutService.getResponseLocation();
150+
builder.singleLogoutServiceLocation(singleLogoutService.getLocation())
151+
.singleLogoutServiceResponseLocation(responseLocation)
152+
.singleLogoutServiceBinding(binding);
153+
break;
154+
}
155+
return builder;
156+
}
157+
158+
private static List<X509Certificate> certificates(KeyDescriptor keyDescriptor) {
159+
try {
160+
return KeyInfoSupport.getCertificates(keyDescriptor.getKeyInfo());
161+
}
162+
catch (CertificateException ex) {
163+
throw new Saml2Exception(ex);
164+
}
165+
}
166+
167+
private static List<SigningMethod> signingMethods(IDPSSODescriptor idpssoDescriptor) {
168+
Extensions extensions = idpssoDescriptor.getExtensions();
169+
List<SigningMethod> result = signingMethods(extensions);
170+
if (!result.isEmpty()) {
171+
return result;
172+
}
173+
EntityDescriptor descriptor = (EntityDescriptor) idpssoDescriptor.getParent();
174+
extensions = descriptor.getExtensions();
175+
return signingMethods(extensions);
176+
}
177+
178+
private static <T> List<T> signingMethods(Extensions extensions) {
179+
if (extensions != null) {
180+
return (List<T>) extensions.getUnknownXMLObjects(SigningMethod.DEFAULT_ELEMENT_NAME);
181+
}
182+
return new ArrayList<>();
66183
}
67184

68185
@Override

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

Lines changed: 0 additions & 228 deletions
This file was deleted.

0 commit comments

Comments
 (0)