1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.common.saml;
21
22 import java.security.PrivateKey;
23 import java.security.cert.X509Certificate;
24 import java.time.Instant;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import org.apache.wss4j.common.crypto.Crypto;
29 import org.apache.wss4j.common.crypto.CryptoType;
30 import org.apache.wss4j.common.ext.WSSecurityException;
31 import org.apache.wss4j.common.saml.builder.SAML1ComponentBuilder;
32 import org.apache.wss4j.common.saml.builder.SAML2ComponentBuilder;
33 import org.apache.wss4j.common.util.DOM2Writer;
34 import org.apache.wss4j.common.util.InetAddressUtils;
35 import org.apache.xml.security.stax.impl.util.IDGenerator;
36 import org.apache.xml.security.utils.XMLUtils;
37 import org.opensaml.core.xml.XMLObject;
38 import org.opensaml.saml.common.SAMLObject;
39 import org.opensaml.saml.common.SAMLObjectContentReference;
40 import org.opensaml.saml.common.SAMLVersion;
41 import org.opensaml.saml.common.SignableSAMLObject;
42 import org.opensaml.saml.saml1.core.AttributeStatement;
43 import org.opensaml.saml.saml1.core.AuthenticationStatement;
44 import org.opensaml.saml.saml1.core.AuthorizationDecisionStatement;
45 import org.opensaml.saml.saml1.core.ConfirmationMethod;
46 import org.opensaml.saml.saml1.core.Statement;
47 import org.opensaml.saml.saml1.core.Subject;
48 import org.opensaml.saml.saml1.core.SubjectConfirmation;
49 import org.opensaml.saml.saml1.core.SubjectStatement;
50 import org.opensaml.saml.saml2.core.AuthnStatement;
51 import org.opensaml.saml.saml2.core.AuthzDecisionStatement;
52 import org.opensaml.saml.saml2.core.Issuer;
53 import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator;
54 import org.opensaml.security.credential.BasicCredential;
55 import org.opensaml.security.x509.BasicX509Credential;
56 import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory;
57 import org.opensaml.xmlsec.signature.KeyInfo;
58 import org.opensaml.xmlsec.signature.Signature;
59 import org.opensaml.xmlsec.signature.support.SignatureConstants;
60 import org.opensaml.xmlsec.signature.support.SignatureException;
61 import org.opensaml.xmlsec.signature.support.SignatureValidator;
62 import org.opensaml.xmlsec.signature.support.SignerProvider;
63 import org.w3c.dom.Document;
64 import org.w3c.dom.Element;
65
66
67
68
69
70 public class SamlAssertionWrapper {
71
72
73
74 private static final org.slf4j.Logger LOG =
75 org.slf4j.LoggerFactory.getLogger(SamlAssertionWrapper.class);
76
77
78
79
80 private SAMLObject samlObject;
81
82
83
84
85 private SAMLVersion samlVersion;
86
87
88
89
90 private Element assertionElement;
91
92
93
94
95 private SAMLKeyInfo subjectKeyInfo;
96
97
98
99
100 private SAMLKeyInfo signatureKeyInfo;
101
102
103
104
105 private final String defaultCanonicalizationAlgorithm = SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS;
106
107
108
109
110 private final String defaultRSASignatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1;
111
112
113
114
115 private final String defaultDSASignatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_DSA;
116
117
118
119
120 private final String defaultECDSASignatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA1;
121
122
123
124
125 private final String defaultSignatureDigestAlgorithm = SignatureConstants.ALGO_ID_DIGEST_SHA1;
126
127
128
129
130 private final boolean fromDOM;
131
132
133
134
135
136
137
138 public SamlAssertionWrapper(Element element) throws WSSecurityException {
139 OpenSAMLUtil.initSamlEngine();
140
141 parseElement(element);
142 fromDOM = true;
143 }
144
145
146
147
148
149
150
151
152
153 public SamlAssertionWrapper(SAMLObject samlObject) throws WSSecurityException {
154 OpenSAMLUtil.initSamlEngine();
155
156 this.samlObject = samlObject;
157 if (samlObject instanceof org.opensaml.saml.saml1.core.Assertion) {
158 samlVersion = SAMLVersion.VERSION_11;
159 } else if (samlObject instanceof org.opensaml.saml.saml2.core.Assertion) {
160 samlVersion = SAMLVersion.VERSION_20;
161 } else {
162 LOG.error(
163 "SamlAssertionWrapper: found unexpected type "
164 + (samlObject != null ? samlObject.getClass().getName() : null)
165 );
166 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty",
167 new Object[] {"A SAML 2.0 or 1.1 Assertion can only be used with "
168 + "SamlAssertionWrapper"});
169 }
170 fromDOM = false;
171 }
172
173
174
175
176
177
178
179
180 public SamlAssertionWrapper(SAMLCallback samlCallback) throws WSSecurityException {
181 OpenSAMLUtil.initSamlEngine();
182
183 if (samlCallback.getAssertionElement() != null) {
184 parseElement(samlCallback.getAssertionElement());
185 fromDOM = true;
186 } else {
187
188 parseCallback(samlCallback);
189 fromDOM = false;
190 }
191 }
192
193
194
195
196
197
198 public org.opensaml.saml.saml1.core.Assertion getSaml1() {
199 if (samlVersion == SAMLVersion.VERSION_11) {
200 return (org.opensaml.saml.saml1.core.Assertion)samlObject;
201 }
202 return null;
203 }
204
205
206
207
208
209
210 public org.opensaml.saml.saml2.core.Assertion getSaml2() {
211 if (samlVersion == SAMLVersion.VERSION_20) {
212 return (org.opensaml.saml.saml2.core.Assertion)samlObject;
213 }
214 return null;
215 }
216
217
218
219
220
221
222 public boolean isCreated() {
223 return samlObject != null;
224 }
225
226
227
228
229
230
231
232
233
234 public Element toDOM(Document doc) throws WSSecurityException {
235 if (fromDOM && assertionElement != null) {
236 parseElement(assertionElement);
237 if (doc != null) {
238 return (Element)doc.importNode(assertionElement, true);
239 }
240 return assertionElement;
241 }
242 assertionElement = OpenSAMLUtil.toDom(samlObject, doc);
243 return assertionElement;
244 }
245
246
247
248
249
250
251 public String assertionToString() throws WSSecurityException {
252 if (assertionElement == null) {
253 Element element = toDOM(null);
254 return DOM2Writer.nodeToString(element);
255 }
256 return DOM2Writer.nodeToString(assertionElement);
257 }
258
259 public Instant getNotBefore() {
260 if (getSamlVersion().equals(SAMLVersion.VERSION_20)) {
261 return getSaml2().getConditions().getNotBefore();
262 } else {
263 return getSaml1().getConditions().getNotBefore();
264 }
265 }
266
267 public Instant getNotOnOrAfter() {
268 if (getSamlVersion().equals(SAMLVersion.VERSION_20)) {
269 return getSaml2().getConditions().getNotOnOrAfter();
270 } else {
271 return getSaml1().getConditions().getNotOnOrAfter();
272 }
273 }
274
275
276
277
278
279
280 public String getId() {
281 String id = null;
282 if (samlVersion == SAMLVersion.VERSION_20) {
283 id = ((org.opensaml.saml.saml2.core.Assertion)samlObject).getID();
284 if (id == null || id.length() == 0) {
285 LOG.error("SamlAssertionWrapper: ID was null, seeting a new ID value");
286 id = IDGenerator.generateID("_");
287 ((org.opensaml.saml.saml2.core.Assertion)samlObject).setID(id);
288 }
289 } else if (samlVersion == SAMLVersion.VERSION_11) {
290 id = ((org.opensaml.saml.saml1.core.Assertion)samlObject).getID();
291 if (id == null || id.length() == 0) {
292 LOG.error("SamlAssertionWrapper: ID was null, seeting a new ID value");
293 id = IDGenerator.generateID("_");
294 ((org.opensaml.saml.saml1.core.Assertion)samlObject).setID(id);
295 }
296 } else {
297 LOG.error("SamlAssertionWrapper: unable to return ID - no saml assertion object");
298 }
299 return id;
300 }
301
302
303
304
305
306
307 public String getIssuerString() {
308 if (samlVersion == SAMLVersion.VERSION_20
309 && ((org.opensaml.saml.saml2.core.Assertion)samlObject).getIssuer() != null) {
310 return ((org.opensaml.saml.saml2.core.Assertion)samlObject).getIssuer().getValue();
311 } else if (samlVersion == SAMLVersion.VERSION_11
312 && ((org.opensaml.saml.saml1.core.Assertion)samlObject).getIssuer() != null) {
313 return ((org.opensaml.saml.saml1.core.Assertion)samlObject).getIssuer();
314 }
315 LOG.error(
316 "SamlAssertionWrapper: unable to return Issuer string - no saml assertion "
317 + "object or issuer is null"
318 );
319 return null;
320 }
321
322
323
324
325
326 public String getSubjectName() {
327 if (samlVersion == SAMLVersion.VERSION_20) {
328 org.opensaml.saml.saml2.core.Subject subject =
329 ((org.opensaml.saml.saml2.core.Assertion)samlObject).getSubject();
330 if (subject != null && subject.getNameID() != null) {
331 return subject.getNameID().getValue();
332 }
333 } else if (samlVersion == SAMLVersion.VERSION_11) {
334 Subject samlSubject = null;
335 for (Statement stmt : ((org.opensaml.saml.saml1.core.Assertion)samlObject).getStatements()) {
336 if (stmt instanceof AttributeStatement) {
337 AttributeStatement attrStmt = (AttributeStatement) stmt;
338 samlSubject = attrStmt.getSubject();
339 } else if (stmt instanceof AuthenticationStatement) {
340 AuthenticationStatement authStmt = (AuthenticationStatement) stmt;
341 samlSubject = authStmt.getSubject();
342 } else {
343 AuthorizationDecisionStatement authzStmt =
344 (AuthorizationDecisionStatement)stmt;
345 samlSubject = authzStmt.getSubject();
346 }
347 if (samlSubject != null) {
348 break;
349 }
350 }
351 if (samlSubject != null && samlSubject.getNameIdentifier() != null) {
352 return samlSubject.getNameIdentifier().getValue();
353 }
354 }
355 LOG.error(
356 "SamlAssertionWrapper: unable to return SubjectName - no saml assertion "
357 + "object or subject is null"
358 );
359 return null;
360 }
361
362
363
364
365
366
367
368 public List<String> getConfirmationMethods() {
369 List<String> methods = new ArrayList<>();
370 if (samlVersion == SAMLVersion.VERSION_20) {
371 org.opensaml.saml.saml2.core.Subject subject =
372 ((org.opensaml.saml.saml2.core.Assertion)samlObject).getSubject();
373 List<org.opensaml.saml.saml2.core.SubjectConfirmation> confirmations =
374 subject.getSubjectConfirmations();
375 for (org.opensaml.saml.saml2.core.SubjectConfirmation confirmation : confirmations) {
376 methods.add(confirmation.getMethod());
377 }
378 } else if (samlVersion == SAMLVersion.VERSION_11) {
379 List<SubjectStatement> subjectStatements = new ArrayList<>();
380 org.opensaml.saml.saml1.core.Assertion saml1 =
381 (org.opensaml.saml.saml1.core.Assertion)samlObject;
382 subjectStatements.addAll(saml1.getSubjectStatements());
383 subjectStatements.addAll(saml1.getAuthenticationStatements());
384 subjectStatements.addAll(saml1.getAttributeStatements());
385 subjectStatements.addAll(saml1.getAuthorizationDecisionStatements());
386 for (SubjectStatement subjectStatement : subjectStatements) {
387 Subject subject = subjectStatement.getSubject();
388 if (subject != null) {
389 SubjectConfirmation confirmation = subject.getSubjectConfirmation();
390 if (confirmation != null) {
391 XMLObject data = confirmation.getSubjectConfirmationData();
392 if (data instanceof ConfirmationMethod) {
393 ConfirmationMethod method = (ConfirmationMethod) data;
394 methods.add(method.getURI());
395 }
396 List<ConfirmationMethod> confirmationMethods =
397 confirmation.getConfirmationMethods();
398 for (ConfirmationMethod confirmationMethod : confirmationMethods) {
399 methods.add(confirmationMethod.getURI());
400 }
401 }
402 }
403 }
404 }
405 return methods;
406 }
407
408
409
410
411
412
413 public boolean isSigned() {
414 return samlObject instanceof SignableSAMLObject
415 && (((SignableSAMLObject)samlObject).isSigned()
416 || ((SignableSAMLObject)samlObject).getSignature() != null);
417 }
418
419
420
421
422
423
424 public void setSignature(Signature signature) {
425 setSignature(signature, defaultSignatureDigestAlgorithm);
426 }
427
428
429
430
431
432
433
434 public void setSignature(Signature signature, String signatureDigestAlgorithm) {
435 if (samlObject instanceof SignableSAMLObject) {
436 SignableSAMLObject signableObject = (SignableSAMLObject) samlObject;
437 signableObject.setSignature(signature);
438 String digestAlg = signatureDigestAlgorithm;
439 if (digestAlg == null) {
440 digestAlg = defaultSignatureDigestAlgorithm;
441 }
442 SAMLObjectContentReference contentRef =
443 (SAMLObjectContentReference)signature.getContentReferences().get(0);
444 contentRef.setDigestAlgorithm(digestAlg);
445 signableObject.releaseDOM();
446 signableObject.releaseChildrenDOM(true);
447 } else {
448 LOG.error("Attempt to sign an unsignable object " + samlObject.getClass().getName());
449 }
450 }
451
452
453
454
455
456
457
458
459
460
461 public void signAssertion(String issuerKeyName, String issuerKeyPassword,
462 Crypto issuerCrypto, boolean sendKeyValue)
463 throws WSSecurityException {
464
465 signAssertion(issuerKeyName, issuerKeyPassword, issuerCrypto,
466 sendKeyValue, defaultCanonicalizationAlgorithm,
467 null, defaultSignatureDigestAlgorithm);
468 }
469
470
471
472
473
474
475
476
477
478
479
480
481 public void signAssertion(String issuerKeyName, String issuerKeyPassword,
482 Crypto issuerCrypto, boolean sendKeyValue,
483 String canonicalizationAlgorithm, String signatureAlgorithm)
484 throws WSSecurityException {
485 signAssertion(issuerKeyName, issuerKeyPassword, issuerCrypto, sendKeyValue,
486 canonicalizationAlgorithm, signatureAlgorithm, defaultSignatureDigestAlgorithm);
487 }
488
489
490
491
492
493
494
495
496
497
498
499
500
501 public void signAssertion(String issuerKeyName, String issuerKeyPassword,
502 Crypto issuerCrypto, boolean sendKeyValue,
503 String canonicalizationAlgorithm, String signatureAlgorithm,
504 String signatureDigestAlgorithm)
505 throws WSSecurityException {
506
507
508
509 Signature signature = OpenSAMLUtil.buildSignature();
510 String c14nAlgo = canonicalizationAlgorithm;
511 if (c14nAlgo == null) {
512 c14nAlgo = defaultCanonicalizationAlgorithm;
513 }
514 signature.setCanonicalizationAlgorithm(c14nAlgo);
515 LOG.debug("Using Canonicalization algorithm {}", c14nAlgo);
516
517
518 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
519 cryptoType.setAlias(issuerKeyName);
520 X509Certificate[] issuerCerts = null;
521 if (issuerCrypto != null) {
522 issuerCerts = issuerCrypto.getX509Certificates(cryptoType);
523 }
524 if (issuerCerts == null || issuerCerts.length == 0) {
525 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty",
526 new Object[] {"No issuer certs were found to sign the SAML Assertion using issuer name: "
527 + issuerKeyName});
528 }
529
530 String sigAlgo = signatureAlgorithm;
531 if (sigAlgo == null) {
532 sigAlgo = defaultRSASignatureAlgorithm;
533 String pubKeyAlgo = issuerCerts[0].getPublicKey().getAlgorithm();
534 LOG.debug("automatic sig algo detection: {}", pubKeyAlgo);
535 if (pubKeyAlgo.equalsIgnoreCase("DSA")) {
536 sigAlgo = defaultDSASignatureAlgorithm;
537 } else if (pubKeyAlgo.equalsIgnoreCase("EC")) {
538 sigAlgo = defaultECDSASignatureAlgorithm;
539 }
540 }
541 LOG.debug("Using Signature algorithm {}", sigAlgo);
542 PrivateKey privateKey;
543 try {
544 privateKey = issuerCrypto.getPrivateKey(issuerKeyName, issuerKeyPassword);
545 } catch (Exception ex) {
546 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex);
547 }
548 if (privateKey == null) {
549 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty",
550 new Object[] {"No private key was found using issuer name: " + issuerKeyName});
551 }
552
553 signature.setSignatureAlgorithm(sigAlgo);
554
555 BasicX509Credential signingCredential =
556 new BasicX509Credential(issuerCerts[0], privateKey);
557
558 signature.setSigningCredential(signingCredential);
559
560 X509KeyInfoGeneratorFactory kiFactory = new X509KeyInfoGeneratorFactory();
561 if (sendKeyValue) {
562 kiFactory.setEmitPublicKeyValue(true);
563 } else {
564 kiFactory.setEmitEntityCertificate(true);
565 }
566 try {
567 KeyInfo keyInfo = kiFactory.newInstance().generate(signingCredential);
568 signature.setKeyInfo(keyInfo);
569 } catch (org.opensaml.security.SecurityException ex) {
570 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
571 new Object[] {"Error generating KeyInfo from signing credential"});
572 }
573
574
575 setSignature(signature, signatureDigestAlgorithm);
576 }
577
578
579
580
581
582
583 public void verifySignature(
584 SAMLKeyInfoProcessor keyInfoProcessor, Crypto sigCrypto
585 ) throws WSSecurityException {
586 Signature sig = getSignature();
587 if (sig != null) {
588 KeyInfo keyInfo = sig.getKeyInfo();
589 if (keyInfo == null) {
590 throw new WSSecurityException(
591 WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity",
592 new Object[] {"cannot get certificate or key"}
593 );
594 }
595 SAMLKeyInfo samlKeyInfo =
596 SAMLUtil.getCredentialFromKeyInfo(keyInfo.getDOM(), keyInfoProcessor, sigCrypto);
597 verifySignature(samlKeyInfo);
598 } else {
599 LOG.debug("SamlAssertionWrapper: no signature to validate");
600 }
601
602 }
603
604
605
606
607
608
609 public void verifySignature(SAMLKeyInfo samlKeyInfo) throws WSSecurityException {
610 Signature sig = getSignature();
611 if (sig != null) {
612 if (samlKeyInfo == null) {
613 throw new WSSecurityException(
614 WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity",
615 new Object[] {"cannot get certificate or key"}
616 );
617 }
618
619 BasicCredential credential = null;
620 if (samlKeyInfo.getCerts() != null) {
621 credential = new BasicX509Credential(samlKeyInfo.getCerts()[0]);
622 } else if (samlKeyInfo.getPublicKey() != null) {
623 credential = new BasicCredential(samlKeyInfo.getPublicKey());
624 } else {
625 throw new WSSecurityException(
626 WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity",
627 new Object[] {"cannot get certificate or key"}
628 );
629 }
630 ClassLoader loader = Thread.currentThread().getContextClassLoader();
631 try {
632 Thread.currentThread().setContextClassLoader(SignerProvider.class.getClassLoader());
633 SignatureValidator.validate(sig, credential);
634 } catch (SignatureException ex) {
635 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex,
636 "empty", new Object[] {"SAML signature validation failed"});
637 } finally {
638 Thread.currentThread().setContextClassLoader(loader);
639 }
640 signatureKeyInfo = samlKeyInfo;
641 } else {
642 LOG.debug("SamlAssertionWrapper: no signature to validate");
643 }
644 }
645
646
647
648
649
650
651 public void validateSignatureAgainstProfile() throws WSSecurityException {
652 Signature sig = getSignature();
653 if (sig != null) {
654 SAMLSignatureProfileValidator validator = new SAMLSignatureProfileValidator();
655 try {
656 validator.validate(sig);
657 } catch (SignatureException ex) {
658 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex,
659 "empty", new Object[] {"SAML signature validation failed"});
660 }
661 }
662 }
663
664
665
666
667
668
669 public void parseSubject(
670 SAMLKeyInfoProcessor keyInfoProcessor,
671 Crypto sigCrypto
672 ) throws WSSecurityException {
673 if (samlVersion == SAMLVersion.VERSION_11) {
674 subjectKeyInfo =
675 SAMLUtil.getCredentialFromSubject(
676 (org.opensaml.saml.saml1.core.Assertion)samlObject, keyInfoProcessor, sigCrypto
677 );
678 } else if (samlVersion == SAMLVersion.VERSION_20) {
679 subjectKeyInfo =
680 SAMLUtil.getCredentialFromSubject(
681 (org.opensaml.saml.saml2.core.Assertion)samlObject, keyInfoProcessor, sigCrypto
682 );
683 }
684 }
685
686
687
688
689
690
691
692 public SAMLVersion getSamlVersion() {
693 if (samlVersion == null) {
694
695 LOG.debug(
696 "The SAML version was null in getSamlVersion(). Recomputing SAML version...");
697 if (samlObject instanceof org.opensaml.saml.saml1.core.Assertion) {
698 samlVersion = SAMLVersion.VERSION_11;
699 } else if (samlObject instanceof org.opensaml.saml.saml2.core.Assertion) {
700 samlVersion = SAMLVersion.VERSION_20;
701 } else {
702
703 throw new IllegalStateException(
704 "Could not determine the SAML version number. Check your "
705 + "configuration and try again."
706 );
707 }
708 }
709 return samlVersion;
710 }
711
712
713
714
715
716 public Element getElement() {
717 return assertionElement;
718 }
719
720
721
722
723
724 public SAMLKeyInfo getSignatureKeyInfo() {
725 return signatureKeyInfo;
726 }
727
728
729
730
731
732 public SAMLKeyInfo getSubjectKeyInfo() {
733 return subjectKeyInfo;
734 }
735
736
737
738
739
740
741 public byte[] getSignatureValue() throws WSSecurityException {
742 Signature sig = null;
743 if (samlObject instanceof SignableSAMLObject) {
744 sig = ((SignableSAMLObject)samlObject).getSignature();
745 }
746 if (sig != null) {
747 return getSignatureValue(sig);
748 }
749 return new byte[0];
750 }
751
752 private byte[] getSignatureValue(Signature signature) throws WSSecurityException {
753 Element signatureElement = signature.getDOM();
754
755 if (signatureElement != null) {
756 Element signedInfoElem = XMLUtils.getNextElement(signatureElement.getFirstChild());
757 if (signedInfoElem != null) {
758 Element signatureValueElement =
759 XMLUtils.getNextElement(signedInfoElem.getNextSibling());
760 if (signatureValueElement != null) {
761 String base64Input = XMLUtils.getFullTextChildrenFromNode(signatureValueElement);
762 return XMLUtils.decode(base64Input);
763 }
764 }
765 }
766
767 return new byte[0];
768 }
769
770 public Signature getSignature() throws WSSecurityException {
771 if (samlObject instanceof SignableSAMLObject) {
772 return ((SignableSAMLObject)samlObject).getSignature();
773 }
774 return null;
775 }
776
777 public SAMLObject getSamlObject() {
778 return samlObject;
779 }
780
781
782
783
784 public void checkConditions(int futureTTL) throws WSSecurityException {
785 Instant validFrom = null;
786 Instant validTill = null;
787
788 if (getSamlVersion().equals(SAMLVersion.VERSION_20)
789 && getSaml2().getConditions() != null) {
790 validFrom = getSaml2().getConditions().getNotBefore();
791 validTill = getSaml2().getConditions().getNotOnOrAfter();
792 } else if (getSamlVersion().equals(SAMLVersion.VERSION_11)
793 && getSaml1().getConditions() != null) {
794 validFrom = getSaml1().getConditions().getNotBefore();
795 validTill = getSaml1().getConditions().getNotOnOrAfter();
796 }
797
798 if (validFrom != null) {
799 Instant currentTime = Instant.now();
800 currentTime = currentTime.plusSeconds(futureTTL);
801 if (validFrom.isAfter(currentTime)) {
802 LOG.warn("SAML Token condition (Not Before) not met");
803 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
804 }
805 }
806
807 if (validTill != null && validTill.isBefore(Instant.now())) {
808 LOG.warn("SAML Token condition (Not On Or After) not met");
809 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
810 }
811 }
812
813
814
815
816 public void checkIssueInstant(int futureTTL, int ttl) throws WSSecurityException {
817 Instant issueInstant = null;
818 Instant validTill = null;
819
820 if (getSamlVersion().equals(SAMLVersion.VERSION_20)
821 && getSaml2().getConditions() != null) {
822 validTill = getSaml2().getConditions().getNotOnOrAfter();
823 issueInstant = getSaml2().getIssueInstant();
824 } else if (getSamlVersion().equals(SAMLVersion.VERSION_11)
825 && getSaml1().getConditions() != null) {
826 validTill = getSaml1().getConditions().getNotOnOrAfter();
827 issueInstant = getSaml1().getIssueInstant();
828 }
829
830
831 if (issueInstant != null) {
832 Instant currentTime = Instant.now().plusSeconds(futureTTL);
833 if (issueInstant.isAfter(currentTime)) {
834 LOG.warn("SAML Token IssueInstant not met");
835 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
836 }
837
838
839 if (validTill == null) {
840 currentTime = currentTime.minusSeconds(ttl);
841
842 if (issueInstant.isBefore(currentTime)) {
843 LOG.warn("SAML Token IssueInstant not met. The assertion was created too long ago.");
844 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
845 }
846 }
847 }
848
849 }
850
851
852
853
854 public void checkAudienceRestrictions(List<String> audienceRestrictions) throws WSSecurityException {
855
856 if (audienceRestrictions == null || audienceRestrictions.isEmpty()) {
857 return;
858 }
859
860 if (getSamlVersion().equals(SAMLVersion.VERSION_20) && getSaml2().getConditions() != null) {
861 org.opensaml.saml.saml2.core.Conditions conditions = getSaml2().getConditions();
862 if (conditions != null && conditions.getAudienceRestrictions() != null
863 && !conditions.getAudienceRestrictions().isEmpty()) {
864 boolean foundAddress = false;
865 for (org.opensaml.saml.saml2.core.AudienceRestriction audienceRestriction
866 : conditions.getAudienceRestrictions()) {
867 if (audienceRestriction.getAudiences() != null) {
868 List<org.opensaml.saml.saml2.core.Audience> audiences =
869 audienceRestriction.getAudiences();
870 for (org.opensaml.saml.saml2.core.Audience audience : audiences) {
871 String audienceURI = audience.getURI();
872 if (audienceRestrictions.contains(audienceURI)) {
873 foundAddress = true;
874 break;
875 }
876 }
877 }
878 }
879
880 if (!foundAddress) {
881 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
882 }
883 }
884 } else if (getSamlVersion().equals(SAMLVersion.VERSION_11) && getSaml1().getConditions() != null) {
885 org.opensaml.saml.saml1.core.Conditions conditions = getSaml1().getConditions();
886 if (conditions != null && conditions.getAudienceRestrictionConditions() != null
887 && !conditions.getAudienceRestrictionConditions().isEmpty()) {
888 boolean foundAddress = false;
889 for (org.opensaml.saml.saml1.core.AudienceRestrictionCondition audienceRestriction
890 : conditions.getAudienceRestrictionConditions()) {
891 if (audienceRestriction.getAudiences() != null) {
892 List<org.opensaml.saml.saml1.core.Audience> audiences =
893 audienceRestriction.getAudiences();
894 for (org.opensaml.saml.saml1.core.Audience audience : audiences) {
895 String audienceURI = audience.getURI();
896 if (audienceRestrictions.contains(audienceURI)) {
897 foundAddress = true;
898 break;
899 }
900 }
901 }
902 }
903
904 if (!foundAddress) {
905 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
906 }
907 }
908 }
909 }
910
911
912
913
914 public void checkAuthnStatements(int futureTTL) throws WSSecurityException {
915 if (getSamlVersion().equals(SAMLVersion.VERSION_20)
916 && getSaml2().getAuthnStatements() != null) {
917 List<AuthnStatement> authnStatements = getSaml2().getAuthnStatements();
918
919 for (AuthnStatement authnStatement : authnStatements) {
920 Instant authnInstant = authnStatement.getAuthnInstant();
921 Instant sessionNotOnOrAfter = authnStatement.getSessionNotOnOrAfter();
922 String subjectLocalityAddress = null;
923
924 if (authnStatement.getSubjectLocality() != null
925 && authnStatement.getSubjectLocality().getAddress() != null) {
926 subjectLocalityAddress = authnStatement.getSubjectLocality().getAddress();
927 }
928
929 validateAuthnStatement(authnInstant, sessionNotOnOrAfter,
930 subjectLocalityAddress, futureTTL);
931 }
932 } else if (getSamlVersion().equals(SAMLVersion.VERSION_11)
933 && getSaml1().getAuthenticationStatements() != null) {
934 List<AuthenticationStatement> authnStatements =
935 getSaml1().getAuthenticationStatements();
936
937 for (AuthenticationStatement authnStatement : authnStatements) {
938 Instant authnInstant = authnStatement.getAuthenticationInstant();
939 String subjectLocalityAddress = null;
940
941 if (authnStatement.getSubjectLocality() != null
942 && authnStatement.getSubjectLocality().getIPAddress() != null) {
943 subjectLocalityAddress = authnStatement.getSubjectLocality().getIPAddress();
944 }
945
946 validateAuthnStatement(authnInstant, null,
947 subjectLocalityAddress, futureTTL);
948 }
949 }
950 }
951
952 private void validateAuthnStatement(
953 Instant authnInstant, Instant sessionNotOnOrAfter, String subjectLocalityAddress,
954 int futureTTL
955 ) throws WSSecurityException {
956
957 Instant currentTime = Instant.now();
958 currentTime = currentTime.plusSeconds(futureTTL);
959 if (authnInstant.isAfter(currentTime)) {
960 LOG.warn("SAML Token AuthnInstant not met");
961 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
962 }
963
964
965 if (sessionNotOnOrAfter != null && sessionNotOnOrAfter.isBefore(Instant.now())) {
966 LOG.warn("SAML Token SessionNotOnOrAfter not met");
967 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
968 }
969
970
971 if (subjectLocalityAddress != null
972 && !(InetAddressUtils.isIPv4Address(subjectLocalityAddress)
973 || InetAddressUtils.isIPv6Address(subjectLocalityAddress))) {
974 LOG.warn("SAML Token SubjectLocality address is not valid: " + subjectLocalityAddress);
975 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
976 }
977 }
978
979
980
981
982 private void parseElement(Element element) throws WSSecurityException {
983 XMLObject xmlObject = OpenSAMLUtil.fromDom(element);
984 if (xmlObject instanceof org.opensaml.saml.saml1.core.Assertion) {
985 this.samlObject = (SAMLObject)xmlObject;
986 samlVersion = SAMLVersion.VERSION_11;
987 } else if (xmlObject instanceof org.opensaml.saml.saml2.core.Assertion) {
988 this.samlObject = (SAMLObject)xmlObject;
989 samlVersion = SAMLVersion.VERSION_20;
990 } else {
991 LOG.error(
992 "SamlAssertionWrapper: found unexpected type " + xmlObject.getClass().getName()
993 );
994 }
995
996 assertionElement = element;
997 }
998
999
1000
1001
1002 private void parseCallback(
1003 SAMLCallback samlCallback
1004 ) throws WSSecurityException {
1005 samlVersion = samlCallback.getSamlVersion();
1006 if (samlVersion == null) {
1007 samlVersion = SAMLVersion.VERSION_20;
1008 }
1009 String issuer = samlCallback.getIssuer();
1010 String issuerFormat = samlCallback.getIssuerFormat();
1011 String issuerQualifier = samlCallback.getIssuerQualifier();
1012
1013 if (samlVersion.equals(SAMLVersion.VERSION_11)) {
1014
1015 org.opensaml.saml.saml1.core.Assertion saml1 =
1016 SAML1ComponentBuilder.createSamlv1Assertion(issuer);
1017
1018 try {
1019
1020 List<AuthenticationStatement> authenticationStatements =
1021 SAML1ComponentBuilder.createSamlv1AuthenticationStatement(
1022 samlCallback.getAuthenticationStatementData()
1023 );
1024 saml1.getAuthenticationStatements().addAll(authenticationStatements);
1025
1026
1027 List<AttributeStatement> attributeStatements =
1028 SAML1ComponentBuilder.createSamlv1AttributeStatement(
1029 samlCallback.getAttributeStatementData()
1030 );
1031 saml1.getAttributeStatements().addAll(attributeStatements);
1032
1033
1034 List<AuthorizationDecisionStatement> authDecisionStatements =
1035 SAML1ComponentBuilder.createSamlv1AuthorizationDecisionStatement(
1036 samlCallback.getAuthDecisionStatementData()
1037 );
1038 saml1.getAuthorizationDecisionStatements().addAll(authDecisionStatements);
1039
1040
1041 org.opensaml.saml.saml1.core.Conditions conditions =
1042 SAML1ComponentBuilder.createSamlv1Conditions(samlCallback.getConditions());
1043 saml1.setConditions(conditions);
1044
1045 if (samlCallback.getAdvice() != null) {
1046 org.opensaml.saml.saml1.core.Advice advice =
1047 SAML1ComponentBuilder.createAdvice(samlCallback.getAdvice());
1048 saml1.setAdvice(advice);
1049 }
1050 } catch (org.opensaml.security.SecurityException ex) {
1051 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
1052 new Object[] {"Error generating KeyInfo from signing credential"}
1053 );
1054 }
1055
1056
1057 samlObject = saml1;
1058
1059 } else if (samlVersion.equals(SAMLVersion.VERSION_20)) {
1060
1061 org.opensaml.saml.saml2.core.Assertion saml2 = SAML2ComponentBuilder.createAssertion();
1062 Issuer samlIssuer = SAML2ComponentBuilder.createIssuer(issuer, issuerFormat, issuerQualifier);
1063
1064
1065 List<AuthnStatement> authnStatements =
1066 SAML2ComponentBuilder.createAuthnStatement(
1067 samlCallback.getAuthenticationStatementData()
1068 );
1069 saml2.getAuthnStatements().addAll(authnStatements);
1070
1071
1072 List<org.opensaml.saml.saml2.core.AttributeStatement> attributeStatements =
1073 SAML2ComponentBuilder.createAttributeStatement(
1074 samlCallback.getAttributeStatementData()
1075 );
1076 saml2.getAttributeStatements().addAll(attributeStatements);
1077
1078
1079 List<AuthzDecisionStatement> authDecisionStatements =
1080 SAML2ComponentBuilder.createAuthorizationDecisionStatement(
1081 samlCallback.getAuthDecisionStatementData()
1082 );
1083 saml2.getAuthzDecisionStatements().addAll(authDecisionStatements);
1084
1085
1086 saml2.setIssuer(samlIssuer);
1087
1088 try {
1089 org.opensaml.saml.saml2.core.Subject subject =
1090 SAML2ComponentBuilder.createSaml2Subject(samlCallback.getSubject());
1091 saml2.setSubject(subject);
1092 } catch (org.opensaml.security.SecurityException ex) {
1093 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
1094 new Object[] {"Error generating KeyInfo from signing credential"}
1095 );
1096 }
1097
1098 org.opensaml.saml.saml2.core.Conditions conditions =
1099 SAML2ComponentBuilder.createConditions(samlCallback.getConditions());
1100 saml2.setConditions(conditions);
1101
1102 if (samlCallback.getAdvice() != null) {
1103 org.opensaml.saml.saml2.core.Advice advice =
1104 SAML2ComponentBuilder.createAdvice(samlCallback.getAdvice());
1105 saml2.setAdvice(advice);
1106 }
1107
1108
1109 samlObject = saml2;
1110 }
1111 }
1112
1113 }