All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.xml.wss.impl.XMLUtil Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package com.sun.xml.wss.impl;

import org.apache.xml.security.exceptions.Base64DecodingException;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.cert.X509Certificate;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import jakarta.xml.soap.SOAPElement;
import jakarta.xml.soap.SOAPException;
import jakarta.xml.soap.SOAPFactory;

import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;

import org.apache.xml.security.keys.content.X509Data;
import org.apache.xml.security.keys.content.keyvalues.DSAKeyValue;
import org.apache.xml.security.keys.content.keyvalues.RSAKeyValue;
import com.sun.xml.wss.impl.misc.Base64;
//import com.sun.org.apache.xpath.internal.XPathAPI;
import com.sun.xml.wss.WSITXMLFactory;
import com.sun.xml.wss.XWSSecurityException;
import com.sun.xml.wss.logging.LogDomainConstants;
import com.sun.xml.wss.logging.LogStringsMessages;
import java.net.MalformedURLException;

public final class XMLUtil {

    private XMLUtil() {}

    /**
     * This is a custom XML handler to load the dtds from the classpath
     * This should be used by all the xml parsing document builders to
     * set the default entity resolvers. This will avoid to have the
     * dtds having specified in a fixed directory  that will get replaced
     * during installation
     * This will need to specify the dtds as follows
     * jar://com/sun/identity/sm/sms.dtd
     * Bundle all the dtds along with the jar files and
     */

   protected static final Logger logger =  Logger.getLogger(
            LogDomainConstants.WSS_API_DOMAIN,LogDomainConstants.WSS_API_DOMAIN_BUNDLE);


    static class XMLHandler extends DefaultHandler {

        /**
         * This method reads the resource from a reader
         */
        String read(Reader aReader) {
            StringBuilder sb = new StringBuilder();

            try {
                BufferedReader bReader = new BufferedReader(aReader);
                char[] data = new char[2048];
                int count = 0;

                while ((count = bReader.read(data)) != -1) {
                    sb.append(data, 0, count);
                }

                //while loop
                bReader.close();
                aReader.close();
            } catch (IOException e) {
            }

            //try/catch
            return sb.toString();
        }

        /**
         * This method reads the resource from the classloader which load this class
         */
        String read(String fileName) {
            return read(fileName, XMLUtil.class);
        }

        /**
         * Reads the resource from a class loader.
         *
         * @param fileName resource to be read.
         * @param cl class which delegates the classloader functionality.
         * @return resource value.
         */
        String read(String fileName, Class cl) {
            String data = "";

           try {
                InputStream in = cl.getResourceAsStream(fileName);

                //may be absoulte file path is given
                if (in == null) {
                    try {
                        //works well if the user has given absolute path
                        in = new FileInputStream(fileName);
                    } catch (FileNotFoundException e) {
                        //works well if the user has given the relative path to the
                        //location of class file
                        String directoryURL = cl.getProtectionDomain()
                        .getCodeSource().getLocation()
                        .toString();
                        String fileURL = directoryURL + fileName;
                        URL url = new URL(fileURL);
                        in = url.openStream();
                    }
                }

                //if
                data = read(new InputStreamReader(in));
                in.close();
            }catch(MalformedURLException e) {
                //ignoring this as well
            } catch(IOException e) {
                //ignore
            }

            //try/catch
            return data;
        }
        @Override
        public InputSource resolveEntity(String aPublicID, String aSystemID) {
            String sysid = aSystemID.trim();

            if (sysid.toLowerCase().startsWith("jar://")) {
                String dtdname = sysid.substring(5);
                String dtdValue = read(dtdname).trim();

                return new InputSource(new StringReader(dtdValue));
            }

            return null;
        }
    }


    protected static SOAPFactory soapFactory;
    static {
        try {
            soapFactory = SOAPFactory.newInstance();
        } catch (SOAPException e) {

        }
    }



    private static boolean validating = false;

