View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.ws.security.saml.ext;
21  
22  import org.apache.ws.security.WSDocInfo;
23  import org.apache.ws.security.WSSecurityException;
24  import org.apache.ws.security.components.crypto.Crypto;
25  import org.apache.ws.security.components.crypto.CryptoType;
26  import org.apache.ws.security.handler.RequestData;
27  import org.apache.ws.security.saml.SAMLKeyInfo;
28  import org.apache.ws.security.saml.SAMLUtil;
29  import org.apache.ws.security.saml.ext.builder.SAML1ComponentBuilder;
30  import org.apache.ws.security.saml.ext.builder.SAML2ComponentBuilder;
31  
32  import org.apache.ws.security.util.DOM2Writer;
33  import org.apache.ws.security.util.UUIDGenerator;
34  import org.apache.xml.security.exceptions.XMLSecurityException;
35  import org.apache.xml.security.signature.XMLSignature;
36  import org.apache.xml.security.signature.XMLSignatureException;
37  
38  import org.opensaml.common.SAMLVersion;
39  import org.opensaml.common.SignableSAMLObject;
40  import org.opensaml.saml1.core.AttributeStatement;
41  import org.opensaml.saml1.core.AuthenticationStatement;
42  import org.opensaml.saml1.core.AuthorizationDecisionStatement;
43  import org.opensaml.saml1.core.ConfirmationMethod;
44  import org.opensaml.saml1.core.Subject;
45  import org.opensaml.saml1.core.SubjectConfirmation;
46  import org.opensaml.saml1.core.SubjectStatement;
47  import org.opensaml.saml2.core.AuthnStatement;
48  import org.opensaml.saml2.core.AuthzDecisionStatement;
49  import org.opensaml.saml2.core.Issuer;
50  import org.opensaml.security.SAMLSignatureProfileValidator;
51  import org.opensaml.xml.XMLObject;
52  import org.opensaml.xml.security.x509.BasicX509Credential;
53  import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory;
54  import org.opensaml.xml.signature.KeyInfo;
55  import org.opensaml.xml.signature.Signature;
56  import org.opensaml.xml.signature.SignatureConstants;
57  import org.opensaml.xml.signature.SignatureValidator;
58  import org.opensaml.xml.validation.ValidationException;
59  
60  import org.w3c.dom.Document;
61  import org.w3c.dom.Element;
62  
63  import javax.security.auth.callback.CallbackHandler;
64  import javax.security.auth.callback.UnsupportedCallbackException;
65  
66  import java.io.IOException;
67  import java.security.PrivateKey;
68  import java.security.cert.X509Certificate;
69  import java.util.ArrayList;
70  import java.util.List;
71  
72  /**
73   * Class AssertionWrapper can generate, sign, and validate both SAML v1.1
74   * and SAML v2.0 assertions.
75   * <p/>
76   * Created on May 18, 2009
77   */
78  public class AssertionWrapper {
79      /**
80       * Field log
81       */
82      private static final org.apache.commons.logging.Log LOG = 
83          org.apache.commons.logging.LogFactory.getLog(AssertionWrapper.class);
84  
85      /**
86       * Raw SAML assertion data
87       */
88      private XMLObject xmlObject = null;
89  
90      /**
91       * Typed SAML v1.1 assertion
92       */
93      private org.opensaml.saml1.core.Assertion saml1 = null;
94  
95      /**
96       * Typed SAML v2.0 assertion
97       */
98      private org.opensaml.saml2.core.Assertion saml2 = null;
99  
100     /**
101      * Which SAML specification to use (currently, only v1.1 and v2.0 are supported)
102      */
103     private SAMLVersion samlVersion;
104 
105     /**
106      * Fully qualified class name of the SAML callback handler implementation to use.
107      * NOTE: Each application should provide a unique implementation of this 
108      * <code>CallbackHandler</code> that is able to extract any dynamic data from the
109      * local environment that should be included in the generated SAML statements.
110      */
111     private CallbackHandler samlCallbackHandler = null;
112     
113     /**
114      * The Assertion as a DOM element
115      */
116     private Element assertionElement;
117     
118     /**
119      * The SAMLKeyInfo object associated with the Subject KeyInfo
120      */
121     private SAMLKeyInfo subjectKeyInfo;
122     
123     /**
124      * The SAMLKeyInfo object associated with the Signature on the Assertion
125      */
126     private SAMLKeyInfo signatureKeyInfo;
127 
128     /**
129      * Default Canonicalization algorithm used for signing.
130      */
131     private final String defaultCanonicalizationAlgorithm = SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS;
132 
133     /**
134      * Default RSA Signature algorithm used for signing.
135      */
136     private final String defaultRSASignatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1;
137 
138     /**
139      * Default DSA Signature algorithm used for signing.
140      */
141     private final String defaultDSASignatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_DSA;
142     
143     /**
144      * Whether this object was instantiated with a DOM Element or an XMLObject initially
145      */
146     private final boolean fromDOM;
147     
148     /**
149      * Constructor AssertionWrapper creates a new AssertionWrapper instance.
150      *
151      * @param element of type Element
152      * @throws UnmarshallingException when
153      */
154     public AssertionWrapper(Element element) throws WSSecurityException {
155         OpenSAMLUtil.initSamlEngine();
156         
157         parseElement(element);
158         fromDOM = true;
159     }
160 
161     /**
162      * Constructor AssertionWrapper creates a new AssertionWrapper instance.
163      *
164      * @param saml2 of type Assertion
165      */
166     public AssertionWrapper(org.opensaml.saml2.core.Assertion saml2) {
167         this((XMLObject)saml2);
168     }
169 
170     /**
171      * Constructor AssertionWrapper creates a new AssertionWrapper instance.
172      *
173      * @param saml1 of type Assertion
174      */
175     public AssertionWrapper(org.opensaml.saml1.core.Assertion saml1) {
176         this((XMLObject)saml1);
177     }
178 
179     /**
180      * Constructor AssertionWrapper creates a new AssertionWrapper instance.
181      * This is the primary constructor.  All other constructor calls should
182      * be routed to this method to ensure that the wrapper is initialized
183      * correctly.
184      *
185      * @param xmlObject of type XMLObject
186      */
187     public AssertionWrapper(XMLObject xmlObject) {
188         OpenSAMLUtil.initSamlEngine();
189         
190         this.xmlObject = xmlObject;
191         if (xmlObject instanceof org.opensaml.saml1.core.Assertion) {
192             this.saml1 = (org.opensaml.saml1.core.Assertion) xmlObject;
193             samlVersion = SAMLVersion.VERSION_11;
194         } else if (xmlObject instanceof org.opensaml.saml2.core.Assertion) {
195             this.saml2 = (org.opensaml.saml2.core.Assertion) xmlObject;
196             samlVersion = SAMLVersion.VERSION_20;
197         } else {
198             LOG.error(
199                 "AssertionWrapper: found unexpected type " 
200                 + (xmlObject != null ? xmlObject.getClass().getName() : null)
201             );
202         }
203         fromDOM = false;
204     }
205 
206     /**
207      * Constructor AssertionWrapper creates a new AssertionWrapper instance.
208      * This constructor is primarily called on the client side to initialize
209      * the wrapper from a configuration file. <br>
210      *
211      * @param parms of type SAMLParms
212      */
213     public AssertionWrapper(SAMLParms parms) throws WSSecurityException {
214         OpenSAMLUtil.initSamlEngine();
215         
216         //
217         // Create the SAML callback that the handler will use to get the required data from the 
218         // client application.
219         //
220         SAMLCallback[] samlCallbacks = new SAMLCallback[] { new SAMLCallback() };
221 
222         try {
223             // Get the SAML source data using the currently configured callback implementation.
224             samlCallbackHandler = parms.getCallbackHandler();
225             samlCallbackHandler.handle(samlCallbacks);
226         } catch (IOException e) {
227             throw new IllegalStateException(
228                 "IOException while creating SAML assertion wrapper", e
229             );
230         } catch (UnsupportedCallbackException e) {
231             throw new IllegalStateException(
232                 "UnsupportedCallbackException while creating SAML assertion wrapper", e
233             );
234         }
235         
236         // See if we already have a DOM element in SAMLCallback
237         if (samlCallbacks[0].getAssertionElement() != null) {
238             parseElement(samlCallbacks[0].getAssertionElement());
239             fromDOM = true;
240         } else {
241             // If not then parse the SAMLCallback object
242             parseCallback(samlCallbacks[0], parms);
243             fromDOM = false;
244         }
245     }
246 
247     /**
248      * Method getSaml1 returns the saml1 of this AssertionWrapper object.
249      *
250      * @return the saml1 (type Assertion) of this AssertionWrapper object.
251      */
252     public org.opensaml.saml1.core.Assertion getSaml1() {
253         return saml1;
254     }
255 
256     /**
257      * Method getSaml2 returns the saml2 of this AssertionWrapper object.
258      *
259      * @return the saml2 (type Assertion) of this AssertionWrapper object.
260      */
261     public org.opensaml.saml2.core.Assertion getSaml2() {
262         return saml2;
263     }
264 
265     /**
266      * Method getXmlObject returns the xmlObject of this AssertionWrapper object.
267      *
268      * @return the xmlObject (type XMLObject) of this AssertionWrapper object.
269      */
270     public XMLObject getXmlObject() {
271         return xmlObject;
272     }
273 
274     /**
275      * Method isCreated returns the created of this AssertionWrapper object.
276      *
277      * @return the created (type boolean) of this AssertionWrapper object.
278      */
279     public boolean isCreated() {
280         return saml1 != null || saml2 != null;
281     }
282 
283 
284     /**
285      * Create a DOM from the current XMLObject content. If the user-supplied doc is not null,
286      * reparent the returned Element so that it is compatible with the user-supplied document.
287      *
288      * @param doc of type Document
289      * @return Element
290      */
291     public Element toDOM(Document doc) throws WSSecurityException {
292         if (fromDOM && assertionElement != null) {
293             parseElement(assertionElement);
294             if (doc != null) {
295                 return (Element)doc.importNode(assertionElement, true);
296             }
297             return assertionElement;
298         }
299         assertionElement = OpenSAMLUtil.toDom(xmlObject, doc);
300         return assertionElement;
301     }
302 
303     /**
304      * Method assertionToString ...
305      *
306      * @return String
307      */
308     public String assertionToString() throws WSSecurityException {
309         if (assertionElement == null) {
310             Element element = toDOM(null);
311             return DOM2Writer.nodeToString(element);
312         }
313         return DOM2Writer.nodeToString(assertionElement);
314     }
315 
316     /**
317      * Method getId returns the id of this AssertionWrapper object.
318      *
319      * @return the id (type String) of this AssertionWrapper object.
320      */
321     public String getId() {
322         String id = null;
323         if (saml2 != null) {
324             id = saml2.getID();
325         } else if (saml1 != null) {
326             id = saml1.getID();
327         } else {
328             LOG.error("AssertionWrapper: unable to return ID - no saml assertion object");
329         }
330         if (id == null || id.length() == 0) {
331             LOG.error("AssertionWrapper: ID was null, seeting a new ID value");
332             id = "_" + UUIDGenerator.getUUID();
333             if (saml2 != null) {
334                 saml2.setID(id);
335             } else if (saml1 != null) {
336                 saml1.setID(id);
337             }
338         }
339         return id;
340     }
341 
342     /**
343      * Method getIssuerString returns the issuerString of this AssertionWrapper object.
344      *
345      * @return the issuerString (type String) of this AssertionWrapper object.
346      */
347     public String getIssuerString() {
348         if (saml2 != null && saml2.getIssuer() != null) {
349             return saml2.getIssuer().getValue();
350         } else if (saml1 != null) {
351             return saml1.getIssuer();
352         }
353         LOG.error(
354             "AssertionWrapper: unable to return Issuer string - no saml assertion "
355             + "object or issuer is null"
356         );
357         return null;
358     }
359 
360     /**
361      * Method getConfirmationMethods returns the confirmationMethods of this 
362      * AssertionWrapper object.
363      *
364      * @return the confirmationMethods of this AssertionWrapper object.
365      */
366     public List<String> getConfirmationMethods() {
367         List<String> methods = new ArrayList<String>();
368         if (saml2 != null) {
369             org.opensaml.saml2.core.Subject subject = saml2.getSubject();
370             List<org.opensaml.saml2.core.SubjectConfirmation> confirmations = 
371                 subject.getSubjectConfirmations();
372             for (org.opensaml.saml2.core.SubjectConfirmation confirmation : confirmations) {
373                 methods.add(confirmation.getMethod());
374             }
375         } else if (saml1 != null) {
376             List<SubjectStatement> subjectStatements = new ArrayList<SubjectStatement>();
377             subjectStatements.addAll(saml1.getSubjectStatements());
378             subjectStatements.addAll(saml1.getAuthenticationStatements());
379             subjectStatements.addAll(saml1.getAttributeStatements());
380             subjectStatements.addAll(saml1.getAuthorizationDecisionStatements());
381             for (SubjectStatement subjectStatement : subjectStatements) {
382                 Subject subject = subjectStatement.getSubject();
383                 if (subject != null) {
384                     SubjectConfirmation confirmation = subject.getSubjectConfirmation();
385                     if (confirmation != null) {
386                         XMLObject data = confirmation.getSubjectConfirmationData();
387                         if (data instanceof ConfirmationMethod) {
388                             ConfirmationMethod method = (ConfirmationMethod) data;
389                             methods.add(method.getConfirmationMethod());
390                         }
391                         List<ConfirmationMethod> confirmationMethods = 
392                             confirmation.getConfirmationMethods();
393                         for (ConfirmationMethod confirmationMethod : confirmationMethods) {
394                             methods.add(confirmationMethod.getConfirmationMethod());
395                         }
396                     }
397                 }
398             }
399         }
400         return methods;
401     }
402 
403     /**
404      * Method isSigned returns the signed of this AssertionWrapper object.
405      *
406      * @return the signed (type boolean) of this AssertionWrapper object.
407      */
408     public boolean isSigned() {
409         if (saml2 != null) {
410             return saml2.isSigned() || saml2.getSignature() != null;
411         } else if (saml1 != null) {
412             return saml1.isSigned() || saml1.getSignature() != null;
413         }
414         return false;
415     }
416 
417     /**
418      * Method setSignature sets the signature of this AssertionWrapper object.
419      *
420      * @param signature the signature of this AssertionWrapper object.
421      */
422     public void setSignature(Signature signature) {
423         if (xmlObject instanceof SignableSAMLObject) {
424             SignableSAMLObject signableObject = (SignableSAMLObject) xmlObject;
425             signableObject.setSignature(signature);
426             signableObject.releaseDOM();
427             signableObject.releaseChildrenDOM(true);
428         } else {
429             LOG.error("Attempt to sign an unsignable object " + xmlObject.getClass().getName());
430         }
431     }
432     
433     /**
434      * Create an enveloped signature on the assertion that has been created.
435      * 
436      * @param issuerKeyName the Issuer KeyName to use with the issuerCrypto argument
437      * @param issuerKeyPassword the Issuer Password to use with the issuerCrypto argument
438      * @param issuerCrypto the Issuer Crypto instance
439      * @param sendKeyValue whether to send the key value or not
440      * @throws WSSecurityException
441      */
442     public void signAssertion(String issuerKeyName, String issuerKeyPassword,
443             Crypto issuerCrypto, boolean sendKeyValue)
444             throws WSSecurityException {
445 
446         signAssertion(issuerKeyName, issuerKeyPassword, issuerCrypto,
447                 sendKeyValue, defaultCanonicalizationAlgorithm,
448                 defaultRSASignatureAlgorithm);
449     }
450     
451     /**
452      * Create an enveloped signature on the assertion that has been created.
453      * 
454      * @param issuerKeyName the Issuer KeyName to use with the issuerCrypto argument
455      * @param issuerKeyPassword the Issuer Password to use with the issuerCrypto argument
456      * @param issuerCrypto the Issuer Crypto instance
457      * @param sendKeyValue whether to send the key value or not
458      * @param canonicalizationAlgorithm the canonicalization algorithm to be used for signing
459      * @param signatureAlgorithm the signature algorithm to be used for signing
460      * @throws WSSecurityException
461      */
462     public void signAssertion(String issuerKeyName, String issuerKeyPassword,
463             Crypto issuerCrypto, boolean sendKeyValue,
464             String canonicalizationAlgorithm, String signatureAlgorithm)
465             throws WSSecurityException {
466         //
467         // Create the signature
468         //
469         Signature signature = OpenSAMLUtil.buildSignature();
470         signature.setCanonicalizationAlgorithm(canonicalizationAlgorithm);
471         LOG.debug("Using Canonicalization algorithm " + canonicalizationAlgorithm);
472         // prepare to sign the SAML token
473         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
474         cryptoType.setAlias(issuerKeyName);
475         X509Certificate[] issuerCerts = issuerCrypto.getX509Certificates(cryptoType);
476         if (issuerCerts == null) {
477             throw new WSSecurityException(
478                     "No issuer certs were found to sign the SAML Assertion using issuer name: "
479                             + issuerKeyName);
480         }
481 
482         String sigAlgo = signatureAlgorithm;
483         String pubKeyAlgo = issuerCerts[0].getPublicKey().getAlgorithm();
484         if (LOG.isDebugEnabled()) {
485             LOG.debug("automatic sig algo detection: " + pubKeyAlgo);
486         }
487         if (pubKeyAlgo.equalsIgnoreCase("DSA")) {
488             sigAlgo = defaultDSASignatureAlgorithm;
489         }
490         LOG.debug("Using Signature algorithm " + sigAlgo);
491         PrivateKey privateKey = null;
492         try {
493             privateKey = issuerCrypto.getPrivateKey(issuerKeyName, issuerKeyPassword);
494         } catch (Exception ex) {
495             throw new WSSecurityException(ex.getMessage(), ex);
496         }
497 
498         signature.setSignatureAlgorithm(sigAlgo);
499 
500         BasicX509Credential signingCredential = new BasicX509Credential();
501         signingCredential.setEntityCertificate(issuerCerts[0]);
502         signingCredential.setPrivateKey(privateKey);
503 
504         signature.setSigningCredential(signingCredential);
505 
506         X509KeyInfoGeneratorFactory kiFactory = new X509KeyInfoGeneratorFactory();
507         if (sendKeyValue) {
508             kiFactory.setEmitPublicKeyValue(true);
509         } else {
510             kiFactory.setEmitEntityCertificate(true);
511         }
512         try {
513             KeyInfo keyInfo = kiFactory.newInstance().generate(
514                     signingCredential);
515             signature.setKeyInfo(keyInfo);
516         } catch (org.opensaml.xml.security.SecurityException ex) {
517             throw new WSSecurityException(
518                     "Error generating KeyInfo from signing credential", ex);
519         }
520 
521         // add the signature to the assertion
522         setSignature(signature);
523     }
524 
525     /**
526      * Verify the signature of this assertion
527      *
528      * @throws ValidationException
529      */
530     public void verifySignature(
531         RequestData data, WSDocInfo docInfo
532     ) throws WSSecurityException {
533         Signature sig = null;
534         if (saml2 != null && saml2.getSignature() != null) {
535             sig = saml2.getSignature();
536         } else if (saml1 != null && saml1.getSignature() != null) {
537             sig = saml1.getSignature();
538         }
539         if (sig != null) {
540             KeyInfo keyInfo = sig.getKeyInfo();
541             SAMLKeyInfo samlKeyInfo = 
542                 SAMLUtil.getCredentialDirectlyFromKeyInfo(keyInfo.getDOM(), data);
543             verifySignature(samlKeyInfo);
544         } else {
545             LOG.debug("AssertionWrapper: no signature to validate");
546         }
547 
548     }
549     
550     /**
551      * Verify the signature of this assertion
552      *
553      * @throws ValidationException
554      */
555     public void verifySignature(SAMLKeyInfo samlKeyInfo) throws WSSecurityException {
556         Signature sig = getSignature();
557         if (sig != null) {
558             if (samlKeyInfo == null) {
559                 throw new WSSecurityException(
560                     WSSecurityException.FAILURE, "invalidSAMLsecurity",
561                     new Object[]{"cannot get certificate or key"}
562                 );
563             }
564             SAMLSignatureProfileValidator validator = new SAMLSignatureProfileValidator();
565             try {
566                 validator.validate(sig);
567             } catch (ValidationException ex) {
568                 throw new WSSecurityException("SAML signature validation failed", ex);
569             }
570             
571             BasicX509Credential credential = new BasicX509Credential();
572             if (samlKeyInfo.getCerts() != null) {
573                 credential.setEntityCertificate(samlKeyInfo.getCerts()[0]);
574             } else if (samlKeyInfo.getPublicKey() != null) {
575                 credential.setPublicKey(samlKeyInfo.getPublicKey());
576             } else {
577                 throw new WSSecurityException(
578                     WSSecurityException.FAILURE, "invalidSAMLsecurity",
579                     new Object[]{"cannot get certificate or key"}
580                 );
581             }
582             SignatureValidator sigValidator = new SignatureValidator(credential);
583             try {
584                 sigValidator.validate(sig);
585             } catch (ValidationException ex) {
586                 throw new WSSecurityException("SAML signature validation failed", ex);
587             }
588             signatureKeyInfo = samlKeyInfo;
589         } else {
590             LOG.debug("AssertionWrapper: no signature to validate");
591         }
592     }
593     
594     public Signature getSignature() {
595         Signature sig = null;
596         if (saml2 != null && saml2.getSignature() != null) {
597             sig = saml2.getSignature();
598         } else if (saml1 != null && saml1.getSignature() != null) {
599             sig = saml1.getSignature();
600         }
601         return sig;
602     }
603 
604     
605     /**
606      * This method parses the KeyInfo of the Subject for the holder-of-key confirmation
607      * method, as required by the SAML Token spec. It then stores the SAMLKeyInfo object that
608      * has been obtained for future processing by the SignatureProcessor.
609      * @throws WSSecurityException
610      */
611     public void parseHOKSubject(
612         RequestData data, WSDocInfo docInfo
613     ) throws WSSecurityException {
614         String confirmMethod = null;
615         List<String> methods = getConfirmationMethods();
616         if (methods != null && methods.size() > 0) {
617             confirmMethod = methods.get(0);
618         }
619         if (OpenSAMLUtil.isMethodHolderOfKey(confirmMethod)) {
620             if (saml1 != null) {
621                 subjectKeyInfo = 
622                     SAMLUtil.getCredentialFromSubject(saml1, data, docInfo, 
623                                                       data.getWssConfig().isWsiBSPCompliant());
624             } else if (saml2 != null) {
625                 subjectKeyInfo = 
626                     SAMLUtil.getCredentialFromSubject(saml2, data, docInfo, 
627                                                       data.getWssConfig().isWsiBSPCompliant());
628             }
629         }
630     }
631     
632 
633     /**
634      * Method getSamlVersion returns the samlVersion of this AssertionWrapper object.
635      *
636      * @return the samlVersion (type SAMLVersion) of this AssertionWrapper object.
637      */
638     public SAMLVersion getSamlVersion() {
639         if (samlVersion == null) {
640             // Try to set the version.
641             if (LOG.isDebugEnabled()) {
642                 LOG.debug(
643                     "The SAML version was null in getSamlVersion(). Recomputing SAML version..."
644                 );
645             }
646             if (saml1 != null && saml2 == null) {
647                 samlVersion = SAMLVersion.VERSION_11;
648             } else if (saml1 == null && saml2 != null) {
649                 samlVersion = SAMLVersion.VERSION_20;
650             } else {
651                 // We are only supporting SAML v1.1 or SAML v2.0 at this time.
652                 throw new IllegalStateException(
653                     "Could not determine the SAML version number. Check your "
654                     + "configuration and try again."
655                 );
656             }
657         }
658         return samlVersion;
659     }
660 
661     /**
662      * Get the Assertion as a DOM Element.
663      * @return the assertion as a DOM Element
664      */
665     public Element getElement() {
666         return assertionElement;
667     }
668     
669     /**
670      * Get the SAMLKeyInfo associated with the signature of the assertion
671      * @return the SAMLKeyInfo associated with the signature of the assertion
672      */
673     public SAMLKeyInfo getSignatureKeyInfo() {
674         return signatureKeyInfo;
675     }
676     
677     /**
678      * Get the SAMLKeyInfo associated with the Subject KeyInfo
679      * @return the SAMLKeyInfo associated with the Subject KeyInfo
680      */
681     public SAMLKeyInfo getSubjectKeyInfo() {
682         return subjectKeyInfo;
683     }
684     
685     /**
686      * Get the SignatureValue bytes of the signed SAML Assertion 
687      * @return the SignatureValue bytes of the signed SAML Assertion 
688      * @throws WSSecurityException
689      */
690     public byte[] getSignatureValue() throws WSSecurityException {
691         Signature sig = null;
692         if (saml2 != null && saml2.getSignature() != null) {
693             sig = saml2.getSignature();
694         } else if (saml1 != null && saml1.getSignature() != null) {
695             sig = saml1.getSignature();
696         }
697         if (sig != null) {
698             Element signatureElement = sig.getDOM();
699             
700             try {
701                 // Use XML-Security class to obtain SignatureValue
702                 XMLSignature xmlSignature = new XMLSignature(signatureElement, "");
703                 return xmlSignature.getSignatureValue();
704             } catch (XMLSignatureException e) {
705                 throw new WSSecurityException(
706                     WSSecurityException.FAILURE, "invalidSAMLsecurity", null, e
707                 );
708             } catch (XMLSecurityException e) {
709                 throw new WSSecurityException(
710                     WSSecurityException.FAILURE, "invalidSAMLsecurity", null, e
711                 );
712             }
713         }
714         return null;
715     }
716     
717     /**
718      * Parse the DOM Element into Opensaml objects.
719      */
720     private void parseElement(Element element) throws WSSecurityException {
721         this.xmlObject = OpenSAMLUtil.fromDom(element);
722         if (xmlObject instanceof org.opensaml.saml1.core.Assertion) {
723             this.saml1 = (org.opensaml.saml1.core.Assertion) xmlObject;
724             samlVersion = SAMLVersion.VERSION_11;
725         } else if (xmlObject instanceof org.opensaml.saml2.core.Assertion) {
726             this.saml2 = (org.opensaml.saml2.core.Assertion) xmlObject;
727             samlVersion = SAMLVersion.VERSION_20;
728         } else {
729             LOG.error(
730                 "AssertionWrapper: found unexpected type " 
731                 + (xmlObject != null ? xmlObject.getClass().getName() : xmlObject)
732             );
733         }
734         
735         assertionElement = element;
736     }
737     
738     /**
739      * Parse a SAMLCallback object to create a SAML Assertion
740      */
741     private void parseCallback(
742         SAMLCallback samlCallback, SAMLParms parms
743     ) throws WSSecurityException {
744         samlVersion = samlCallback.getSamlVersion();
745         if (samlVersion == null) {
746             samlVersion = parms.getSAMLVersion();
747         }
748         String issuer = samlCallback.getIssuer();
749         if (issuer == null && parms.getIssuer() != null) {
750             issuer = parms.getIssuer();
751         }
752         if (samlVersion.equals(SAMLVersion.VERSION_11)) {
753             // Build a SAML v1.1 assertion
754             saml1 = SAML1ComponentBuilder.createSamlv1Assertion(issuer);
755 
756             try {
757                 // Process the SAML authentication statement(s)
758                 List<AuthenticationStatement> authenticationStatements = 
759                     SAML1ComponentBuilder.createSamlv1AuthenticationStatement(
760                         samlCallback.getAuthenticationStatementData()
761                     );
762                 saml1.getAuthenticationStatements().addAll(authenticationStatements);
763     
764                 // Process the SAML attribute statement(s)            
765                 List<AttributeStatement> attributeStatements =
766                         SAML1ComponentBuilder.createSamlv1AttributeStatement(
767                             samlCallback.getAttributeStatementData()
768                         );
769                 saml1.getAttributeStatements().addAll(attributeStatements);
770     
771                 // Process the SAML authorization decision statement(s)
772                 List<AuthorizationDecisionStatement> authDecisionStatements =
773                         SAML1ComponentBuilder.createSamlv1AuthorizationDecisionStatement(
774                             samlCallback.getAuthDecisionStatementData()
775                         );
776                 saml1.getAuthorizationDecisionStatements().addAll(authDecisionStatements);
777     
778                 // Build the complete assertion
779                 org.opensaml.saml1.core.Conditions conditions = 
780                     SAML1ComponentBuilder.createSamlv1Conditions(samlCallback.getConditions());
781                 saml1.setConditions(conditions);
782             } catch (org.opensaml.xml.security.SecurityException ex) {
783                 throw new WSSecurityException(
784                     "Error generating KeyInfo from signing credential", ex
785                 );
786             }
787 
788             // Set the OpenSaml2 XMLObject instance
789             xmlObject = saml1;
790 
791         } else if (samlVersion.equals(SAMLVersion.VERSION_20)) {
792             // Build a SAML v2.0 assertion
793             saml2 = SAML2ComponentBuilder.createAssertion();
794             Issuer samlIssuer = SAML2ComponentBuilder.createIssuer(issuer);
795 
796             // Authn Statement(s)
797             List<AuthnStatement> authnStatements = 
798                 SAML2ComponentBuilder.createAuthnStatement(
799                     samlCallback.getAuthenticationStatementData()
800                 );
801             saml2.getAuthnStatements().addAll(authnStatements);
802 
803             // Attribute statement(s)
804             List<org.opensaml.saml2.core.AttributeStatement> attributeStatements = 
805                 SAML2ComponentBuilder.createAttributeStatement(
806                     samlCallback.getAttributeStatementData()
807                 );
808             saml2.getAttributeStatements().addAll(attributeStatements);
809 
810             // AuthzDecisionStatement(s)
811             List<AuthzDecisionStatement> authDecisionStatements =
812                     SAML2ComponentBuilder.createAuthorizationDecisionStatement(
813                         samlCallback.getAuthDecisionStatementData()
814                     );
815             saml2.getAuthzDecisionStatements().addAll(authDecisionStatements);
816 
817             // Build the SAML v2.0 assertion
818             saml2.setIssuer(samlIssuer);
819             
820             try {
821                 org.opensaml.saml2.core.Subject subject = 
822                     SAML2ComponentBuilder.createSaml2Subject(samlCallback.getSubject());
823                 saml2.setSubject(subject);
824             } catch (org.opensaml.xml.security.SecurityException ex) {
825                 throw new WSSecurityException(
826                     "Error generating KeyInfo from signing credential", ex
827                 );
828             }
829             
830             org.opensaml.saml2.core.Conditions conditions = 
831                 SAML2ComponentBuilder.createConditions(samlCallback.getConditions());
832             saml2.setConditions(conditions);
833 
834             // Set the OpenSaml2 XMLObject instance
835             xmlObject = saml2;
836         }
837     }
838 
839 }