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