    /**
     * convertToSoapElement
     *
     * @param doc the Owner Soap Document of the SOAPElement to be returned
     * @param elem the DOM Element to be converted to SOAPElement
     * @return a SOAPElement whose parent node is null
     */
    public static SOAPElement convertToSoapElement(Document doc, Element elem)
    throws DOMException, ClassCastException {
        if (elem instanceof SOAPElement)
            return (SOAPElement) elem;
        return (SOAPElement) doc.importNode(elem, true);
    }

    /**
     * This method searches children of Element element for element with tagName
     * and namespaceURI nsName. It searchs one level down only.
     * @param element The root element
     * @param nsName NamespaceURI
     * @param tagName A String representing the name of the tag to be searched
     *                        for.
     * @return A List of elements that meet the criterial.
     */
    @SuppressWarnings("unchecked")
    public static List getElementsByTagNameNS1(Element element, String nsName,
    String tagName) {
        List list = new ArrayList();
        if (element != null) {
            NodeList nl = element.getChildNodes();
            int length = nl.getLength();
            Node child = null;
            String childName;
            String childNS;

            for (int i = 0; i < length; i++) {
                child = nl.item(i);
                childName = child.getLocalName();
                childNS = child.getNamespaceURI();

                if ((childName != null) && (childName.equals(tagName)) &&
                (childNS != null) && (childNS.equals(nsName))) {
                    list.add(child);
                }
            }
        }

        return list;
    }

    public static String getFullTextFromChildren(Element element) {
        if (element == null) {
            return null;
        }

        StringBuilder sb = new StringBuilder(1000);
        NodeList nl = element.getChildNodes();
        Node child = null;
        int length = nl.getLength();

        for (int i = 0; i < length; i++) {
            child = nl.item(i);

            if (child.getNodeType() == Node.TEXT_NODE) {
                sb.append(child.getNodeValue());
            }
        }

        return sb.toString().trim();
    }

    public static boolean inEncryptionNS(SOAPElement element) {
        return element.getNamespaceURI().equals(MessageConstants.XENC_NS);
    }

    public static boolean inSamlNSv1_0(SOAPElement element) {
        return element.getNamespaceURI().equals(MessageConstants.SAML_v1_0_NS);
    }

    public static boolean inSamlNSv2_0(SOAPElement element) {
        return element.getNamespaceURI().equals(MessageConstants.SAML_v2_0_NS);
    }

    public static boolean inSamlNSv1_1(SOAPElement element) {
        return element.getNamespaceURI().equals(MessageConstants.SAML_v1_1_NS);
    }

    public static boolean inSignatureNS(SOAPElement element) {
        return element.getNamespaceURI().equals(MessageConstants.DSIG_NS);
    }

    public static boolean inWsseNS(SOAPElement element) {
        return element.getNamespaceURI().equals(MessageConstants.WSSE_NS);
    }

    public static boolean inWsscNS(SOAPElement element) {
        return element.getNamespaceURI().equals(MessageConstants.WSSC_NS);
    }

    public static boolean inWsse11NS(SOAPElement element){
        return element.getNamespaceURI().equals(MessageConstants.WSSE11_NS);
    }

    public static boolean inWSS11_NS(SOAPElement element) {
        return element.getNamespaceURI().equals(MessageConstants.WSS11_SPEC_NS);
    }


    public static boolean inWsuNS(SOAPElement element) {
        return element.getNamespaceURI().equals(MessageConstants.WSU_NS);
    }

    public static String resolveXPath(Node element) throws Exception {
        if (element.getOwnerDocument() == null) {
            logger.log(Level.SEVERE,LogStringsMessages.WSS_0424_NULL_OWNER_DOCUMENT_ELEMENT());
            throw new Exception(
            "Element does not have an owner document");
        }
        StringBuilder xpath = new StringBuilder();
        String prefix = element.getPrefix();
        String lcname = element.getLocalName();
        String lxpath = prefix+":"+lcname;
        xpath.append(lxpath);
        Node parentNode = element.getParentNode();
        while (parentNode != null && parentNode.getNodeType() != Node.DOCUMENT_NODE) {
            prefix = parentNode.getPrefix();
            lcname = parentNode.getLocalName();
            lxpath = prefix+":"+lcname+"/";
            xpath.insert(0, lxpath);
            parentNode = parentNode.getParentNode();
        }
        xpath.insert(0, "./");
        return xpath.toString();
    }

