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