src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/XMLUtils.java
changeset 59240 b3116877866f
parent 54731 81de17a33575
equal deleted inserted replaced
59239:9fe5d0d4e9c5 59240:b3116877866f
    21  * under the License.
    21  * under the License.
    22  */
    22  */
    23 package com.sun.org.apache.xml.internal.security.utils;
    23 package com.sun.org.apache.xml.internal.security.utils;
    24 
    24 
    25 import java.io.IOException;
    25 import java.io.IOException;
       
    26 import java.io.InputStream;
    26 import java.io.OutputStream;
    27 import java.io.OutputStream;
    27 import java.math.BigInteger;
    28 import java.math.BigInteger;
    28 import java.security.AccessController;
    29 import java.security.AccessController;
    29 import java.security.PrivilegedAction;
    30 import java.security.PrivilegedAction;
    30 import java.util.ArrayList;
    31 import java.util.ArrayList;
    31 import java.util.Base64;
    32 import java.util.Base64;
       
    33 import java.util.Collections;
    32 import java.util.HashSet;
    34 import java.util.HashSet;
    33 import java.util.Iterator;
    35 import java.util.Iterator;
    34 import java.util.List;
    36 import java.util.List;
       
    37 import java.util.Map;
       
    38 import java.util.Queue;
    35 import java.util.Set;
    39 import java.util.Set;
       
    40 import java.util.WeakHashMap;
       
    41 import java.util.concurrent.ArrayBlockingQueue;
    36 
    42 
    37 import javax.xml.parsers.DocumentBuilder;
    43 import javax.xml.parsers.DocumentBuilder;
    38 import javax.xml.parsers.DocumentBuilderFactory;
    44 import javax.xml.parsers.DocumentBuilderFactory;
    39 import javax.xml.parsers.ParserConfigurationException;
    45 import javax.xml.parsers.ParserConfigurationException;
    40 
    46 
    46 import org.w3c.dom.Element;
    52 import org.w3c.dom.Element;
    47 import org.w3c.dom.NamedNodeMap;
    53 import org.w3c.dom.NamedNodeMap;
    48 import org.w3c.dom.Node;
    54 import org.w3c.dom.Node;
    49 import org.w3c.dom.NodeList;
    55 import org.w3c.dom.NodeList;
    50 import org.w3c.dom.Text;
    56 import org.w3c.dom.Text;
       
    57 import org.xml.sax.InputSource;
       
    58 import org.xml.sax.SAXException;
    51 
    59 
    52 /**
    60 /**
    53  * DOM and XML accessibility and comfort functions.
    61  * DOM and XML accessibility and comfort functions.
    54  *
    62  *
    55  */
    63  */
    56 public final class XMLUtils {
    64 public final class XMLUtils {
    57 
    65 
    58     private static boolean ignoreLineBreaks =
    66     private static boolean ignoreLineBreaks =
    59         AccessController.doPrivileged(
    67         AccessController.doPrivileged(
    60             (PrivilegedAction<Boolean>) () -> Boolean.getBoolean("com.sun.org.apache.xml.internal.security.ignoreLineBreaks"));
    68             (PrivilegedAction<Boolean>) () -> Boolean.getBoolean("com.sun.org.apache.xml.internal.security.ignoreLineBreaks"));
       
    69     private static int parserPoolSize =
       
    70         AccessController.doPrivileged(
       
    71             (PrivilegedAction<Integer>) () -> Integer.getInteger("com.sun.org.apache.xml.internal.security.parser.pool-size", 20));
    61 
    72 
    62     private static volatile String dsPrefix = "ds";
    73     private static volatile String dsPrefix = "ds";
    63     private static volatile String ds11Prefix = "dsig11";
    74     private static volatile String ds11Prefix = "dsig11";
    64     private static volatile String xencPrefix = "xenc";
    75     private static volatile String xencPrefix = "xenc";
    65     private static volatile String xenc11Prefix = "xenc11";
    76     private static volatile String xenc11Prefix = "xenc11";
    66 
    77 
    67     private static final com.sun.org.slf4j.internal.Logger LOG =
    78     private static final com.sun.org.slf4j.internal.Logger LOG =
    68         com.sun.org.slf4j.internal.LoggerFactory.getLogger(XMLUtils.class);
    79         com.sun.org.slf4j.internal.LoggerFactory.getLogger(XMLUtils.class);
    69 
    80 
       
    81     private static final Map<ClassLoader, Queue<DocumentBuilder>> DOCUMENT_BUILDERS =
       
    82         Collections.synchronizedMap(new WeakHashMap<ClassLoader, Queue<DocumentBuilder>>());
       
    83 
       
    84     private static final Map<ClassLoader, Queue<DocumentBuilder>> DOCUMENT_BUILDERS_DISALLOW_DOCTYPE =
       
    85         Collections.synchronizedMap(new WeakHashMap<ClassLoader, Queue<DocumentBuilder>>());
    70 
    86 
    71     /**
    87     /**
    72      * Constructor XMLUtils
    88      * Constructor XMLUtils
    73      *
    89      *
    74      */
    90      */
   145     private static void getSetRec(final Node rootNode, final Set<Node> result,
   161     private static void getSetRec(final Node rootNode, final Set<Node> result,
   146                                 final Node exclude, final boolean com) {
   162                                 final Node exclude, final boolean com) {
   147         if (rootNode == exclude) {
   163         if (rootNode == exclude) {
   148             return;
   164             return;
   149         }
   165         }
   150         switch (rootNode.getNodeType()) {
   166         switch (rootNode.getNodeType()) { //NOPMD
   151         case Node.ELEMENT_NODE:
   167         case Node.ELEMENT_NODE:
   152             result.add(rootNode);
   168             result.add(rootNode);
   153             Element el = (Element)rootNode;
   169             Element el = (Element)rootNode;
   154             if (el.hasAttributes()) {
   170             if (el.hasAttributes()) {
   155                 NamedNodeMap nl = el.getAttributes();
   171                 NamedNodeMap nl = el.getAttributes();
   170                         return;
   186                         return;
   171                     }
   187                     }
   172                 }
   188                 }
   173                 getSetRec(r, result, exclude, com);
   189                 getSetRec(r, result, exclude, com);
   174             }
   190             }
   175             return;
   191             break;
   176         case Node.COMMENT_NODE:
   192         case Node.COMMENT_NODE:
   177             if (com) {
   193             if (com) {
   178                 result.add(rootNode);
   194                 result.add(rootNode);
   179             }
   195             }
   180             return;
   196             break;
   181         case Node.DOCUMENT_TYPE_NODE:
   197         case Node.DOCUMENT_TYPE_NODE:
   182             return;
   198             break;
   183         default:
   199         default:
   184             result.add(rootNode);
   200             result.add(rootNode);
   185         }
   201         }
   186     }
   202     }
   187 
       
   188 
   203 
   189     /**
   204     /**
   190      * Outputs a DOM tree to an {@link OutputStream}.
   205      * Outputs a DOM tree to an {@link OutputStream}.
   191      *
   206      *
   192      * @param contextNode root node of the DOM tree
   207      * @param contextNode root node of the DOM tree
   958             }
   973             }
   959         }
   974         }
   960         return true;
   975         return true;
   961     }
   976     }
   962 
   977 
   963     public static DocumentBuilder createDocumentBuilder(boolean validating)
   978     public static Document newDocument() throws ParserConfigurationException {
   964             throws ParserConfigurationException {
   979         ClassLoader loader = getContextClassLoader();
       
   980         if (loader == null) {
       
   981             loader = getClassLoader(XMLUtils.class);
       
   982         }
       
   983         // If the ClassLoader is null then just create a DocumentBuilder and use it
       
   984         if (loader == null) {
       
   985             DocumentBuilder documentBuilder = buildDocumentBuilder(true);
       
   986             return documentBuilder.newDocument();
       
   987         }
       
   988 
       
   989         Queue<DocumentBuilder> queue = getDocumentBuilderQueue(true, loader);
       
   990         DocumentBuilder documentBuilder = getDocumentBuilder(true, queue);
       
   991         Document doc = documentBuilder.newDocument();
       
   992         repoolDocumentBuilder(documentBuilder, queue);
       
   993         return doc;
       
   994     }
       
   995 
       
   996     public static Document read(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException {
       
   997         return read(inputStream, true);
       
   998     }
       
   999 
       
  1000     public static Document read(InputStream inputStream, boolean disAllowDocTypeDeclarations) throws ParserConfigurationException, SAXException, IOException {
       
  1001         ClassLoader loader = getContextClassLoader();
       
  1002         if (loader == null) {
       
  1003             loader = getClassLoader(XMLUtils.class);
       
  1004         }
       
  1005         // If the ClassLoader is null then just create a DocumentBuilder and use it
       
  1006         if (loader == null) {
       
  1007             DocumentBuilder documentBuilder = buildDocumentBuilder(disAllowDocTypeDeclarations);
       
  1008             return documentBuilder.parse(inputStream);
       
  1009         }
       
  1010 
       
  1011         Queue<DocumentBuilder> queue = getDocumentBuilderQueue(disAllowDocTypeDeclarations, loader);
       
  1012         DocumentBuilder documentBuilder = getDocumentBuilder(disAllowDocTypeDeclarations, queue);
       
  1013         Document doc = documentBuilder.parse(inputStream);
       
  1014         repoolDocumentBuilder(documentBuilder, queue);
       
  1015         return doc;
       
  1016     }
       
  1017 
       
  1018     public static Document read(String uri, boolean disAllowDocTypeDeclarations)
       
  1019         throws ParserConfigurationException, SAXException, IOException {
       
  1020         ClassLoader loader = getContextClassLoader();
       
  1021         if (loader == null) {
       
  1022             loader = getClassLoader(XMLUtils.class);
       
  1023         }
       
  1024         // If the ClassLoader is null then just create a DocumentBuilder and use it
       
  1025         if (loader == null) {
       
  1026             DocumentBuilder documentBuilder = buildDocumentBuilder(disAllowDocTypeDeclarations);
       
  1027             return documentBuilder.parse(uri);
       
  1028         }
       
  1029 
       
  1030         Queue<DocumentBuilder> queue = getDocumentBuilderQueue(disAllowDocTypeDeclarations, loader);
       
  1031         DocumentBuilder documentBuilder = getDocumentBuilder(disAllowDocTypeDeclarations, queue);
       
  1032         Document doc = documentBuilder.parse(uri);
       
  1033         repoolDocumentBuilder(documentBuilder, queue);
       
  1034         return doc;
       
  1035     }
       
  1036 
       
  1037     public static Document read(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {
       
  1038         return read(inputSource, true);
       
  1039     }
       
  1040 
       
  1041     public static Document read(InputSource inputSource, boolean disAllowDocTypeDeclarations)
       
  1042         throws ParserConfigurationException, SAXException, IOException {
       
  1043         ClassLoader loader = getContextClassLoader();
       
  1044         if (loader == null) {
       
  1045             loader = getClassLoader(XMLUtils.class);
       
  1046         }
       
  1047         // If the ClassLoader is null then just create a DocumentBuilder and use it
       
  1048         if (loader == null) {
       
  1049             DocumentBuilder documentBuilder = buildDocumentBuilder(disAllowDocTypeDeclarations);
       
  1050             return documentBuilder.parse(inputSource);
       
  1051         }
       
  1052 
       
  1053         Queue<DocumentBuilder> queue = getDocumentBuilderQueue(disAllowDocTypeDeclarations, loader);
       
  1054         DocumentBuilder documentBuilder = getDocumentBuilder(disAllowDocTypeDeclarations, queue);
       
  1055         Document doc = documentBuilder.parse(inputSource);
       
  1056         repoolDocumentBuilder(documentBuilder, queue);
       
  1057         return doc;
       
  1058     }
       
  1059 
       
  1060     /**
       
  1061      * @deprecated Use XMLUtils.read instead to directly read a document.
       
  1062      */
       
  1063     @Deprecated
       
  1064     public static DocumentBuilder createDocumentBuilder(boolean validating) throws ParserConfigurationException {
   965         return createDocumentBuilder(validating, true);
  1065         return createDocumentBuilder(validating, true);
   966     }
  1066     }
   967 
  1067 
   968     // The current implementation does not throw a ParserConfigurationException.
  1068     /**
   969     // Kept here in case we create the DocumentBuilder inline again.
  1069      * @deprecated Use XMLUtils.read instead to directly read a document.
       
  1070      */
       
  1071     @Deprecated
   970     public static DocumentBuilder createDocumentBuilder(
  1072     public static DocumentBuilder createDocumentBuilder(
   971         boolean validating, boolean disAllowDocTypeDeclarations
  1073         boolean validating, boolean disAllowDocTypeDeclarations
   972     ) throws ParserConfigurationException {
  1074     ) throws ParserConfigurationException {
   973         DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
  1075         DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
   974         dfactory.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
  1076         dfactory.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
   975         if (disAllowDocTypeDeclarations) {
  1077         if (disAllowDocTypeDeclarations) {
   976             dfactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
  1078             dfactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
   977         }
  1079         }
   978         dfactory.setValidating(validating);
  1080         dfactory.setValidating(validating);
   979         dfactory.setNamespaceAware(true);
  1081         dfactory.setNamespaceAware(true);
   980         return dfactory.newDocumentBuilder();
  1082         return dfactory.newDocumentBuilder();
   981     }
  1083     }
   982 
  1084 
   983     /**
  1085     /**
       
  1086      * @deprecated This method has no effect in Santuario 2.1.4
       
  1087      */
       
  1088     @Deprecated
       
  1089     public static boolean repoolDocumentBuilder(DocumentBuilder db) {
       
  1090         return true;
       
  1091     }
       
  1092 
       
  1093     /**
   984      * Returns a byte-array representation of a {@code {@link BigInteger}}.
  1094      * Returns a byte-array representation of a {@code {@link BigInteger}}.
   985      * No sign-bit is output.
  1095      * No sign-bit is output.
   986      *
  1096      *
   987      * <b>N.B.:</B> {@code {@link BigInteger}}'s toByteArray
  1097      * <b>N.B.:</B> {@code {@link BigInteger}}'s toByteArray
   988      * returns eventually longer arrays because of the leading sign-bit.
  1098      * returns eventually longer arrays because of the leading sign-bit.
  1022 
  1132 
  1023         System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, bigLen);
  1133         System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, bigLen);
  1024 
  1134 
  1025         return resizedBytes;
  1135         return resizedBytes;
  1026     }
  1136     }
       
  1137 
       
  1138     private static Queue<DocumentBuilder> getDocumentBuilderQueue(boolean disAllowDocTypeDeclarations, ClassLoader loader) throws ParserConfigurationException {
       
  1139         Map<ClassLoader, Queue<DocumentBuilder>> docBuilderCache =
       
  1140             disAllowDocTypeDeclarations ? DOCUMENT_BUILDERS_DISALLOW_DOCTYPE : DOCUMENT_BUILDERS;
       
  1141         Queue<DocumentBuilder> queue = docBuilderCache.get(loader);
       
  1142         if (queue == null) {
       
  1143             queue = new ArrayBlockingQueue<>(parserPoolSize);
       
  1144             docBuilderCache.put(loader, queue);
       
  1145         }
       
  1146 
       
  1147         return queue;
       
  1148     }
       
  1149 
       
  1150     private static DocumentBuilder getDocumentBuilder(boolean disAllowDocTypeDeclarations, Queue<DocumentBuilder> queue) throws ParserConfigurationException {
       
  1151         DocumentBuilder db = queue.poll();
       
  1152         if (db == null) {
       
  1153             db = buildDocumentBuilder(disAllowDocTypeDeclarations);
       
  1154         }
       
  1155         return db;
       
  1156     }
       
  1157 
       
  1158     private static DocumentBuilder buildDocumentBuilder(boolean disAllowDocTypeDeclarations) throws ParserConfigurationException {
       
  1159         DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
       
  1160         f.setNamespaceAware(true);
       
  1161         f.setFeature(javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING, true);
       
  1162         f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", disAllowDocTypeDeclarations);
       
  1163         return f.newDocumentBuilder();
       
  1164     }
       
  1165 
       
  1166     private static void repoolDocumentBuilder(DocumentBuilder db, Queue<DocumentBuilder> queue) {
       
  1167         if (queue != null) {
       
  1168             db.reset();
       
  1169             queue.offer(db);
       
  1170         }
       
  1171     }
       
  1172 
       
  1173     private static ClassLoader getContextClassLoader() {
       
  1174         final SecurityManager sm = System.getSecurityManager();
       
  1175         if (sm != null) {
       
  1176             return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
       
  1177                 public ClassLoader run() {
       
  1178                     return Thread.currentThread().getContextClassLoader();
       
  1179                 }
       
  1180             });
       
  1181         }
       
  1182         return Thread.currentThread().getContextClassLoader();
       
  1183     }
       
  1184 
       
  1185     private static ClassLoader getClassLoader(final Class<?> clazz) {
       
  1186         final SecurityManager sm = System.getSecurityManager();
       
  1187         if (sm != null) {
       
  1188             return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
       
  1189                 public ClassLoader run() {
       
  1190                     return clazz.getClassLoader();
       
  1191                 }
       
  1192             });
       
  1193         }
       
  1194         return clazz.getClassLoader();
       
  1195     }
       
  1196 
  1027 }
  1197 }