    public static Element prependChildElement(
    Element parent,
    Element child,
    boolean addWhitespace,
    Document doc) {

        Node firstChild = parent.getFirstChild();
        if (firstChild == null) {
            parent.appendChild(child);
        } else {
            parent.insertBefore(child, firstChild);
        }

        if (addWhitespace) {
            Node whitespaceText = doc.createTextNode("\n");
            parent.insertBefore(whitespaceText, child);
        }
        return child;
    }

    public static Element prependChildElement(
    Element parent, Element child, Document doc) {
        return prependChildElement(parent, child, true, doc);
    }

    /**
     * Print a Node tree recursively.
     * @param node A DOM tree Node
     * @return An xml String representation of the DOM tree.
     */
    public static String print(Node node) {
        if (node == null) {
            return null;
        }

        StringBuilder xml = new StringBuilder(100);
        int type = node.getNodeType();

        switch (type) {
            // print element with attributes
            case Node.ELEMENT_NODE: {
                xml.append('<');
                xml.append(node.getNodeName());

                NamedNodeMap attrs = node.getAttributes();
                int length = attrs.getLength();

                for (int i = 0; i < length; i++) {
                    Attr attr = (Attr) attrs.item(i);
                    xml.append(' ');
                    xml.append(attr.getNodeName());
                    xml.append("=\"");

                    //xml.append(normalize(attr.getNodeValue()));
                    xml.append(attr.getNodeValue());
                    xml.append('"');
                }

                xml.append('>');

                NodeList children = node.getChildNodes();

                if (children != null) {
                    int len = children.getLength();

                    for (int i = 0; i < len; i++) {
                        xml.append(print(children.item(i)));
                    }
                }

                break;
            }

            // handle entity reference nodes
            case Node.ENTITY_REFERENCE_NODE: {
                NodeList children = node.getChildNodes();

                if (children != null) {
                    int len = children.getLength();

                    for (int i = 0; i < len; i++) {
                        xml.append(print(children.item(i)));
                    }
                }

                break;
            }

            // print cdata sections
            case Node.CDATA_SECTION_NODE: {
                xml.append("");

                break;
            }

            // print text
            case Node.TEXT_NODE: {
                //xml.append(normalize(node.getNodeValue()));
                xml.append(node.getNodeValue());

                break;
            }

            // print processing instruction
            case Node.PROCESSING_INSTRUCTION_NODE: {
                xml.append(" 0)) {
                    xml.append(' ');
                    xml.append(data);
                }

                xml.append("?>");

                break;
            }
        }

        if (type == Node.ELEMENT_NODE) {
            xml.append("');
        }

        return xml.toString();
    }

//    public static  Node selectSingleNode(
//    Node contextNode,
//    String xpath,
//    Element nsContext)
//    throws XWSSecurityException {
//
//        try {
//            return XPathAPI.selectSingleNode(contextNode, xpath, nsContext);
//        } catch (TransformerException e) {
//            logger.log(Level.SEVERE, "WSS0425.unableto.resolve.xpath",e);
//            throw new XWSSecurityException("Unable to resolve XPath", e);
//        }
//    }

    public static void setWsuIdAttr(Element element, String wsuId) {
        element.setAttributeNS(
        MessageConstants.NAMESPACES_NS,
        "xmlns:" + MessageConstants.WSU_PREFIX,
        MessageConstants.WSU_NS);
        element.setAttributeNS(
        MessageConstants.WSU_NS,
        MessageConstants.WSU_ID_QNAME,
        wsuId);
    }

     public static void setIdAttr(Element element, String Id) {
        element.setAttribute("Id", Id);
        element.setIdAttribute("Id", true);
    }

    /**
     * Converts the XML document from an input stream  to DOM Document format.
     *
     * @param is is the InputStream that contains XML document
     * @return Document is the DOM object obtained by parsing the input stream.
     *         Returns null if there are any parser errores.
     */
    public static Document toDOMDocument(InputStream is) {
        /* Constructing a DocumentBuilderFactory for every call is less expensive than a
           synchronizing a single instance of the factory and obtaining the builder
         */
        DocumentBuilderFactory dbFactory = null;

        try {
            // Assign new debug object
            dbFactory = WSITXMLFactory.createDocumentBuilderFactory(WSITXMLFactory.DISABLE_SECURE_PROCESSING);
            //new com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl();
            dbFactory.setValidating(validating);
            dbFactory.setNamespaceAware(true);
        } catch (Exception e) {
        }

        try {
            DocumentBuilder documentBuilder = dbFactory.newDocumentBuilder();

            if (documentBuilder == null) {
                return null;
            }

            documentBuilder.setEntityResolver(new XMLHandler());
            //XMLHandler());

            return documentBuilder.parse(is);
        } catch (Exception e) {
            // Since there may potentially be several invalid XML documents
            // that are mostly client-side errors, only a warning is logged for
            // efficiency reasons.
            return null;
        }
    }

    /**
     * Converts the XML document from a String format to DOM Document format.
     *
     * @param xmlString is the XML document in a String format
     * @return Document is the DOM object obtained by converting the String XML
     *         Returns null if xmlString is null.
     *               Returns null if there are any parser errores.
     */
    public static Document toDOMDocument(String xmlString) {
        if (xmlString == null) {
            return null;
        }

        ByteArrayInputStream is = new ByteArrayInputStream(xmlString.getBytes(
                StandardCharsets.UTF_8));

        return toDOMDocument(is);
    }

    /**
     * Obtains a new instance of a DOM Document object
     * @return a new instance of a DOM Document object
     * @exception ParserConfigurationException if an error occurs while constructing a new
     *                      document
     */
    public static Document newDocument() throws ParserConfigurationException {
        DocumentBuilderFactory dbFactory = WSITXMLFactory.createDocumentBuilderFactory(WSITXMLFactory.DISABLE_SECURE_PROCESSING);
        dbFactory.setNamespaceAware(true);
        dbFactory.setValidating(validating);

        return dbFactory.newDocumentBuilder().newDocument();
    }

    /**
     * Checks if a node has a child of ELEMENT type.
     * @param node a node
     * @return true if the node has a child of ELEMENT type
     */
    public static boolean hasElementChild(Node node) {
        NodeList nl = node.getChildNodes();
        Node child = null;
        int length = nl.getLength();

        for (int i = 0; i < length; i++) {
            child = nl.item(i);

            if (child.getNodeType() == Node.ELEMENT_NODE) {
                return true;
            }
        }

        return false;
    }

    public static DSAKeyValue getDSAKeyValue(
    Document doc, X509Certificate cert) throws XWSSecurityException {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("DSA");
            DSAPublicKeySpec dsaPkSpec =
                    keyFactory.getKeySpec(
                    cert.getPublicKey(), DSAPublicKeySpec.class);
            return
            new DSAKeyValue(
            doc,
            dsaPkSpec.getP(),
            dsaPkSpec.getQ(),
            dsaPkSpec.getG(),
            dsaPkSpec.getY());

        } catch (Exception e) {
            logger.log(Level.SEVERE,LogStringsMessages.WSS_0426_FAILED_DSA_KEY_VALUE(), e);
            throw new XWSSecurityException(e);
        }
    }

