1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.wss4j.stax.validate;
20
21 import java.time.Instant;
22 import java.util.List;
23
24 import org.apache.wss4j.common.cache.ReplayCache;
25 import org.apache.wss4j.common.crypto.Crypto;
26 import org.apache.wss4j.common.ext.WSSecurityException;
27 import org.apache.wss4j.common.saml.OpenSAMLUtil;
28 import org.apache.wss4j.common.saml.SamlAssertionWrapper;
29 import org.apache.wss4j.common.saml.builder.SAML1Constants;
30 import org.apache.wss4j.common.saml.builder.SAML2Constants;
31 import org.apache.wss4j.stax.securityToken.SamlSecurityToken;
32 import org.apache.wss4j.stax.impl.securityToken.SamlSecurityTokenImpl;
33 import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
34 import org.apache.xml.security.stax.securityToken.InboundSecurityToken;
35 import org.opensaml.saml.common.SAMLVersion;
36
37 public class SamlTokenValidatorImpl extends SignatureTokenValidatorImpl implements SamlTokenValidator {
38
39 private static final transient org.slf4j.Logger LOG =
40 org.slf4j.LoggerFactory.getLogger(SamlTokenValidatorImpl.class);
41
42
43
44
45
46 private int futureTTL = 60;
47
48
49
50
51
52 private int ttl = 60 * 30;
53
54
55
56
57
58 private boolean validateSignatureAgainstProfile = true;
59
60
61
62
63 private String requiredSubjectConfirmationMethod;
64
65
66
67
68
69 private boolean requireStandardSubjectConfirmationMethod = true;
70
71
72
73
74
75 private boolean requireBearerSignature = true;
76
77
78
79
80
81 public void setFutureTTL(int newFutureTTL) {
82 futureTTL = newFutureTTL;
83 }
84
85
86
87
88
89 public boolean isValidateSignatureAgainstProfile() {
90 return validateSignatureAgainstProfile;
91 }
92
93
94
95
96
97 public void setValidateSignatureAgainstProfile(boolean validateSignatureAgainstProfile) {
98 this.validateSignatureAgainstProfile = validateSignatureAgainstProfile;
99 }
100
101 public String getRequiredSubjectConfirmationMethod() {
102 return requiredSubjectConfirmationMethod;
103 }
104
105 public void setRequiredSubjectConfirmationMethod(String requiredSubjectConfirmationMethod) {
106 this.requiredSubjectConfirmationMethod = requiredSubjectConfirmationMethod;
107 }
108
109 @Override
110 public <T extends SamlSecurityToken & InboundSecurityToken> T validate(final SamlAssertionWrapper samlAssertionWrapper,
111 final InboundSecurityToken subjectSecurityToken,
112 final TokenContext tokenContext) throws WSSecurityException {
113
114 checkConditions(samlAssertionWrapper,
115 tokenContext.getWssSecurityProperties().getAudienceRestrictions());
116
117
118 checkAuthnStatements(samlAssertionWrapper);
119
120
121 verifySubjectConfirmationMethod(samlAssertionWrapper);
122
123
124 checkOneTimeUse(samlAssertionWrapper,
125 tokenContext.getWssSecurityProperties().getSamlOneTimeUseReplayCache());
126
127
128 validateAssertion(samlAssertionWrapper);
129
130 Crypto sigVerCrypto = null;
131 if (samlAssertionWrapper.isSigned()) {
132 sigVerCrypto = tokenContext.getWssSecurityProperties().getSignatureVerificationCrypto();
133 }
134 SamlSecurityTokenImpl securityToken = new SamlSecurityTokenImpl(
135 samlAssertionWrapper, subjectSecurityToken,
136 tokenContext.getWsSecurityContext(),
137 sigVerCrypto,
138 WSSecurityTokenConstants.KeyIdentifier_NoKeyInfo,
139 tokenContext.getWssSecurityProperties());
140
141 securityToken.setElementPath(tokenContext.getElementPath());
142 securityToken.setXMLSecEvent(tokenContext.getFirstXMLSecEvent());
143 @SuppressWarnings("unchecked")
144 T token = (T)securityToken;
145 return token;
146 }
147
148
149
150
151 protected void verifySubjectConfirmationMethod(
152 SamlAssertionWrapper samlAssertion
153 ) throws WSSecurityException {
154
155 List<String> methods = samlAssertion.getConfirmationMethods();
156 if (methods == null || methods.isEmpty()) {
157 if (requiredSubjectConfirmationMethod != null) {
158 LOG.warn("A required subject confirmation method was not present");
159 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
160 "invalidSAMLsecurity");
161 } else if (requireStandardSubjectConfirmationMethod) {
162 LOG.warn("A standard subject confirmation method was not present");
163 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
164 "invalidSAMLsecurity");
165 }
166 }
167
168 boolean signed = samlAssertion.isSigned();
169 boolean requiredMethodFound = false;
170 boolean standardMethodFound = false;
171 if (methods != null) {
172 for (String method : methods) {
173
174 if (OpenSAMLUtil.isMethodHolderOfKey(method)) {
175 if (!signed) {
176 LOG.warn("A holder-of-key assertion must be signed");
177 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
178 "invalidSAMLsecurity");
179 }
180 standardMethodFound = true;
181 }
182
183 if (method != null) {
184 if (method.equals(requiredSubjectConfirmationMethod)) {
185 requiredMethodFound = true;
186 }
187 if (SAML2Constants.CONF_BEARER.equals(method)
188 || SAML1Constants.CONF_BEARER.equals(method)) {
189 standardMethodFound = true;
190 if (requireBearerSignature && !signed) {
191 LOG.warn("A Bearer Assertion was not signed");
192 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
193 "invalidSAMLsecurity");
194 }
195 } else if (SAML2Constants.CONF_SENDER_VOUCHES.equals(method)
196 || SAML1Constants.CONF_SENDER_VOUCHES.equals(method)) {
197 standardMethodFound = true;
198 }
199 }
200 }
201 }
202
203 if (!requiredMethodFound && requiredSubjectConfirmationMethod != null) {
204 LOG.warn("A required subject confirmation method was not present");
205 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
206 "invalidSAMLsecurity");
207 }
208
209 if (!standardMethodFound && requireStandardSubjectConfirmationMethod) {
210 LOG.warn("A standard subject confirmation method was not present");
211 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
212 "invalidSAMLsecurity");
213 }
214 }
215
216
217
218
219 protected void checkConditions(
220 SamlAssertionWrapper samlAssertion, List<String> audienceRestrictions
221 ) throws WSSecurityException {
222 checkConditions(samlAssertion);
223 samlAssertion.checkAudienceRestrictions(audienceRestrictions);
224 }
225
226
227
228
229 protected void checkConditions(SamlAssertionWrapper samlAssertion) throws WSSecurityException {
230 samlAssertion.checkConditions(futureTTL);
231 samlAssertion.checkIssueInstant(futureTTL, ttl);
232 }
233
234
235
236
237 protected void checkAuthnStatements(SamlAssertionWrapper samlAssertion) throws WSSecurityException {
238 samlAssertion.checkAuthnStatements(futureTTL);
239 }
240
241
242
243
244
245 protected void checkOneTimeUse(
246 SamlAssertionWrapper samlAssertion, ReplayCache replayCache
247 ) throws WSSecurityException {
248 if (replayCache != null
249 && samlAssertion.getSamlVersion().equals(SAMLVersion.VERSION_20)
250 && samlAssertion.getSaml2().getConditions() != null
251 && samlAssertion.getSaml2().getConditions().getOneTimeUse() != null) {
252 String identifier = samlAssertion.getId();
253
254 if (replayCache.contains(identifier)) {
255 throw new WSSecurityException(
256 WSSecurityException.ErrorCode.INVALID_SECURITY,
257 "badSamlToken",
258 new Object[] {"A replay attack has been detected"});
259 }
260
261 Instant expires = samlAssertion.getSaml2().getConditions().getNotOnOrAfter();
262 if (expires != null) {
263 replayCache.add(identifier, expires);
264 } else {
265 replayCache.add(identifier);
266 }
267 }
268 }
269
270
271
272
273 protected void validateAssertion(SamlAssertionWrapper samlAssertion) throws WSSecurityException {
274 if (validateSignatureAgainstProfile) {
275 samlAssertion.validateSignatureAgainstProfile();
276 }
277 }
278
279 public boolean isRequireStandardSubjectConfirmationMethod() {
280 return requireStandardSubjectConfirmationMethod;
281 }
282
283 public void setRequireStandardSubjectConfirmationMethod(boolean requireStandardSubjectConfirmationMethod) {
284 this.requireStandardSubjectConfirmationMethod = requireStandardSubjectConfirmationMethod;
285 }
286
287 public boolean isRequireBearerSignature() {
288 return requireBearerSignature;
289 }
290
291 public void setRequireBearerSignature(boolean requireBearerSignature) {
292 this.requireBearerSignature = requireBearerSignature;
293 }
294
295 public int getTtl() {
296 return ttl;
297 }
298
299 public void setTtl(int ttl) {
300 this.ttl = ttl;
301 }
302
303 }