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 in
005: * compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://glassfish.dev.java.net/public/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 Notice in each file and include the License file
014: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
015: * If applicable, add the following below the CDDL Header,
016: * with the fields enclosed by brackets [] replaced by
017: * you own identifying information:
018: * "Portions Copyrighted [year] [name of copyright owner]"
019: *
020: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
021: */
022:
023: package com.sun.xml.wss.impl.dsig;
024:
025: import com.sun.xml.wss.core.reference.X509ThumbPrintIdentifier;
026: import com.sun.xml.wss.impl.FilterProcessingContext;
027: import com.sun.xml.wss.core.reference.X509SubjectKeyIdentifier;
028: import com.sun.xml.wss.logging.LogDomainConstants;
029: import com.sun.xml.wss.impl.MessageConstants;
030: import com.sun.xml.wss.impl.SecurableSoapMessage;
031: import com.sun.xml.wss.impl.XMLUtil;
032: import com.sun.xml.wss.XWSSecurityException;
033: import com.sun.xml.wss.impl.XWSSecurityRuntimeException;
034: import com.sun.xml.wss.core.ReferenceElement;
035: import com.sun.xml.wss.core.SecurityToken;
036: import com.sun.xml.wss.core.SecurityTokenReference;
037: import com.sun.xml.wss.core.X509SecurityToken;
038: import com.sun.xml.wss.core.reference.DirectReference;
039: import com.sun.xml.wss.core.reference.KeyIdentifier;
040: import com.sun.xml.wss.core.reference.X509IssuerSerial;
041: import com.sun.xml.wss.saml.AssertionUtil;
042:
043: import java.io.InputStream;
044: import java.lang.reflect.Constructor;
045: import java.math.BigInteger;
046: import java.security.cert.X509Certificate;
047: import java.util.Collections;
048: import java.util.HashMap;
049: import java.util.HashSet;
050: import java.util.Iterator;
051: import java.util.Set;
052: import java.util.logging.Logger;
053: import javax.xml.crypto.Data;
054: import javax.xml.crypto.NodeSetData;
055: import javax.xml.crypto.OctetStreamData;
056: import javax.xml.crypto.URIDereferencer;
057: import javax.xml.crypto.URIReference;
058: import javax.xml.crypto.URIReferenceException;
059: import javax.xml.crypto.XMLCryptoContext;
060: import javax.xml.crypto.dom.DOMURIReference;
061: import javax.xml.soap.AttachmentPart;
062: import javax.xml.soap.SOAPElement;
063: import javax.xml.soap.SOAPMessage;
064:
065: import org.w3c.dom.Attr;
066: import org.w3c.dom.DOMException;
067: import org.w3c.dom.Document;
068: import org.w3c.dom.Element;
069: import org.w3c.dom.NamedNodeMap;
070: import org.w3c.dom.Node;
071:
072: import com.sun.xml.wss.saml.Assertion;
073: import com.sun.xml.wss.saml.util.SAMLUtil;
074: import java.util.logging.Level;
075:
076: /**
077: * Implementation of JSR 105 URIDereference interface.
078: * @author <U><B>k.venugopal@sun.com</B></U>
079: */
080: public class DSigResolver implements URIDereferencer {
081:
082: private static volatile DSigResolver resolver = null;
083: private static Logger logger = Logger.getLogger(
084: LogDomainConstants.IMPL_SIGNATURE_DOMAIN,
085: LogDomainConstants.IMPL_SIGNATURE_DOMAIN_BUNDLE);
086:
087: private String optNSClassName = "org.jcp.xml.dsig.internal.dom.DOMSubTreeData";
088: private Class _nodeSetClass = null;
089: private Constructor _constructor = null;
090: private Boolean _false = Boolean.valueOf(false);
091:
092: /** Creates a new instance of DSigResolver */
093: private DSigResolver() {
094: try {
095: _nodeSetClass = Class.forName(optNSClassName);
096: _constructor = _nodeSetClass.getConstructor(new Class[] {
097: org.w3c.dom.Node.class, boolean.class });
098: } catch (LinkageError le) {
099: logger
100: .log(
101: Level.FINE,
102: "Not able load JSR 105 RI specific NodeSetData class ",
103: le);
104: } catch (ClassNotFoundException cne) {
105: logger
106: .log(
107: Level.FINE,
108: "Not able load JSR 105 RI specific NodeSetData class ",
109: cne);
110: } catch (NoSuchMethodException ne) {
111:
112: }
113: }
114:
115: /**
116: *
117: * @return URI Dereferencer instance.
118: */
119: public static URIDereferencer getInstance() {
120: if (resolver == null) {
121: init();
122: }
123: return resolver;
124: }
125:
126: private static void init() {
127: if (resolver == null) {
128: synchronized (DSigResolver.class) {
129: if (resolver == null) {
130: resolver = new DSigResolver();
131: }
132: }
133: }
134: }
135:
136: /**
137: * resolve the URI of type "cid:" , "attachmentRef:", "http:", "#xyz".
138: * @param uriRef {@inheritDoc}
139: * @param context{@inheritDoc}
140: * @throws URIReferenceException {@inheritDoc}
141: * @return {@inheritDoc}
142: */
143: public Data dereference(URIReference uriRef,
144: XMLCryptoContext context) throws URIReferenceException {
145: String uri = null;
146:
147: try {
148: if (uriRef instanceof DOMURIReference) {
149: DOMURIReference domRef = (DOMURIReference) uriRef;
150: Node node = domRef.getHere();
151: if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
152: uri = uriRef.getURI();
153: return dereferenceURI(uri, context);
154: } else if (node.getNodeType() == Node.ELEMENT_NODE) {
155: if ("SecurityTokenReference".equals(node
156: .getLocalName())) {
157: return derefSecurityTokenReference(node,
158: context);
159: }
160: }
161: } else {
162: uri = uriRef.getURI();
163: if (MessageConstants.debug) {
164: logger.log(Level.FINEST, "URI " + uri);
165: }
166: return dereferenceURI(uri, context);
167: }
168: } catch (XWSSecurityException ex) {
169: if (logger.getLevel() == Level.FINEST) {
170: logger.log(Level.FINEST,
171: "Error occurred while resolving" + uri, ex);
172: }
173: throw new URIReferenceException(ex.getMessage());
174: }
175: return null;
176: }
177:
178: Data dereferenceURI(String uri, XMLCryptoContext context)
179: throws URIReferenceException, XWSSecurityException {
180: FilterProcessingContext filterContext = (FilterProcessingContext) context
181: .get(MessageConstants.WSS_PROCESSING_CONTEXT);
182: SecurableSoapMessage secureMsg = filterContext
183: .getSecurableSoapMessage();
184: if (uri == null || uri.equals("")) {
185: SOAPMessage msg = filterContext.getSOAPMessage();
186: Document doc = msg.getSOAPPart();
187: if (_constructor == null) {
188: return convertToData((Node) doc, true);
189: } else {
190: try {
191: return (Data) _constructor
192: .newInstance(new Object[] { doc, _false });
193: } catch (Exception ex) {
194: //throw new XWSSecurityException(ex);
195: }
196: return convertToData((Node) doc, true);
197: }
198: } else if (uri.charAt(0) == '#') {
199: return dereferenceFragment(secureMsg
200: .getIdFromFragmentRef(uri), context);
201: } else if (uri.startsWith("cid:")
202: || uri.startsWith("attachmentRef:")) {
203: return dereferenceAttachments(uri, context);
204: } else if (uri.startsWith("http")) {
205: //throw new UnsupportedOperationException("Not yet supported ");
206: return dereferenceExternalResource(uri, context);
207: } else {
208: return dereferenceFragment(uri, context);
209: }
210: //throw new URIReferenceException("Resource "+uri+" was not found");
211: }
212:
213: Data dereferenceExternalResource(final String uri,
214: XMLCryptoContext context) throws URIReferenceException,
215: XWSSecurityException {
216:
217: URIDereferencer resolver = WSSPolicyConsumerImpl.getInstance()
218: .getDefaultResolver();
219: URIReference uriRef = null;
220: FilterProcessingContext filterContext = (FilterProcessingContext) context
221: .get(MessageConstants.WSS_PROCESSING_CONTEXT);
222: SecurableSoapMessage secureMsg = filterContext
223: .getSecurableSoapMessage();
224: final Attr uriAttr = secureMsg.getSOAPMessage().getSOAPPart()
225: .createAttribute("uri");
226: uriAttr.setNodeValue(uri);
227: uriRef = new DOMURIReference() {
228:
229: public String getURI() {
230: return uri;
231: }
232:
233: public String getType() {
234: return null;
235: }
236:
237: public Node getHere() {
238: return uriAttr;
239: }
240: };
241: try {
242: Data data = resolver.dereference(uriRef, context);
243:
244: if (MessageConstants.debug) {
245: if (data instanceof NodeSetData) {
246: logger.log(Level.FINE, "Node set Data");
247: } else if (data instanceof OctetStreamData) {
248: logger.log(Level.FINE, "Octet Data");
249: try {
250: InputStream is = ((OctetStreamData) data)
251: .getOctetStream();
252: int len = is.available();
253: byte[] bb = new byte[len];
254: is.read(bb);
255: logger.log(Level.FINE, "Data: "
256: + new String(bb));
257: } catch (Exception ex) {
258: logger.log(Level.FINE, "ERROR", ex);
259: }
260: }
261: }
262: return data;
263: } catch (URIReferenceException ue) {
264: logger
265: .log(Level.SEVERE, "WSS1325.dsig.externaltarget",
266: uri);
267: throw ue;
268: }
269:
270: }
271:
272: Data dereferenceAttachments(String uri, XMLCryptoContext context)
273: throws URIReferenceException, XWSSecurityException {
274: boolean sunAttachmentTransformProvider = true;
275: FilterProcessingContext filterContext = (FilterProcessingContext) context
276: .get(MessageConstants.WSS_PROCESSING_CONTEXT);
277:
278: SecurableSoapMessage secureMsg = filterContext
279: .getSecurableSoapMessage();
280: AttachmentPart attachment = secureMsg.getAttachmentPart(uri);
281: if (attachment == null) {
282: throw new URIReferenceException(
283: "Attachment Resource with Identifier " + uri
284: + " was not found");
285: }
286: if (sunAttachmentTransformProvider) {
287: AttachmentData attachData = new AttachmentData();
288: attachData.setAttachmentPart(attachment);
289: return attachData;
290: } else {
291: //Attachments need to be serialized and returned as OctectStreamData
292: //attachment.getDataHandler();
293: // new OctectStreamData();
294: throw new UnsupportedOperationException(
295: "Not yet supported ");
296: }
297: // throw new URIReferenceException("Attachment Resource with Identifier "+uri+" was not found");
298: }
299:
300: Data dereferenceFragment(String uri, XMLCryptoContext context)
301: throws URIReferenceException, XWSSecurityException {
302: FilterProcessingContext filterContext = (FilterProcessingContext) context
303: .get(MessageConstants.WSS_PROCESSING_CONTEXT);
304: HashMap elementCache = filterContext.getElementCache();
305: if (elementCache.size() > 0) {
306: Object obj = elementCache.get(uri);
307: if (obj != null) {
308: if (_constructor == null) {
309: return convertToData((Element) obj, true);
310: } else {
311: try {
312: return (Data) _constructor
313: .newInstance(new Object[] { obj, _false });
314: } catch (Exception ex) {
315: //throw new XWSSecurityException(ex);
316: }
317: }
318: return convertToData((Element) obj, true);
319: }
320: }
321: SecurableSoapMessage secureMsg = filterContext
322: .getSecurableSoapMessage();
323: Element element = secureMsg.getElementById(uri);
324: if (element == null) {
325: throw new URIReferenceException(
326: "Resource with fragment Identifier " + uri
327: + " was not found");
328: //log;
329: }
330: if (_constructor == null) {
331: return convertToData(element, true);
332: } else {
333: try {
334: return (Data) _constructor.newInstance(new Object[] {
335: element, _false });
336: } catch (Exception ex) {
337: //throw new XWSSecurityException(ex);
338: }
339: }
340: return convertToData(element, true);
341: }
342:
343: Data convertToData(final Node node, boolean xpathNodeSet) {
344: final HashSet nodeSet = new HashSet();
345: if (xpathNodeSet) {
346: toNodeSet(node, nodeSet);
347: return new NodeSetData() {
348: public Iterator iterator() {
349: return nodeSet.iterator();
350: }
351: };
352: } else {
353: return new NodeSetData() {
354: public Iterator iterator() {
355: return Collections.singletonList(node).iterator();
356:
357: }
358: };
359: }
360: }
361:
362: void toNodeSet(final Node rootNode, final Set result) {
363: //handle EKSHA1 under DKT
364: if (rootNode == null)
365: return;
366: switch (rootNode.getNodeType()) {
367: case Node.ELEMENT_NODE:
368: result.add(rootNode);
369: Element el = (Element) rootNode;
370: if (el.hasAttributes()) {
371: NamedNodeMap nl = ((Element) rootNode).getAttributes();
372: for (int i = 0; i < nl.getLength(); i++) {
373: result.add(nl.item(i));
374: }
375: }
376: //no return keep working
377: case Node.DOCUMENT_NODE:
378: for (Node r = rootNode.getFirstChild(); r != null; r = r
379: .getNextSibling()) {
380: if (r.getNodeType() == Node.TEXT_NODE) {
381: result.add(r);
382: while ((r != null)
383: && (r.getNodeType() == Node.TEXT_NODE)) {
384: r = r.getNextSibling();
385: }
386: if (r == null)
387: return;
388: }
389: toNodeSet(r, result);
390: }
391: return;
392: case Node.COMMENT_NODE:
393: return;
394: case Node.DOCUMENT_TYPE_NODE:
395: return;
396: default:
397: result.add(rootNode);
398: }
399: return;
400: }
401:
402: private Data derefSecurityTokenReference(Node element,
403: XMLCryptoContext context) throws XWSSecurityException,
404: URIReferenceException {
405: /**
406: * Four Cases:
407: * (1). Direct Reference
408: * (2). KeyIdentifier
409: * * X509 SubjectKeyIdentifier
410: * * SAML Assertion ID
411: * (3). Embedded Reference
412: * (4). X509 Issuer Serial
413: */
414: SecurityToken secToken = null;
415: FilterProcessingContext filterContext = (FilterProcessingContext) context
416: .get(MessageConstants.WSS_PROCESSING_CONTEXT);
417: SecurableSoapMessage secureMessage = filterContext
418: .getSecurableSoapMessage();
419: Document soapDocument = secureMessage.getSOAPPart();
420: SOAPElement soapElem = XMLUtil.convertToSoapElement(
421: soapDocument, (Element) element);
422: SecurityTokenReference tokenRef = new SecurityTokenReference(
423: soapElem);
424: ReferenceElement refElement = tokenRef.getReference();
425: HashMap tokenCache = filterContext.getTokenCache();
426: Element tokenElement = null;
427: Element newElement = null;
428:
429: if (refElement instanceof DirectReference) {
430: // isXMLToken = true;
431: /* Use the URI value to locate the BST */
432: String uri = ((DirectReference) refElement).getURI();
433: String tokenId = uri.substring(1);
434: secToken = (SecurityToken) tokenCache.get(tokenId);
435: if (secToken == null) {
436: tokenElement = secureMessage.getElementById(tokenId);
437: if (tokenElement == null) {
438: throw new URIReferenceException(
439: "Could not locate token with following ID"
440: + tokenId);
441: }
442:
443: } else {
444: tokenElement = secToken.getAsSoapElement();
445: }
446: newElement = (Element) element.getOwnerDocument()
447: .importNode(tokenElement, true);
448:
449: } else if (refElement instanceof KeyIdentifier) {
450: String valueType = ((KeyIdentifier) refElement)
451: .getValueType();
452: String keyId = ((KeyIdentifier) refElement)
453: .getReferenceValue();
454: if (MessageConstants.X509SubjectKeyIdentifier_NS
455: .equals(valueType)
456: || MessageConstants.X509v3SubjectKeyIdentifier_NS
457: .equals(valueType)) {
458: /* Use the Subject Key Identifier to locate BST */
459: // isXMLToken = false;
460: X509Certificate cert = null;
461:
462: Object token = tokenCache.get(keyId);
463: if (token instanceof X509SubjectKeyIdentifier) {
464: if (token != null) {
465: cert = ((X509SubjectKeyIdentifier) token)
466: .getCertificate();
467: }
468: }
469:
470: if (cert == null) {
471: cert = filterContext
472: .getSecurityEnvironment()
473: .getCertificate(
474: filterContext
475: .getExtraneousProperties(),
476: XMLUtil
477: .getDecodedBase64EncodedData(keyId));
478: }
479: secToken = new X509SecurityToken(soapDocument, cert);
480: tokenElement = secToken.getAsSoapElement();
481: newElement = tokenElement;
482: //(Element)element.getOwnerDocument().importNode(tokenElement, true);
483: try {
484: // EncodingType should not be set -
485: // As specified by WSS spec
486: newElement.removeAttribute("EncodingType");
487: } catch (DOMException de) {
488: //log.log(Level.SEVERE, "WSS0607.str.transform.exception");
489: throw new XWSSecurityRuntimeException(de
490: .getMessage(), de);
491: }
492: } else if (MessageConstants.ThumbPrintIdentifier_NS
493: .equals(valueType)) {
494: X509Certificate cert = null;
495:
496: Object token = tokenCache.get(keyId);
497: if (token instanceof X509ThumbPrintIdentifier) {
498: if (token != null) {
499: cert = ((X509ThumbPrintIdentifier) token)
500: .getCertificate();
501: }
502: }
503:
504: if (cert == null) {
505: cert = filterContext
506: .getSecurityEnvironment()
507: .getCertificate(
508: filterContext
509: .getExtraneousProperties(),
510: XMLUtil
511: .getDecodedBase64EncodedData(keyId),
512: MessageConstants.THUMB_PRINT_TYPE);
513: }
514: secToken = new X509SecurityToken(soapDocument, cert);
515: tokenElement = secToken.getAsSoapElement();
516: newElement = tokenElement;
517: //(Element)element.getOwnerDocument().importNode(tokenElement, true);
518: try {
519: // EncodingType should not be set -
520: // As specified by WSS spec
521: newElement.removeAttribute("EncodingType");
522: } catch (DOMException de) {
523: //log.log(Level.SEVERE, "WSS0607.str.transform.exception");
524: throw new XWSSecurityRuntimeException(de
525: .getMessage(), de);
526: }
527: } else if (MessageConstants.EncryptedKeyIdentifier_NS
528: .equals(valueType)) {
529: // do something here
530: newElement = null;
531: } else if (MessageConstants.WSSE_SAML_KEY_IDENTIFIER_VALUE_TYPE
532: .equals(valueType)
533: || MessageConstants.WSSE_SAML_v2_0_KEY_IDENTIFIER_VALUE_TYPE
534: .equals(valueType)) {
535:
536: //TODO : should we first try locating from the cache
537: if (tokenRef.getSamlAuthorityBinding() != null) {
538: tokenElement = filterContext
539: .getSecurityEnvironment()
540: .locateSAMLAssertion(
541: filterContext
542: .getExtraneousProperties(),
543: tokenRef.getSamlAuthorityBinding(),
544: keyId, secureMessage.getSOAPPart());
545: } else {
546: tokenElement = SAMLUtil.locateSamlAssertion(keyId,
547: secureMessage.getSOAPPart());
548: }
549: newElement = (Element) element.getOwnerDocument()
550: .importNode(tokenElement, true);
551:
552: Assertion assertion = null;
553: try {
554: assertion = AssertionUtil.fromElement(tokenElement);
555: } catch (Exception e) {
556: throw new XWSSecurityException(e);
557: }
558: tokenCache.put(keyId, assertion);
559:
560: } else {
561: try {
562: tokenElement = resolveSAMLToken(tokenRef, keyId,
563: filterContext);
564: } catch (Exception e) {
565: // ignore
566: }
567: if (tokenElement != null) {
568: newElement = (Element) element.getOwnerDocument()
569: .importNode(tokenElement, true);
570: } else {
571: //TODO : there can be a X509 KeyIdentifier without ValueType
572: // log.log(Level.SEVERE, "WSS0334.unsupported.keyidentifier");
573: XWSSecurityException xwsse = new XWSSecurityException(
574: "WSS_DSIG0008:unsupported KeyIdentifier Reference Type "
575: + valueType);
576: throw SecurableSoapMessage
577: .newSOAPFaultException(
578: MessageConstants.WSSE_INVALID_SECURITY_TOKEN,
579: xwsse.getMessage(), xwsse);
580: }
581: }
582:
583: } else if (refElement instanceof X509IssuerSerial) {
584: // isXMLToken = false;
585: BigInteger serialNumber = ((X509IssuerSerial) refElement)
586: .getSerialNumber();
587: String issuerName = ((X509IssuerSerial) refElement)
588: .getIssuerName();
589: X509Certificate cert = null;
590: Object token = tokenCache.get(issuerName + serialNumber);
591: if (token instanceof X509IssuerSerial) {
592: cert = ((X509IssuerSerial) token).getCertificate();
593: }
594:
595: if (cert == null) {
596: cert = filterContext
597: .getSecurityEnvironment()
598: .getCertificate(
599: filterContext.getExtraneousProperties(),
600: serialNumber, issuerName);
601: }
602: secToken = new X509SecurityToken(soapDocument, cert);
603: tokenElement = secToken.getAsSoapElement();
604: newElement = tokenElement;
605: //(Element)element.getOwnerDocument().importNode(tokenElement, true);
606: try {
607: // EncodingType should not be set - As specified by WSS spec
608: newElement.removeAttribute("EncodingType");
609: } catch (DOMException de) {
610: //log.log(Level.SEVERE,"WSS0607.str.transform.exception");
611: throw new XWSSecurityException(de.getMessage(), de);
612: }
613: } else {
614: /* log.log(Level.SEVERE,
615: "WSS0608.illegal.reference.mechanism");*/
616: throw new XWSSecurityException(
617: "Cannot handle reference mechanism: "
618: + refElement.getTagName());
619: }
620: Attr attr = element.getOwnerDocument().createAttributeNS(
621: MessageConstants.NAMESPACES_NS, "xmlns");
622: attr.setValue("");
623: if (newElement != null) {
624: newElement.setAttributeNodeNS(attr);
625: }
626: return convertToData(newElement, false);
627: }
628:
629: private static Element resolveSAMLToken(
630: SecurityTokenReference tokenRef, String assertionId,
631: FilterProcessingContext context)
632: throws XWSSecurityException {
633:
634: Assertion ret = (Assertion) context.getTokenCache().get(
635: assertionId);
636: if (ret != null) {
637: try {
638: return SAMLUtil.toElement(context
639: .getSecurableSoapMessage().getSOAPPart(), ret);
640: } catch (Exception e) {
641: throw new XWSSecurityException(e);
642: }
643: }
644:
645: Element tokenElement = null;
646: if (tokenRef.getSamlAuthorityBinding() != null) {
647: tokenElement = context.getSecurityEnvironment()
648: .locateSAMLAssertion(
649: context.getExtraneousProperties(),
650: tokenRef.getSamlAuthorityBinding(),
651: assertionId,
652: context.getSOAPMessage().getSOAPPart());
653: } else {
654: tokenElement = SAMLUtil.locateSamlAssertion(assertionId,
655: context.getSOAPMessage().getSOAPPart());
656: }
657:
658: try {
659: ret = AssertionUtil.fromElement(tokenElement);
660: } catch (Exception e) {
661: throw new XWSSecurityException(e);
662: }
663: context.getTokenCache().put(assertionId, ret);
664:
665: return tokenElement;
666: }
667:
668: }
|