    public static RSAKeyValue getRSAKeyValue(
    Document doc, X509Certificate cert) throws XWSSecurityException {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPublicKeySpec rsaPkSpec =
                    keyFactory.getKeySpec(
                    cert.getPublicKey(), RSAPublicKeySpec.class);
            return
            new RSAKeyValue(
            doc,
            rsaPkSpec.getModulus(),
            rsaPkSpec.getPublicExponent()
            );

        } catch (Exception e) {
            logger.log(Level.SEVERE, LogStringsMessages.WSS_0293_FAILED_RSA_KEY_VALUE(), e);
            throw new XWSSecurityException(e);
        }
    }

    // The X509Certificate element, which contains
    // a base64-encoded [X509v3] certificate is added into the X509Data
    public static X509Data getX509Data(
    Document doc, X509Certificate cert) throws XWSSecurityException {
        try {
            X509Data x509Data = new X509Data(doc);
            x509Data.addCertificate(cert);
            return x509Data;
        } catch (Exception e) {
            logger.log(Level.SEVERE, LogStringsMessages.WSS_0294_FAILED_X_509_DATA(), e);
            throw new XWSSecurityException(e);
        }
    }

     // Looks up elements with wsu:Id or Id in xenc or dsig namespace.
     //
     // @param doc
     //@param id
     //
     //@return element
     //
     // @throws TransformerException
     //
