001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.xml;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.security.pacl.permission.PortalRuntimePermission;
020    import com.liferay.portal.kernel.util.PropsKeys;
021    import com.liferay.portal.kernel.util.PropsUtil;
022    import com.liferay.portal.kernel.util.StringBundler;
023    import com.liferay.portal.kernel.util.StringPool;
024    
025    import java.io.File;
026    import java.io.InputStream;
027    import java.io.Reader;
028    
029    import java.net.MalformedURLException;
030    import java.net.URL;
031    
032    import java.util.List;
033    import java.util.Map;
034    
035    /**
036     * @author Brian Wing Shun Chan
037     */
038    public class SAXReaderUtil {
039    
040            public static Attribute createAttribute(
041                    Element element, QName qName, String value) {
042    
043                    return getSecureSAXReader().createAttribute(element, qName, value);
044            }
045    
046            public static Attribute createAttribute(
047                    Element element, String name, String value) {
048    
049                    return getSecureSAXReader().createAttribute(element, name, value);
050            }
051    
052            public static Document createDocument() {
053                    return getSecureSAXReader().createDocument();
054            }
055    
056            public static Document createDocument(Element rootElement) {
057                    return getSecureSAXReader().createDocument(rootElement);
058            }
059    
060            public static Document createDocument(String encoding) {
061                    return getSecureSAXReader().createDocument(encoding);
062            }
063    
064            public static Element createElement(QName qName) {
065                    return getSecureSAXReader().createElement(qName);
066            }
067    
068            public static Element createElement(String name) {
069                    return getSecureSAXReader().createElement(name);
070            }
071    
072            public static Entity createEntity(String name, String text) {
073                    return getSecureSAXReader().createEntity(name, text);
074            }
075    
076            public static Namespace createNamespace(String uri) {
077                    return getSecureSAXReader().createNamespace(uri);
078            }
079    
080            public static Namespace createNamespace(String prefix, String uri) {
081                    return getSecureSAXReader().createNamespace(prefix, uri);
082            }
083    
084            public static ProcessingInstruction createProcessingInstruction(
085                    String target, Map<String, String> data) {
086    
087                    return getSecureSAXReader().createProcessingInstruction(target, data);
088            }
089    
090            public static ProcessingInstruction createProcessingInstruction(
091                    String target, String data) {
092    
093                    return getSecureSAXReader().createProcessingInstruction(target, data);
094            }
095    
096            public static QName createQName(String localName) {
097                    return getSecureSAXReader().createQName(localName);
098            }
099    
100            public static QName createQName(String localName, Namespace namespace) {
101                    return getSecureSAXReader().createQName(localName, namespace);
102            }
103    
104            public static Text createText(String text) {
105                    return getSecureSAXReader().createText(text);
106            }
107    
108            public static XPath createXPath(String xPathExpression) {
109                    return getSecureSAXReader().createXPath(xPathExpression);
110            }
111    
112            public static XPath createXPath(
113                    String xPathExpression, Map<String, String> namespaceContextMap) {
114    
115                    return getSecureSAXReader().createXPath(
116                            xPathExpression, namespaceContextMap);
117            }
118    
119            public static XPath createXPath(
120                    String xPathExpression, String prefix, String namespace) {
121    
122                    return getSecureSAXReader().createXPath(
123                            xPathExpression, prefix, namespace);
124            }
125    
126            /**
127             * @deprecated As of 6.2.0, renamed to {@link #getSecureSAXReader}
128             */
129            public static SAXReader getSAXReader() {
130                    return getSecureSAXReader();
131            }
132    
133            public static SAXReader getSecureSAXReader() {
134                    PortalRuntimePermission.checkGetBeanProperty(SAXReaderUtil.class);
135    
136                    if (isCallerWhitelisted()) {
137                            return getUnsecureSAXReader();
138                    }
139    
140                    return _saxReader;
141            }
142    
143            public static SAXReader getUnsecureSAXReader() {
144                    PortalRuntimePermission.checkGetBeanProperty(
145                            SAXReaderUtil.class, "unsecureSAXReader");
146    
147                    return _unsecureSAXReader;
148            }
149    
150            public static Document read(File file) throws DocumentException {
151                    return getSecureSAXReader().read(file);
152            }
153    
154            public static Document read(File file, boolean validate)
155                    throws DocumentException {
156    
157                    return getSecureSAXReader().read(file, validate);
158            }
159    
160            public static Document read(InputStream is) throws DocumentException {
161                    return getSecureSAXReader().read(is);
162            }
163    
164            public static Document read(InputStream is, boolean validate)
165                    throws DocumentException {
166    
167                    return getSecureSAXReader().read(is, validate);
168            }
169    
170            public static Document read(Reader reader) throws DocumentException {
171                    return getSecureSAXReader().read(reader);
172            }
173    
174            public static Document read(Reader reader, boolean validate)
175                    throws DocumentException {
176    
177                    return getSecureSAXReader().read(reader, validate);
178            }
179    
180            public static Document read(String xml) throws DocumentException {
181                    return getSecureSAXReader().read(xml);
182            }
183    
184            public static Document read(String xml, boolean validate)
185                    throws DocumentException {
186    
187                    return getSecureSAXReader().read(xml, validate);
188            }
189    
190            public static Document read(String xml, XMLSchema xmlSchema)
191                    throws DocumentException {
192    
193                    return getSecureSAXReader().read(xml, xmlSchema);
194            }
195    
196            public static Document read(URL url) throws DocumentException {
197                    return getSecureSAXReader().read(url);
198            }
199    
200            public static Document read(URL url, boolean validate)
201                    throws DocumentException {
202    
203                    return getSecureSAXReader().read(url, validate);
204            }
205    
206            public static Document readURL(String url)
207                    throws DocumentException, MalformedURLException {
208    
209                    return getSecureSAXReader().readURL(url);
210            }
211    
212            public static Document readURL(String url, boolean validate)
213                    throws DocumentException, MalformedURLException {
214    
215                    return getSecureSAXReader().readURL(url, validate);
216            }
217    
218            public static List<Node> selectNodes(
219                    String xPathFilterExpression, List<Node> nodes) {
220    
221                    return getSecureSAXReader().selectNodes(xPathFilterExpression, nodes);
222            }
223    
224            public static List<Node> selectNodes(
225                    String xPathFilterExpression, Node node) {
226    
227                    return getSecureSAXReader().selectNodes(xPathFilterExpression, node);
228            }
229    
230            public static void sort(List<Node> nodes, String xPathExpression) {
231                    getSecureSAXReader().sort(nodes, xPathExpression);
232            }
233    
234            public static void sort(
235                    List<Node> nodes, String xPathExpression, boolean distinct) {
236    
237                    getSecureSAXReader().sort(nodes, xPathExpression, distinct);
238            }
239    
240            public void setSecureSAXReader(SAXReader saxReader) {
241                    PortalRuntimePermission.checkSetBeanProperty(getClass());
242    
243                    _saxReader = saxReader;
244            }
245    
246            public void setUnsecureSAXReader(SAXReader unsecureSAXReader) {
247                    PortalRuntimePermission.checkSetBeanProperty(
248                            getClass(), "unsecureSAXReader");
249    
250                    _unsecureSAXReader = unsecureSAXReader;
251            }
252    
253            protected static boolean isCallerWhitelisted() {
254                    StringBundler sb = new StringBundler(3);
255    
256                    Exception e = new Exception();
257    
258                    StackTraceElement[] stackTraceElements = e.getStackTrace();
259    
260                    StackTraceElement stackTraceElement = stackTraceElements[2];
261    
262                    String methodName = stackTraceElement.getMethodName();
263    
264                    if (!methodName.startsWith("read")) {
265                            return false;
266                    }
267    
268                    stackTraceElement = stackTraceElements[3];
269    
270                    sb.append(stackTraceElement.getClassName());
271                    sb.append(StringPool.POUND);
272                    sb.append(stackTraceElement.getMethodName());
273    
274                    String callerSignature = sb.toString();
275    
276                    for (String whitelistSignature : _XML_SECURITY_WHITELIST) {
277                            if (callerSignature.startsWith(whitelistSignature)) {
278                                    if (_log.isDebugEnabled()) {
279                                            _log.debug(
280                                                    "Unsecure SAX reader allowed for " + callerSignature +
281                                                            " based on the \"" + whitelistSignature +
282                                                                    "\" whitelist");
283                                    }
284    
285                                    return true;
286                            }
287                    }
288    
289                    if (_log.isDebugEnabled()) {
290                            _log.debug("Unsecure SAX reader disallowed for " + callerSignature);
291                    }
292    
293                    return false;
294            }
295    
296            private static Log _log = LogFactoryUtil.getLog(SAXReaderUtil.class);
297    
298            private static final String[] _XML_SECURITY_WHITELIST = PropsUtil.getArray(
299                    PropsKeys.XML_SECURITY_WHITELIST);
300    
301            private static SAXReader _saxReader;
302            private static SAXReader _unsecureSAXReader;
303    
304    }