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