Skip to content

Commit 80b3182

Browse files
committed
Use OpenSAML API in authentication
Issue gh-11658
1 parent 416859e commit 80b3182

File tree

11 files changed

+1652
-1167
lines changed

11 files changed

+1652
-1167
lines changed

saml2/saml2-service-provider/spring-security-saml2-service-provider.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ sourceSets.configureEach { set ->
1313
filter { line -> line.replaceAll(".saml2.internal", ".saml2.provider.service.authentication.logout") }
1414
with from
1515
}
16+
17+
copy {
18+
into "$projectDir/src/$set.name/java/org/springframework/security/saml2/provider/service/authentication"
19+
filter { line -> line.replaceAll(".saml2.internal", ".saml2.provider.service.authentication") }
20+
with from
21+
}
1622
}
1723

1824
dependencies {

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/BaseOpenSamlAuthenticationProvider.java

Lines changed: 678 additions & 0 deletions
Large diffs are not rendered by default.

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4AuthenticationProvider.java

Lines changed: 38 additions & 565 deletions
Large diffs are not rendered by default.

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSaml4Template.java

Lines changed: 617 additions & 0 deletions
Large diffs are not rendered by default.

saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/authentication/OpenSamlDecryptionUtils.java

Lines changed: 0 additions & 113 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
* Copyright 2002-2024 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.authentication;
18+
19+
import java.io.InputStream;
20+
import java.nio.charset.StandardCharsets;
21+
import java.util.Collection;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.Objects;
25+
26+
import javax.xml.namespace.QName;
27+
28+
import org.opensaml.core.xml.XMLObject;
29+
import org.opensaml.saml.saml2.core.Issuer;
30+
import org.opensaml.saml.saml2.core.RequestAbstractType;
31+
import org.opensaml.saml.saml2.core.StatusResponseType;
32+
import org.opensaml.xmlsec.signature.SignableXMLObject;
33+
import org.w3c.dom.Element;
34+
35+
import org.springframework.security.saml2.core.Saml2Error;
36+
import org.springframework.security.saml2.core.Saml2ParameterNames;
37+
import org.springframework.security.saml2.core.Saml2X509Credential;
38+
import org.springframework.web.util.UriComponentsBuilder;
39+
40+
interface OpenSamlOperations {
41+
42+
<T extends XMLObject> T build(QName elementName);
43+
44+
<T extends XMLObject> T deserialize(String serialized);
45+
46+
<T extends XMLObject> T deserialize(InputStream serialized);
47+
48+
SerializationConfigurer<?> serialize(XMLObject object);
49+
50+
SerializationConfigurer<?> serialize(Element element);
51+
52+
SignatureConfigurer<?> withSigningKeys(Collection<Saml2X509Credential> credentials);
53+
54+
VerificationConfigurer withVerificationKeys(Collection<Saml2X509Credential> credentials);
55+
56+
DecryptionConfigurer withDecryptionKeys(Collection<Saml2X509Credential> credentials);
57+
58+
interface SerializationConfigurer<B extends SerializationConfigurer<B>> {
59+
60+
B prettyPrint(boolean pretty);
61+
62+
String serialize();
63+
64+
}
65+
66+
interface SignatureConfigurer<B extends SignatureConfigurer<B>> {
67+
68+
B algorithms(List<String> algs);
69+
70+
<O extends SignableXMLObject> O sign(O object);
71+
72+
Map<String, String> sign(Map<String, String> params);
73+
74+
}
75+
76+
interface VerificationConfigurer {
77+
78+
VerificationConfigurer entityId(String entityId);
79+
80+
Collection<Saml2Error> verify(SignableXMLObject signable);
81+
82+
Collection<Saml2Error> verify(VerificationConfigurer.RedirectParameters parameters);
83+
84+
final class RedirectParameters {
85+
86+
private final String id;
87+
88+
private final Issuer issuer;
89+
90+
private final String algorithm;
91+
92+
private final byte[] signature;
93+
94+
private final byte[] content;
95+
96+
RedirectParameters(Map<String, String> parameters, String parametersQuery, RequestAbstractType request) {
97+
this.id = request.getID();
98+
this.issuer = request.getIssuer();
99+
this.algorithm = parameters.get(Saml2ParameterNames.SIG_ALG);
100+
if (parameters.get(Saml2ParameterNames.SIGNATURE) != null) {
101+
this.signature = Saml2Utils.samlDecode(parameters.get(Saml2ParameterNames.SIGNATURE));
102+
}
103+
else {
104+
this.signature = null;
105+
}
106+
Map<String, String> queryParams = UriComponentsBuilder.newInstance()
107+
.query(parametersQuery)
108+
.build(true)
109+
.getQueryParams()
110+
.toSingleValueMap();
111+
String relayState = parameters.get(Saml2ParameterNames.RELAY_STATE);
112+
this.content = getContent(Saml2ParameterNames.SAML_REQUEST, relayState, queryParams);
113+
}
114+
115+
RedirectParameters(Map<String, String> parameters, String parametersQuery, StatusResponseType response) {
116+
this.id = response.getID();
117+
this.issuer = response.getIssuer();
118+
this.algorithm = parameters.get(Saml2ParameterNames.SIG_ALG);
119+
if (parameters.get(Saml2ParameterNames.SIGNATURE) != null) {
120+
this.signature = Saml2Utils.samlDecode(parameters.get(Saml2ParameterNames.SIGNATURE));
121+
}
122+
else {
123+
this.signature = null;
124+
}
125+
Map<String, String> queryParams = UriComponentsBuilder.newInstance()
126+
.query(parametersQuery)
127+
.build(true)
128+
.getQueryParams()
129+
.toSingleValueMap();
130+
String relayState = parameters.get(Saml2ParameterNames.RELAY_STATE);
131+
this.content = getContent(Saml2ParameterNames.SAML_RESPONSE, relayState, queryParams);
132+
}
133+
134+
static byte[] getContent(String samlObject, String relayState, final Map<String, String> queryParams) {
135+
if (Objects.nonNull(relayState)) {
136+
return String
137+
.format("%s=%s&%s=%s&%s=%s", samlObject, queryParams.get(samlObject),
138+
Saml2ParameterNames.RELAY_STATE, queryParams.get(Saml2ParameterNames.RELAY_STATE),
139+
Saml2ParameterNames.SIG_ALG, queryParams.get(Saml2ParameterNames.SIG_ALG))
140+
.getBytes(StandardCharsets.UTF_8);
141+
}
142+
else {
143+
return String
144+
.format("%s=%s&%s=%s", samlObject, queryParams.get(samlObject), Saml2ParameterNames.SIG_ALG,
145+
queryParams.get(Saml2ParameterNames.SIG_ALG))
146+
.getBytes(StandardCharsets.UTF_8);
147+
}
148+
}
149+
150+
String getId() {
151+
return this.id;
152+
}
153+
154+
Issuer getIssuer() {
155+
return this.issuer;
156+
}
157+
158+
byte[] getContent() {
159+
return this.content;
160+
}
161+
162+
String getAlgorithm() {
163+
return this.algorithm;
164+
}
165+
166+
byte[] getSignature() {
167+
return this.signature;
168+
}
169+
170+
boolean hasSignature() {
171+
return this.signature != null;
172+
}
173+
174+
}
175+
176+
}
177+
178+
interface DecryptionConfigurer {
179+
180+
void decrypt(XMLObject object);
181+
182+
}
183+
184+
}

0 commit comments

Comments
 (0)