001: /*
002: * $Id: Assertion.java,v 1.11 2007/09/12 05:41:12 jdg6688 Exp $
003: */
004:
005: /*
006: * The contents of this file are subject to the terms
007: * of the Common Development and Distribution License
008: * (the License). You may not use this file except in
009: * compliance with the License.
010: *
011: * You can obtain a copy of the license at
012: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
013: * See the License for the specific language governing
014: * permissions and limitations under the License.
015: *
016: * When distributing Covered Code, include this CDDL
017: * Header Notice in each file and include the License file
018: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
019: * If applicable, add the following below the CDDL Header,
020: * with the fields enclosed by brackets [] replaced by
021: * you own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
025: */
026:
027: package com.sun.xml.wss.saml.assertion.saml20.jaxb20;
028:
029: //import com.sun.xml.wss.impl.dsig.DSigResolver;
030: import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
031: import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
032:
033: import com.sun.xml.wss.core.SecurityTokenReference;
034: import com.sun.xml.wss.impl.dsig.WSSPolicyConsumerImpl;
035: import com.sun.xml.wss.saml.SAMLException;
036: import com.sun.xml.wss.saml.util.SAMLUtil;
037: import com.sun.xml.wss.saml.internal.saml20.jaxb20.AssertionType;
038: import com.sun.xml.wss.saml.internal.saml20.jaxb20.NameIDType;
039: import java.util.GregorianCalendar;
040: import javax.xml.bind.JAXBElement;
041:
042: import javax.xml.datatype.DatatypeFactory;
043:
044: import java.lang.reflect.Constructor;
045: import java.security.PrivateKey;
046: import java.security.PublicKey;
047: import java.util.ArrayList;
048: import java.util.Collections;
049: import java.util.HashMap;
050: import java.util.HashSet;
051:
052: import java.util.List;
053:
054: import com.sun.xml.wss.logging.LogDomainConstants;
055: import com.sun.xml.wss.impl.XMLUtil;
056: import com.sun.xml.wss.impl.MessageConstants;
057: import com.sun.xml.wss.XWSSecurityException;
058: import com.sun.xml.wss.core.reference.X509SubjectKeyIdentifier;
059: import com.sun.xml.wss.saml.util.SAML20JAXBUtil;
060: import java.security.InvalidAlgorithmParameterException;
061: import java.security.NoSuchAlgorithmException;
062: import java.security.cert.X509Certificate;
063: import java.util.Map;
064:
065: import org.w3c.dom.Document;
066: import org.w3c.dom.Element;
067: import org.w3c.dom.NamedNodeMap;
068: import org.w3c.dom.Node;
069:
070: import javax.xml.bind.JAXBContext;
071: import java.util.Set;
072: import java.util.Iterator;
073: import java.util.logging.Logger;
074:
075: import javax.xml.crypto.*;
076: import javax.xml.crypto.dom.DOMStructure;
077: import javax.xml.crypto.dsig.*;
078: import javax.xml.crypto.dsig.dom.DOMSignContext;
079: import javax.xml.crypto.dsig.keyinfo.*;
080: import javax.xml.crypto.dsig.spec.*;
081: import javax.xml.soap.MessageFactory;
082: import javax.xml.soap.SOAPException;
083:
084: //import com.sun.xml.wss.saml.Assertion20;
085:
086: /**
087: * This object stands for <code>Assertion</code> element. An Assertion is a package
088: * of information that supplies one or more <code>Statement</code> made by an
089: * issuer. There are three kinds of assertions Au [java] <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
090: * [java] <Conditions NotBefore="2005-08-16T13:21:50.503+05:30" NotOnOrAfter="2005-08-16T15:21:50.504+05:30" xmlns="urn:oasis:names:tc:SAML:1.0:assertion"/>
091: * [java] <Subject xmlns="urn:oasis:names:tc:SAML:1.0:assertion">
092: * [java] <NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName">CN=SAML User,OU=SU,O=SAML
093: * User,L=Los Angeles,ST=CA,C=US</NameIdentifier>
094: * [java] <SubjectConfirmation>
095: * [java] <ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:sender-vouches</ConfirmationMethod>
096: * [java] </SubjectConfirmation>
097: * [java] </Subject>
098: * [java] <Attribute AttributeName="attribute1" AttributeNamespace="urn:com:sun:xml:wss:attribute" xmlns="urn:oasis:names:tc:SAML:1.0:assertion">
099: * [java] <AttributeValue>ATTRIBUTE1</AttributeValue>
100: * [java] </Attribute>
101: * thentication, Authorization
102: * Decision and Attribute assertion.
103: */
104: public class Assertion extends AssertionType implements
105: com.sun.xml.wss.saml.Assertion {
106:
107: private Element signedAssertion = null;
108: private NameIDType issuerValue = null;
109: private java.math.BigInteger majorValue = null;
110: private java.math.BigInteger minorValue = null;
111:
112: public Assertion(AssertionType assertion) {
113: this .setID(assertion.getID());
114: this .setIssueInstant(assertion.getIssueInstant());
115: this .setIssuer(assertion.getIssuer());
116: this .setAdvice(assertion.getAdvice());
117: this .setConditions(assertion.getConditions());
118: this .setSubject(assertion.getSubject());
119: this .setVersion(assertion.getVersion());
120: this .setSignature(assertion.getSignature());
121: this
122: .setStatement(assertion
123: .getStatementOrAuthnStatementOrAuthzDecisionStatement());
124: }
125:
126: protected static final Logger log = Logger.getLogger(
127: LogDomainConstants.WSS_API_DOMAIN,
128: LogDomainConstants.WSS_API_DOMAIN_BUNDLE);
129:
130: public java.math.BigInteger getMajorVersion() {
131: return this .majorValue;
132: }
133:
134: public java.math.BigInteger getMinorVersion() {
135: return this .minorValue;
136: }
137:
138: public void setMajorVersion(java.math.BigInteger majorValue) {
139: this .majorValue = majorValue;
140: }
141:
142: public void setMinorVersion(java.math.BigInteger minorValue) {
143: this .minorValue = minorValue;
144: }
145:
146: public String getAssertionID() {
147: return getID();
148: }
149:
150: public String getSamlIssuer() {
151: this .issuerValue = this .getIssuer();
152: return issuerValue.getValue();
153: }
154:
155: /**
156: * sign the saml assertion (Enveloped Signature)
157: * @param pubKey PublicKey to be used for Signature verification
158: * @param privKey PrivateKey to be used for Signature calculation
159: */
160:
161: public Element sign(PublicKey pubKey, PrivateKey privKey)
162: throws SAMLException {
163:
164: //Check if the signature is already calculated
165: if (signedAssertion != null) {
166: return signedAssertion;
167: }
168:
169: //Calculate the enveloped signature
170: try {
171:
172: XMLSignatureFactory fac = WSSPolicyConsumerImpl
173: .getInstance().getSignatureFactory();
174: return sign(fac.newDigestMethod(DigestMethod.SHA1, null),
175: SignatureMethod.RSA_SHA1, pubKey, privKey);
176:
177: } catch (Exception ex) {
178: // log here
179: throw new SAMLException(ex);
180: }
181: }
182:
183: public Element sign(X509Certificate cert, PrivateKey privKey)
184: throws SAMLException {
185: //Check if the signature is already calculated
186: if (signedAssertion != null) {
187: return signedAssertion;
188: }
189:
190: //Calculate the enveloped signature
191: try {
192:
193: XMLSignatureFactory fac = WSSPolicyConsumerImpl
194: .getInstance().getSignatureFactory();
195: return sign(fac.newDigestMethod(DigestMethod.SHA1, null),
196: SignatureMethod.RSA_SHA1, cert, privKey);
197:
198: } catch (Exception ex) {
199: // log here
200: throw new SAMLException(ex);
201: }
202: }
203:
204: /**
205: * sign the saml assertion (Enveloped Signature)
206: * @param digestMethod DigestMethod to be used
207: * @param signatureMethod SignatureMethod to be used.
208: * @param pubKey PublicKey to be used for Signature verification
209: * @param privKey PrivateKey to be used for Signature calculation
210: */
211:
212: public Element sign(DigestMethod digestMethod,
213: String signatureMethod, PublicKey pubKey, PrivateKey privKey)
214: throws SAMLException {
215:
216: //Check if the signature is already calculated
217: if (signedAssertion != null) {
218: return signedAssertion;
219: //return;
220: }
221:
222: //Calculate the enveloped signature
223: try {
224:
225: XMLSignatureFactory fac = WSSPolicyConsumerImpl
226: .getInstance().getSignatureFactory();
227: ArrayList transformList = new ArrayList();
228:
229: Transform tr1 = fac.newTransform(Transform.ENVELOPED,
230: (TransformParameterSpec) null);
231: Transform tr2 = fac.newTransform(
232: CanonicalizationMethod.EXCLUSIVE,
233: (TransformParameterSpec) null);
234: transformList.add(tr1);
235: transformList.add(tr2);
236:
237: String uri = "#" + this .getID();
238: Reference ref = fac.newReference(uri, digestMethod,
239: transformList, null, null);
240:
241: // Create the SignedInfo
242: SignedInfo si = fac.newSignedInfo(fac
243: .newCanonicalizationMethod(
244: CanonicalizationMethod.EXCLUSIVE,
245: (C14NMethodParameterSpec) null), fac
246: .newSignatureMethod(signatureMethod, null),
247: Collections.singletonList(ref));
248:
249: // Create a KeyValue containing the DSA PublicKey that was generated
250: KeyInfoFactory kif = fac.getKeyInfoFactory();
251: KeyValue kv = kif.newKeyValue(pubKey);
252:
253: // Create a KeyInfo and add the KeyValue to it
254: KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
255:
256: // Instantiate the document to be signed
257: Document doc = XMLUtil.newDocument();
258:
259: //Document document;
260:
261: //Element assertionElement = this.toElement(doc);
262: Element assertionElement = this .toElement(doc);
263: //try {
264: // DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
265: // DocumentBuilder builder = factory.newDocumentBuilder();
266: // document = builder.newDocument();
267: //} catch (Exception ex) {
268: // throw new XWSSecurityException("Unable to create Document : " + ex.getMessage());
269: //}
270:
271: //document.appendChild(assertionElement);
272: //doc.appendChild(assertionElement);
273:
274: // Create a DOMSignContext and specify the DSA PrivateKey and
275: // location of the resulting XMLSignature's parent element
276:
277: DOMSignContext dsc = new DOMSignContext(privKey,
278: assertionElement);
279: HashMap map = new HashMap();
280: map.put(this .getID(), assertionElement);
281:
282: dsc.setURIDereferencer(new DSigResolver(map,
283: assertionElement));
284: XMLSignature signature = fac.newXMLSignature(si, ki);
285: dsc.putNamespacePrefix(
286: "http://www.w3.org/2000/09/xmldsig#", "ds");
287:
288: // Marshal, generate (and sign) the enveloped signature
289: signature.sign(dsc);
290:
291: signedAssertion = assertionElement;
292: return assertionElement;
293: } catch (Exception ex) {
294: // log here
295: throw new SAMLException(ex);
296: }
297: //return signedAssertion;
298: }
299:
300: public Element sign(DigestMethod digestMethod,
301: String signatureMethod, X509Certificate cert,
302: PrivateKey privKey) throws SAMLException {
303: //Check if the signature is already calculated
304: if (signedAssertion != null) {
305: return signedAssertion;
306: //return;
307: }
308:
309: //Calculate the enveloped signature
310: try {
311: XMLSignatureFactory fac = WSSPolicyConsumerImpl
312: .getInstance().getSignatureFactory();
313: ArrayList transformList = new ArrayList();
314:
315: Transform tr1 = fac.newTransform(Transform.ENVELOPED,
316: (TransformParameterSpec) null);
317: Transform tr2 = fac.newTransform(
318: CanonicalizationMethod.EXCLUSIVE,
319: (TransformParameterSpec) null);
320: transformList.add(tr1);
321: transformList.add(tr2);
322:
323: String uri = "#" + this .getID();
324: Reference ref = fac.newReference(uri, digestMethod,
325: transformList, null, null);
326:
327: // Create the SignedInfo
328: SignedInfo si = fac.newSignedInfo(fac
329: .newCanonicalizationMethod(
330: CanonicalizationMethod.EXCLUSIVE,
331: (C14NMethodParameterSpec) null), fac
332: .newSignatureMethod(signatureMethod, null),
333: Collections.singletonList(ref));
334:
335: // Instantiate the document to be signed
336: Document doc = MessageFactory.newInstance().createMessage()
337: .getSOAPPart();
338: KeyInfoFactory kif = fac.getKeyInfoFactory();
339: KeyInfo ki = null;
340: byte[] skid = X509SubjectKeyIdentifier
341: .getSubjectKeyIdentifier(cert);
342: if (skid != null) {
343: X509SubjectKeyIdentifier keyIdentifier = new X509SubjectKeyIdentifier(
344: doc);
345: keyIdentifier.setCertificate(cert);
346: keyIdentifier.setReferenceValue(Base64.encode(skid));
347: SecurityTokenReference str = new SecurityTokenReference();
348: str.setReference(keyIdentifier);
349: DOMStructure domKeyInfo = new DOMStructure(str
350: .getAsSoapElement());
351: ki = kif.newKeyInfo(Collections
352: .singletonList(domKeyInfo));
353: } else {
354: X509Data x509Data = kif.newX509Data(Collections
355: .singletonList(cert));
356: ki = kif
357: .newKeyInfo(Collections.singletonList(x509Data));
358: }
359: /* KeyIdentifier kid = new KeyIdentifierImpl(MessageConstants.X509SubjectKeyIdentifier_NS, MessageConstants.MessageConstants.BASE64_ENCODING_NS);
360: kid.setValue(Base64.encode(X509SubjectKeyIdentifier.getSubjectKeyIdentifier(cert)));
361: SecurityTokenReference str = new SecurityTokenReferenceImpl(kid);*/
362: Element assertionElement = this .toElement(doc);
363: //try {
364: // DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
365: // DocumentBuilder builder = factory.newDocumentBuilder();
366: // document = builder.newDocument();
367: //} catch (Exception ex) {
368: // throw new XWSSecurityException("Unable to create Document : " + ex.getMessage());
369: //}
370: //document.appendChild(assertionElement);
371: //doc.appendChild(assertionElement);
372:
373: // Create a DOMSignContext and specify the DSA PrivateKey and
374: // location of the resulting XMLSignature's parent element
375: DOMSignContext dsc = new DOMSignContext(privKey,
376: assertionElement);
377: HashMap map = new HashMap();
378: map.put(this .getID(), assertionElement);
379:
380: dsc.setURIDereferencer(new DSigResolver(map,
381: assertionElement));
382: XMLSignature signature = fac.newXMLSignature(si, ki);
383: dsc.putNamespacePrefix(
384: "http://www.w3.org/2000/09/xmldsig#", "ds");
385:
386: // Marshal, generate (and sign) the enveloped signature
387: signature.sign(dsc);
388:
389: signedAssertion = assertionElement;
390: return assertionElement;
391: } catch (XWSSecurityException ex) {
392: throw new SAMLException(ex);
393: } catch (MarshalException ex) {
394: throw new SAMLException(ex);
395: } catch (NoSuchAlgorithmException ex) {
396: throw new SAMLException(ex);
397: } catch (SOAPException ex) {
398: throw new SAMLException(ex);
399: } catch (XMLSignatureException ex) {
400: throw new SAMLException(ex);
401: } catch (InvalidAlgorithmParameterException ex) {
402: throw new SAMLException(ex);
403: }
404: }
405:
406: public Element toElement(Node doc) throws XWSSecurityException {
407: if (signedAssertion == null) {
408: signedAssertion = SAMLUtil.toElement(doc, this );
409: if (signedAssertion == null) {
410: return signedAssertion;
411: }
412: if (System.getProperty("com.sun.xml.wss.saml.binding.jaxb") == null) {
413: signedAssertion.setAttributeNS(
414: NamespaceContext.XMLNS_URI, "xmlns:xs",
415: MessageConstants.XSD_NS);
416: }
417: }
418: return signedAssertion;
419: }
420:
421: public boolean isSigned() {
422: return signature != null ? true : false;
423: }
424:
425: /**
426: * This constructor is used to build <code>Assertion</code> object from a
427: * block of existing XML that has already been built into a DOM.
428: *
429: * @param assertionElement A <code>org.w3c.dom.Element</code> representing
430: * DOM tree for <code>Assertion</code> object
431: * @exception SAMLException if it could not process the Element properly,
432: * implying that there is an error in the sender or in the
433: * element definition.
434: */
435: public static Assertion fromElement(org.w3c.dom.Element element)
436: throws SAMLException {
437: try {
438: JAXBContext jc = SAML20JAXBUtil.getJAXBContext();
439:
440: javax.xml.bind.Unmarshaller u = jc.createUnmarshaller();
441: Object el = u.unmarshal(element);
442: //return new Assertion((AssertionType)u.unmarshal(element));
443: return new Assertion((AssertionType) ((JAXBElement) el)
444: .getValue());
445: } catch (Exception ex) {
446: // log here
447: throw new SAMLException(ex);
448: }
449: }
450:
451: private void setStatement(List statement) {
452: this .statementOrAuthnStatementOrAuthzDecisionStatement = statement;
453: }
454:
455: public String getType() {
456: return MessageConstants.SAML_v2_0_NS;
457: }
458:
459: public Object getTokenValue() {
460: //TODO: Implement this method
461: return null;
462: }
463:
464: /**
465: * This constructor is used to populate the data members: the
466: * <code>assertionID</code>, the issuer, time when assertion issued,
467: * the conditions when creating a new assertion , <code>Advice</code>
468: * applicable to this <code>Assertion</code> and a set of
469: * <code>Statement</code>(s) in the assertion.
470: *
471: * @param assertionID <code>AssertionID</code> object contained within this
472: * <code>Assertion</code> if null its generated internally.
473: * @param issuer The issuer of this assertion.
474: * @param issueInstant Time instant of the issue. It has type
475: * <code>dateTime</code> which is built in to the W3C XML Schema
476: * Types specification. if null, current time is used.
477: * @param conditions <code>Conditions</code> under which the this
478: * <code>Assertion</code> is valid.
479: * @param advice <code>Advice</code> applicable for this
480: * <code>Assertion</code>.
481: * @param statements List of <code>Statement</code> objects within this
482: * <code>Assertion</code>. It could be of type
483: * <code>AuthenticationStatement</code>,
484: * <code>AuthorizationDecisionStatement</code> and
485: * <code>AttributeStatement</code>. Each Assertion can have
486: * multiple type of statements in it.
487: * @exception SAMLException if there is an error in processing input.
488: */
489: public Assertion(String assertionID, NameID issuer,
490: GregorianCalendar issueInstant, Conditions conditions,
491: Advice advice, Subject subject, List statements)
492: throws SAMLException {
493: if (assertionID != null)
494: setID(assertionID);
495:
496: if (issuer != null)
497: setIssuer(issuer);
498:
499: if (issueInstant != null) {
500: try {
501: DatatypeFactory factory = DatatypeFactory.newInstance();
502: setIssueInstant(factory
503: .newXMLGregorianCalendar(issueInstant));
504: } catch (Exception e) {
505: //ignore
506: }
507: }
508:
509: if (conditions != null)
510: setConditions(conditions);
511:
512: if (advice != null)
513: setAdvice(advice);
514:
515: if (statements != null)
516: setStatement(statements);
517:
518: if (subject != null)
519: setSubject(subject);
520:
521: setVersion("20");
522: }
523:
524: private static class DSigResolver implements URIDereferencer {
525: //TODO : Convert DSigResolver to singleton class.
526: Element elem = null;
527: Map map = null;
528: Class _nodeSetClass = null;
529: String optNSClassName = "org.jcp.xml.dsig.internal.dom.DOMSubTreeData";
530: Constructor _constructor = null;
531: Boolean _false = Boolean.valueOf(false);
532:
533: DSigResolver(Map map, Element elem) {
534: this .elem = elem;
535: this .map = map;
536: init();
537: }
538:
539: void init() {
540: try {
541: _nodeSetClass = Class.forName(optNSClassName);
542: _constructor = _nodeSetClass
543: .getConstructor(new Class[] {
544: org.w3c.dom.Node.class, boolean.class });
545: } catch (LinkageError le) {
546: // logger.log (Level.FINE,"Not able load JSR 105 RI specific NodeSetData class ",le);
547: } catch (ClassNotFoundException cne) {
548: // logger.log (Level.FINE,"Not able load JSR 105 RI specific NodeSetData class ",cne);
549: } catch (NoSuchMethodException ne) {
550:
551: }
552: }
553:
554: public Data dereference(URIReference uriRef,
555: XMLCryptoContext context) throws URIReferenceException {
556: try {
557: String uri = null;
558: uri = uriRef.getURI();
559: return dereferenceURI(uri, context);
560: } catch (Exception ex) {
561: // log here
562: throw new URIReferenceException(ex);
563: }
564: }
565:
566: Data dereferenceURI(String uri, XMLCryptoContext context)
567: throws URIReferenceException {
568: if (uri.charAt(0) == '#') {
569: uri = uri.substring(1, uri.length());
570: Element el = elem.getOwnerDocument()
571: .getElementById(uri);
572: if (el == null) {
573: el = (Element) map.get(uri);
574: }
575:
576: if (_constructor != null) {
577: try {
578: return (Data) _constructor
579: .newInstance(new Object[] { el, _false });
580: } catch (Exception ex) {
581: // TODO: igonore this ?
582: ex.printStackTrace();
583: }
584: } else {
585: final HashSet nodeSet = new HashSet();
586: toNodeSet(el, nodeSet);
587: return new NodeSetData() {
588: public Iterator iterator() {
589: return nodeSet.iterator();
590: }
591: };
592: }
593:
594: }
595:
596: return null;
597: //throw new URIReferenceException("Resource "+uri+" was not found");
598: }
599:
600: void toNodeSet(final Node rootNode, final Set result) {
601: switch (rootNode.getNodeType()) {
602: case Node.ELEMENT_NODE:
603: result.add(rootNode);
604: Element el = (Element) rootNode;
605: if (el.hasAttributes()) {
606: NamedNodeMap nl = ((Element) rootNode)
607: .getAttributes();
608: for (int i = 0; i < nl.getLength(); i++) {
609: result.add(nl.item(i));
610: }
611: }
612: //no return keep working
613: case Node.DOCUMENT_NODE:
614: for (Node r = rootNode.getFirstChild(); r != null; r = r
615: .getNextSibling()) {
616: if (r.getNodeType() == Node.TEXT_NODE) {
617: result.add(r);
618: while ((r != null)
619: && (r.getNodeType() == Node.TEXT_NODE)) {
620: r = r.getNextSibling();
621: }
622: if (r == null)
623: return;
624: }
625: toNodeSet(r, result);
626: }
627: return;
628: case Node.COMMENT_NODE:
629: return;
630: case Node.DOCUMENT_TYPE_NODE:
631: return;
632: default:
633: result.add(rootNode);
634: }
635: return;
636: }
637:
638: }
639: }
|