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
821
822
823 if (getSamlVersion().equals(SAMLVersion.VERSION_20)) {
824 issueInstant = getSaml2().getIssueInstant();
825 if (getSaml2().getConditions() != null) {
826 validTill = getSaml2().getConditions().getNotOnOrAfter();
827 }
828 } else if (getSamlVersion().equals(SAMLVersion.VERSION_11)) {
829 issueInstant = getSaml1().getIssueInstant();
830 if (getSaml1().getConditions() != null) {
831 validTill = getSaml1().getConditions().getNotOnOrAfter();
832 }
833 }
834
835
836 if (issueInstant != null) {
837 Instant currentTime = Instant.now().plusSeconds(futureTTL);
838 if (issueInstant.isAfter(currentTime)) {
839 LOG.warn("SAML Token IssueInstant not met");
840 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
841 }
842
843
844 if (validTill == null) {
845 currentTime = currentTime.minusSeconds(ttl);
846
847 if (issueInstant.isBefore(currentTime)) {
848 LOG.warn("SAML Token IssueInstant not met. The assertion was created too long ago.");
849 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
850 }
851 }
852 }
853
854 }
855
856
857
858
859 public void checkAudienceRestrictions(List<String> audienceRestrictions) throws WSSecurityException {
860
861 if (audienceRestrictions == null || audienceRestrictions.isEmpty()) {
862 return;
863 }
864
865 if (getSamlVersion().equals(SAMLVersion.VERSION_20) && getSaml2().getConditions() != null) {
866 org.opensaml.saml.saml2.core.Conditions conditions = getSaml2().getConditions();
867 if (conditions != null && conditions.getAudienceRestrictions() != null
868 && !conditions.getAudienceRestrictions().isEmpty()) {
869 boolean foundAddress = false;
870 for (org.opensaml.saml.saml2.core.AudienceRestriction audienceRestriction
871 : conditions.getAudienceRestrictions()) {
872 if (audienceRestriction.getAudiences() != null) {
873 List<org.opensaml.saml.saml2.core.Audience> audiences =
874 audienceRestriction.getAudiences();
875 for (org.opensaml.saml.saml2.core.Audience audience : audiences) {
876 String audienceURI = audience.getURI();
877 if (audienceRestrictions.contains(audienceURI)) {
878 foundAddress = true;
879 break;
880 }
881 }
882 }
883 }
884
885 if (!foundAddress) {
886 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
887 }
888 }
889 } else if (getSamlVersion().equals(SAMLVersion.VERSION_11) && getSaml1().getConditions() != null) {
890 org.opensaml.saml.saml1.core.Conditions conditions = getSaml1().getConditions();
891 if (conditions != null && conditions.getAudienceRestrictionConditions() != null
892 && !conditions.getAudienceRestrictionConditions().isEmpty()) {
893 boolean foundAddress = false;
894 for (org.opensaml.saml.saml1.core.AudienceRestrictionCondition audienceRestriction
895 : conditions.getAudienceRestrictionConditions()) {
896 if (audienceRestriction.getAudiences() != null) {
897 List<org.opensaml.saml.saml1.core.Audience> audiences =
898 audienceRestriction.getAudiences();
899 for (org.opensaml.saml.saml1.core.Audience audience : audiences) {
900 String audienceURI = audience.getURI();
901 if (audienceRestrictions.contains(audienceURI)) {
902 foundAddress = true;
903 break;
904 }
905 }
906 }
907 }
908
909 if (!foundAddress) {
910 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
911 }
912 }
913 }
914 }
915
916
917
918
919 public void checkAuthnStatements(int futureTTL) throws WSSecurityException {
920 if (getSamlVersion().equals(SAMLVersion.VERSION_20)
921 && getSaml2().getAuthnStatements() != null) {
922 List<AuthnStatement> authnStatements = getSaml2().getAuthnStatements();
923
924 for (AuthnStatement authnStatement : authnStatements) {
925 Instant authnInstant = authnStatement.getAuthnInstant();
926 Instant sessionNotOnOrAfter = authnStatement.getSessionNotOnOrAfter();
927 String subjectLocalityAddress = null;
928
929 if (authnStatement.getSubjectLocality() != null
930 && authnStatement.getSubjectLocality().getAddress() != null) {
931 subjectLocalityAddress = authnStatement.getSubjectLocality().getAddress();
932 }
933
934 validateAuthnStatement(authnInstant, sessionNotOnOrAfter,
935 subjectLocalityAddress, futureTTL);
936 }
937 } else if (getSamlVersion().equals(SAMLVersion.VERSION_11)
938 && getSaml1().getAuthenticationStatements() != null) {
939 List<AuthenticationStatement> authnStatements =
940 getSaml1().getAuthenticationStatements();
941
942 for (AuthenticationStatement authnStatement : authnStatements) {
943 Instant authnInstant = authnStatement.getAuthenticationInstant();
944 String subjectLocalityAddress = null;
945
946 if (authnStatement.getSubjectLocality() != null
947 && authnStatement.getSubjectLocality().getIPAddress() != null) {
948 subjectLocalityAddress = authnStatement.getSubjectLocality().getIPAddress();
949 }
950
951 validateAuthnStatement(authnInstant, null,
952 subjectLocalityAddress, futureTTL);
953 }
954 }
955 }
956
957 private void validateAuthnStatement(
958 Instant authnInstant, Instant sessionNotOnOrAfter, String subjectLocalityAddress,
959 int futureTTL
960 ) throws WSSecurityException {
961
962 Instant currentTime = Instant.now();
963 currentTime = currentTime.plusSeconds(futureTTL);
964 if (authnInstant.isAfter(currentTime)) {
965 LOG.warn("SAML Token AuthnInstant not met");
966 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
967 }
968
969
970 if (sessionNotOnOrAfter != null && sessionNotOnOrAfter.isBefore(Instant.now())) {
971 LOG.warn("SAML Token SessionNotOnOrAfter not met");
972 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
973 }
974
975
976 if (subjectLocalityAddress != null
977 && !(InetAddressUtils.isIPv4Address(subjectLocalityAddress)
978 || InetAddressUtils.isIPv6Address(subjectLocalityAddress))) {
979 LOG.warn("SAML Token SubjectLocality address is not valid: " + subjectLocalityAddress);
980 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity");
981 }
982 }
983
984
985
986
987 private void parseElement(Element element) throws WSSecurityException {
988 XMLObject xmlObject = OpenSAMLUtil.fromDom(element);
989 if (xmlObject instanceof org.opensaml.saml.saml1.core.Assertion) {
990 this.samlObject = (SAMLObject)xmlObject;
991 samlVersion = SAMLVersion.VERSION_11;
992 } else if (xmlObject instanceof org.opensaml.saml.saml2.core.Assertion) {
993 this.samlObject = (SAMLObject)xmlObject;
994 samlVersion = SAMLVersion.VERSION_20;
995 } else {
996 LOG.error(
997 "SamlAssertionWrapper: found unexpected type " + xmlObject.getClass().getName()
998 );
999 }
1000
1001 assertionElement = element;
1002 }
1003
1004
1005
1006
1007 private void parseCallback(
1008 SAMLCallback samlCallback
1009 ) throws WSSecurityException {
1010 samlVersion = samlCallback.getSamlVersion();
1011 if (samlVersion == null) {
1012 samlVersion = SAMLVersion.VERSION_20;
1013 }
1014 String issuer = samlCallback.getIssuer();
1015 String issuerFormat = samlCallback.getIssuerFormat();
1016 String issuerQualifier = samlCallback.getIssuerQualifier();
1017
1018 if (samlVersion.equals(SAMLVersion.VERSION_11)) {
1019
1020 org.opensaml.saml.saml1.core.Assertion saml1 =
1021 SAML1ComponentBuilder.createSamlv1Assertion(issuer);
1022
1023 try {
1024
1025 List<AuthenticationStatement> authenticationStatements =
1026 SAML1ComponentBuilder.createSamlv1AuthenticationStatement(
1027 samlCallback.getAuthenticationStatementData()
1028 );
1029 saml1.getAuthenticationStatements().addAll(authenticationStatements);
1030
1031
1032 List<AttributeStatement> attributeStatements =
1033 SAML1ComponentBuilder.createSamlv1AttributeStatement(
1034 samlCallback.getAttributeStatementData()
1035 );
1036 saml1.getAttributeStatements().addAll(attributeStatements);
1037
1038
1039 List<AuthorizationDecisionStatement> authDecisionStatements =
1040 SAML1ComponentBuilder.createSamlv1AuthorizationDecisionStatement(
1041 samlCallback.getAuthDecisionStatementData()
1042 );
1043 saml1.getAuthorizationDecisionStatements().addAll(authDecisionStatements);
1044
1045
1046 org.opensaml.saml.saml1.core.Conditions conditions =
1047 SAML1ComponentBuilder.createSamlv1Conditions(samlCallback.getConditions());
1048 saml1.setConditions(conditions);
1049
1050 if (samlCallback.getAdvice() != null) {
1051 org.opensaml.saml.saml1.core.Advice advice =
1052 SAML1ComponentBuilder.createAdvice(samlCallback.getAdvice());
1053 saml1.setAdvice(advice);
1054 }
1055 } catch (org.opensaml.security.SecurityException ex) {
1056 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
1057 new Object[] {"Error generating KeyInfo from signing credential"}
1058 );
1059 }
1060
1061
1062 samlObject = saml1;
1063
1064 } else if (samlVersion.equals(SAMLVersion.VERSION_20)) {
1065
1066 org.opensaml.saml.saml2.core.Assertion saml2 = SAML2ComponentBuilder.createAssertion();
1067 Issuer samlIssuer = SAML2ComponentBuilder.createIssuer(issuer, issuerFormat, issuerQualifier);
1068
1069
1070 List<AuthnStatement> authnStatements =
1071 SAML2ComponentBuilder.createAuthnStatement(
1072 samlCallback.getAuthenticationStatementData()
1073 );
1074 saml2.getAuthnStatements().addAll(authnStatements);
1075
1076
1077 List<org.opensaml.saml.saml2.core.AttributeStatement> attributeStatements =
1078 SAML2ComponentBuilder.createAttributeStatement(
1079 samlCallback.getAttributeStatementData()
1080 );
1081 saml2.getAttributeStatements().addAll(attributeStatements);
1082
1083
1084 List<AuthzDecisionStatement> authDecisionStatements =
1085 SAML2ComponentBuilder.createAuthorizationDecisionStatement(
1086 samlCallback.getAuthDecisionStatementData()
1087 );
1088 saml2.getAuthzDecisionStatements().addAll(authDecisionStatements);
1089
1090
1091 saml2.setIssuer(samlIssuer);
1092
1093 try {
1094 org.opensaml.saml.saml2.core.Subject subject =
1095 SAML2ComponentBuilder.createSaml2Subject(samlCallback.getSubject());
1096 saml2.setSubject(subject);
1097 } catch (org.opensaml.security.SecurityException ex) {
1098 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "empty",
1099 new Object[] {"Error generating KeyInfo from signing credential"}
1100 );
1101 }
1102
1103 org.opensaml.saml.saml2.core.Conditions conditions =
1104 SAML2ComponentBuilder.createConditions(samlCallback.getConditions());
1105 saml2.setConditions(conditions);
1106
1107 if (samlCallback.getAdvice() != null) {
1108 org.opensaml.saml.saml2.core.Advice advice =
1109 SAML2ComponentBuilder.createAdvice(samlCallback.getAdvice());
1110 saml2.setAdvice(advice);
1111 }
1112
1113
1114 samlObject = saml2;
1115 }
1116 }
1117
1118 }