//    public static Element getElementById(
//    Document doc,
//    String id)
//    throws TransformerException {
//
//        Element  selement = doc.getElementById(id);
//        if (selement != null) {
//            return selement;
//        }
//
//        Document sdoc = null;
//        if (doc instanceof SOAPDocumentImpl) {
//            sdoc = ((SOAPDocumentImpl)doc).getSOAPPart();
//        }
//        if (sdoc == null) {
//            sdoc = doc;
//        }
//
//        Element nscontext = XMLUtils.createDSctx(sdoc,
//            "wsu",
//            MessageConstants.WSU_NS);
//        Element element =
//            (Element) XPathAPI.selectSingleNode(
//                sdoc, "//*[@wsu:Id='" + id + "']", nscontext);
//
//        if (element == null) {
//            NodeList elems = XPathAPI.selectNodeList(
//            sdoc,
//            "//*[@Id='" + id + "']",
//            nscontext);
//            for (int i=0; i < elems.getLength(); i++) {
//                Element elem = (Element)elems.item(i);
//                String namespace = elem.getNamespaceURI();
//                if (namespace.equals(MessageConstants.DSIG_NS) ||
//                    namespace.equals(MessageConstants.XENC_NS) ||
//                    namespace.equals(MessageConstants.WSSE11_NS)) {
//                    element = elem;
//                    break;
//                }
//            }
//        }
//
//        // look for SAML AssertionID
//        if (element == null) {
//
//            /*NodeList assertions =
//                sdoc.getElementsByTagNameNS(MessageConstants.SAML_v1_0_NS,
//                    MessageConstants.SAML_ASSERTION_LNAME);*/
//            NodeList assertions = sdoc.getElementsByTagName(MessageConstants.SAML_ASSERTION_LNAME);
//            int len = assertions.getLength();
//            if (len > 0) {
//                for (int i=0; i < len; i++) {
//                    SOAPElement elem = (SOAPElement)assertions.item(i);
//                    String assertionId = elem.getAttribute(MessageConstants.SAML_ASSERTIONID_LNAME);
//                    String saml20Id = elem.getAttribute(MessageConstants.SAML_ID_LNAME);
//                    if (id.equals(assertionId) || id.equals(saml20Id)) {
//                        element = elem;
//                        break;
//                    }
//                }
//            }
//        }
//
//        return element;
//    }


    public static String convertToXpath(String qname) {
        QName name = QName.valueOf(qname);
        if ("".equals(name.getNamespaceURI())) {
            return "//" + name.getLocalPart();
        } else {
            return "//*[local-name()='"
            + name.getLocalPart()
            + "' and namespace-uri()='"
            + name.getNamespaceURI()
            + "']";
        }
    }

    public static byte[] getDecodedBase64EncodedData(String encodedData)throws XWSSecurityException {
        try {
            return Base64.decode(encodedData);
        } catch (Base64DecodingException e) {
            logger.log(Level.SEVERE, LogStringsMessages.WSS_0427_UNABLETO_DECODE_BASE_64(), e);
            throw new XWSSecurityException(
            "Unable to decode Base64 encoded data",
            e);
        }
    }

    public static Document getOwnerDocument(Node node) {
        if (node.getNodeType() == Node.DOCUMENT_NODE) {
            return (Document) node;
        } else {
            return node.getOwnerDocument();
        }
    }

    public static Element getFirstChildElement(Node node) {
        Node child = node.getFirstChild();
        while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
            child = child.getNextSibling();
        }
        return (Element) child;
    }

    public static Element createElement(Document doc, String tag, String nsURI,
        String prefix) {
        String qName = prefix == null ? tag : prefix + ":" + tag;
        return doc.createElementNS(nsURI, qName);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy