001    /**
002     * Copyright (c) 2000-2012 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.security.pacl.checker;
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.PACLConstants;
020    import com.liferay.portal.kernel.util.PathUtil;
021    import com.liferay.portal.kernel.util.ServerDetector;
022    import com.liferay.portal.kernel.util.Validator;
023    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
024    import com.liferay.portal.security.pacl.PACLClassUtil;
025    import com.liferay.portal.security.pacl.PACLPolicy;
026    import com.liferay.portal.util.PortalImpl;
027    import com.liferay.portal.util.PortalUtil;
028    
029    import java.util.Properties;
030    import java.util.Set;
031    
032    import sun.reflect.Reflection;
033    
034    /**
035     * @author Brian Wing Shun Chan
036     * @author Raymond Augé
037     */
038    public abstract class BaseChecker implements Checker, PACLConstants {
039    
040            public BaseChecker() {
041                    ClassLoader portalClassLoader = BaseChecker.class.getClassLoader();
042    
043                    _portalClassLoader = portalClassLoader;
044                    _commonClassLoader = portalClassLoader.getParent();
045                    _systemClassLoader = ClassLoader.getSystemClassLoader();
046            }
047    
048            public ClassLoader getClassLoader() {
049                    return _paclPolicy.getClassLoader();
050            }
051    
052            public ClassLoader getCommonClassLoader() {
053                    return _commonClassLoader;
054            }
055    
056            public PACLPolicy getPACLPolicy() {
057                    return _paclPolicy;
058            }
059    
060            public ClassLoader getPortalClassLoader() {
061                    return _portalClassLoader;
062            }
063    
064            public String getServletContextName() {
065                    return _paclPolicy.getServletContextName();
066            }
067    
068            public ClassLoader getSystemClassLoader() {
069                    return _systemClassLoader;
070            }
071    
072            public void setPACLPolicy(PACLPolicy paclPolicy) {
073                    _paclPolicy = paclPolicy;
074            }
075    
076            protected Properties getProperties() {
077                    return _paclPolicy.getProperties();
078            }
079    
080            protected String getProperty(String key) {
081                    return _paclPolicy.getProperty(key);
082            }
083    
084            protected String[] getPropertyArray(String key) {
085                    return _paclPolicy.getPropertyArray(key);
086            }
087    
088            protected boolean getPropertyBoolean(String key) {
089                    return _paclPolicy.getPropertyBoolean(key);
090            }
091    
092            protected Set<String> getPropertySet(String key) {
093                    return _paclPolicy.getPropertySet(key);
094            }
095    
096            protected boolean isJSPCompiler(String subject, String actions) {
097                    for (int i = 7;; i++) {
098                            Class<?> callerClass = Reflection.getCallerClass(i);
099    
100                            if (callerClass == null) {
101                                    return false;
102                            }
103    
104                            Boolean allowed = null;
105    
106                            String callerClassName = callerClass.getName();
107    
108                            if (ServerDetector.isGeronimo()) {
109                                    if (callerClassName.equals(_ClASS_NAME_COMPILER) ||
110                                            callerClassName.startsWith(
111                                                    _CLASS_NAME_JASPER_SERVLET_CONTEXT_CUSTOMIZER) ||
112                                            callerClassName.equals(_ClASS_NAME_TAG_HANDLER_POOL)) {
113    
114                                            String actualClassLocation = PACLClassUtil.getClassLocation(
115                                                    callerClass);
116                                            String expectedClassLocation = PathUtil.toUnixPath(
117                                                    System.getProperty("org.apache.geronimo.home.dir") +
118                                                            "/repository/org/apache/geronimo/");
119    
120                                            allowed = actualClassLocation.contains(
121                                                    expectedClassLocation);
122                                    }
123                            }
124                            else if (ServerDetector.isGlassfish()) {
125                                    if (callerClassName.equals(_ClASS_NAME_COMPILER) ||
126                                            callerClassName.equals(
127                                                    _ClASS_NAME_JSP_COMPILATION_CONTEXT)) {
128    
129                                            String classLocation = PACLClassUtil.getClassLocation(
130                                                    callerClass);
131    
132                                            allowed = classLocation.startsWith("bundle://");
133                                    }
134                            }
135                            else if (ServerDetector.isJBoss()) {
136                                    if (callerClassName.equals(_ClASS_NAME_COMPILER)) {
137                                            ClassLoader callerClassLoader =
138                                                    PACLClassLoaderUtil.getClassLoader(callerClass);
139    
140                                            String callerClassLoaderString =
141                                                    callerClassLoader.toString();
142    
143                                            allowed = callerClassLoaderString.contains(
144                                                    _MODULE_NAME_ORG_JBOSS_AS_WEB_MAIN);
145                                    }
146                            }
147                            else if (ServerDetector.isJetty()) {
148                                    if (callerClassName.equals(_ClASS_NAME_COMPILER) ||
149                                            callerClassName.equals(_ClASS_NAME_JASPER_LOADER)) {
150    
151                                            ClassLoader callerClassLoader =
152                                                    PACLClassLoaderUtil.getClassLoader(callerClass);
153    
154                                            allowed = (callerClassLoader == _commonClassLoader);
155                                    }
156                            }
157                            else if (ServerDetector.isJOnAS()) {
158                                    if (callerClassName.equals(
159                                                    _ClASS_NAME_DEFAULT_ANNOTATION_PROCESSOR) ||
160                                            callerClassName.equals(_ClASS_NAME_JASPER_LOADER) ||
161                                            callerClassName.equals(
162                                                    _ClASS_NAME_JSP_COMPILATION_CONTEXT)) {
163    
164                                            String classLocation = PACLClassUtil.getClassLocation(
165                                                    callerClass);
166    
167                                            allowed = classLocation.startsWith("bundle://");
168                                    }
169                            }
170                            else if (ServerDetector.isResin()) {
171                                    if (callerClassName.equals(_ClASS_NAME_JSP_MANAGER) ||
172                                            callerClassName.equals(_ClASS_NAME_PAGE_MANAGER)) {
173    
174                                            String actualClassLocation = PACLClassUtil.getClassLocation(
175                                                    callerClass);
176                                            String expectedClassLocation = PathUtil.toUnixPath(
177                                                    System.getProperty("resin.home") + "/lib/resin.jar!/");
178    
179                                            allowed = actualClassLocation.contains(
180                                                    expectedClassLocation);
181                                    }
182                            }
183                            else if (ServerDetector.isTomcat()) {
184                                    if (callerClassName.equals(
185                                                    _ClASS_NAME_DEFAULT_INSTANCE_MANAGER) ||
186                                            callerClassName.equals(_ClASS_NAME_COMPILER) ||
187                                            callerClassName.equals(_ClASS_NAME_TAG_HANDLER_POOL)) {
188    
189                                            ClassLoader callerClassLoader =
190                                                    PACLClassLoaderUtil.getClassLoader(callerClass);
191    
192                                            allowed = (callerClassLoader == _commonClassLoader);
193                                    }
194                            }
195                            else if (ServerDetector.isWebLogic()) {
196                                    if (callerClassName.equals(_CLASS_NAME_JSP_CLASS_LOADER) ||
197                                            callerClassName.equals(_CLASS_NAME_JSP_STUB)) {
198    
199                                            String classLocation = PACLClassUtil.getClassLocation(
200                                                    callerClass);
201    
202                                            allowed = classLocation.contains(
203                                                    "/wlserver/server/lib/weblogic.jar!/");
204                                    }
205                            }
206                            else if (ServerDetector.isWebSphere()) {
207                                    if (callerClassName.equals(
208                                                    _CLASS_NAME_JSP_EXTENSION_CLASS_LOADER) ||
209                                            callerClassName.equals(_ClASS_NAME_JSP_TRANSLATOR_UTIL)) {
210    
211                                            String classLocation = PACLClassUtil.getClassLocation(
212                                                    callerClass);
213    
214                                            return classLocation.startsWith("bundleresource://");
215                                    }
216                            }
217    
218                            if (allowed == null) {
219                                    continue;
220                            }
221    
222                            if (allowed) {
223                                    if (_log.isDebugEnabled()) {
224                                            if (Validator.isNotNull(actions)) {
225                                                    _log.debug(
226                                                            "Allowing the JSP compiler via " + callerClassName +
227                                                                    " to " + actions + " " + subject);
228                                            }
229                                            else {
230                                                    _log.debug(
231                                                            "Allowing the JSP compiler via " + callerClassName +
232                                                                    " to " + subject);
233                                            }
234                                    }
235    
236                                    return true;
237                            }
238                            else {
239                                    if (Validator.isNotNull(actions)) {
240                                            _log.error(
241                                                    "A plugin is hijacking the JSP compiler via " +
242                                                            callerClassName + " to " + actions + " " +
243                                                                    subject);
244                                    }
245                                    else {
246                                            _log.error(
247                                                    "A plugin is hijacking the JSP compiler via " +
248                                                            callerClassName + " to " + subject);
249                                    }
250    
251                                    return false;
252                            }
253                    }
254            }
255    
256            protected boolean isTrustedCallerClass(Class<?> callerClass) {
257                    String callerClassLocation = PACLClassUtil.getClassLocation(
258                            callerClass);
259    
260                    if (callerClassLocation.startsWith(portalImplJarLocation) ||
261                            callerClassLocation.startsWith(portalServiceJarLocation) ||
262                            callerClassLocation.contains("/util-bridges.jar!/") ||
263                            callerClassLocation.contains("/util-java.jar!/") ||
264                            callerClassLocation.contains("/util-taglib.jar!/")) {
265    
266                            return true;
267                    }
268    
269                    return false;
270            }
271    
272            protected void throwSecurityException(Log log, String message) {
273                    if (log.isWarnEnabled()) {
274                            log.warn(message);
275                    }
276    
277                    throw new SecurityException(message);
278            }
279    
280            protected String portalImplJarLocation = PACLClassUtil.getJarLocation(
281                    PortalImpl.class);
282            protected String portalServiceJarLocation = PACLClassUtil.getJarLocation(
283                    PortalUtil.class);
284    
285            private static final String _ClASS_NAME_COMPILER =
286                    "org.apache.jasper.compiler.Compiler";
287    
288            private static final String _ClASS_NAME_DEFAULT_ANNOTATION_PROCESSOR =
289                    "org.apache.catalina.util.DefaultAnnotationProcessor";
290    
291            private static final String _ClASS_NAME_DEFAULT_INSTANCE_MANAGER =
292                    "org.apache.catalina.core.DefaultInstanceManager";
293    
294            private static final String _ClASS_NAME_JASPER_LOADER =
295                    "org.apache.jasper.servlet.JasperLoader";
296    
297            private static final String _CLASS_NAME_JASPER_SERVLET_CONTEXT_CUSTOMIZER =
298                    "org.apache.geronimo.jasper.JasperServletContextCustomizer$";
299    
300            private static final String _CLASS_NAME_JSP_CLASS_LOADER =
301                    "weblogic.servlet.jsp.JspClassLoader";
302    
303            private static final String _ClASS_NAME_JSP_COMPILATION_CONTEXT =
304                    "org.apache.jasper.JspCompilationContext";
305    
306            private static final String _CLASS_NAME_JSP_EXTENSION_CLASS_LOADER =
307                    "com.ibm.ws.jsp.webcontainerext.JSPExtensionClassLoader";
308    
309            private static final String _ClASS_NAME_JSP_MANAGER =
310                    "com.caucho.jsp.JspManager";
311    
312            private static final String _CLASS_NAME_JSP_STUB =
313                    "weblogic.servlet.jsp.JspStub";
314    
315            private static final String _ClASS_NAME_JSP_TRANSLATOR_UTIL =
316                    "com.ibm.ws.jsp.translator.utils.JspTranslatorUtil";
317    
318            private static final String _ClASS_NAME_PAGE_MANAGER =
319                    "com.caucho.jsp.PageManager";
320    
321            private static final String _ClASS_NAME_TAG_HANDLER_POOL =
322                    "org.apache.jasper.runtime.TagHandlerPool";
323    
324            private static final String _MODULE_NAME_ORG_JBOSS_AS_WEB_MAIN =
325                    "org.jboss.as.web:main";
326    
327            private static Log _log = LogFactoryUtil.getLog(BaseChecker.class);
328    
329            private ClassLoader _commonClassLoader;
330            private PACLPolicy _paclPolicy;
331            private ClassLoader _portalClassLoader;
332            private ClassLoader _systemClassLoader;
333    
334    }