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 */ |
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 } |