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;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.util.AggregateClassLoader;
020    import com.liferay.portal.kernel.util.ProxyUtil;
021    import com.liferay.portal.kernel.util.ServerDetector;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.security.lang.PortalSecurityManagerThreadLocal;
025    import com.liferay.portal.spring.util.FilterClassLoader;
026    
027    import java.net.URL;
028    
029    import sun.reflect.Reflection;
030    
031    /**
032     * @author Brian Wing Shun Chan
033     */
034    public class PACLClassUtil {
035    
036            public static ClassLoader getCallerClassLoader(Class<?> callerClass) {
037                    boolean enabled = PortalSecurityManagerThreadLocal.isEnabled();
038    
039                    try {
040                            PortalSecurityManagerThreadLocal.setEnabled(false);
041    
042                            return _instance._getCallerClassLoader(callerClass);
043                    }
044                    finally {
045                            PortalSecurityManagerThreadLocal.setEnabled(enabled);
046                    }
047            }
048    
049            public static String getClassLocation(Class<?> clazz) {
050                    boolean enabled = PortalSecurityManagerThreadLocal.isEnabled();
051    
052                    try {
053                            PortalSecurityManagerThreadLocal.setEnabled(false);
054    
055                            ClassLoader classLoader = clazz.getClassLoader();
056    
057                            if (classLoader == null) {
058                                    return StringPool.BLANK;
059                            }
060    
061                            String className = clazz.getName();
062    
063                            String name = StringUtil.replace(
064                                    className, StringPool.PERIOD, StringPool.SLASH);
065    
066                            name += ".class";
067    
068                            URL url = classLoader.getResource(name);
069    
070                            return url.toString();
071                    }
072                    finally {
073                            PortalSecurityManagerThreadLocal.setEnabled(enabled);
074                    }
075            }
076    
077            public static String getJarLocation(Class<?> clazz) {
078                    String classLocation = getClassLocation(clazz);
079    
080                    if (classLocation == null) {
081                            return null;
082                    }
083    
084                    int index = classLocation.indexOf(".jar!");
085    
086                    return classLocation.substring(0, index + 4);
087            }
088    
089            public static PACLPolicy getPACLPolicy(boolean deep, boolean debug) {
090                    PACLPolicy paclPolicy =
091                            PortalSecurityManagerThreadLocal.getPACLPolicy();
092    
093                    if (paclPolicy != null) {
094                            return paclPolicy;
095                    }
096    
097                    return getPACLPolicyByReflection(deep, debug);
098            }
099    
100            public static PACLPolicy getPACLPolicyByReflection(
101                    boolean deep, boolean debug) {
102    
103                    boolean enabled = PortalSecurityManagerThreadLocal.isEnabled();
104    
105                    try {
106                            PortalSecurityManagerThreadLocal.setEnabled(false);
107    
108                            return _instance._getPACLPolicyByReflection(deep, debug);
109                    }
110                    finally {
111                            PortalSecurityManagerThreadLocal.setEnabled(enabled);
112                    }
113            }
114    
115            private PACLClassUtil() {
116                    _systemClassLoader = ClassLoader.getSystemClassLoader();
117    
118                    _portalClassLoader = PACLAdvice.class.getClassLoader();
119    
120                    _commonClassLoader = _portalClassLoader.getParent();
121            }
122    
123            private ClassLoader _getCallerClassLoader(Class<?> callerClass) {
124                    ClassLoader callerClassLoader = callerClass.getClassLoader();
125    
126                    if (callerClassLoader == null) {
127                            return null;
128                    }
129    
130                    Class<?> callerClassLoaderClass = callerClassLoader.getClass();
131    
132                    String callerClassLoaderClassName = callerClassLoaderClass.getName();
133    
134                    if (callerClassLoader instanceof FilterClassLoader) {
135                            callerClassLoader = callerClassLoader.getParent();
136    
137                            if (callerClassLoader instanceof AggregateClassLoader) {
138                                    callerClassLoader = callerClassLoader.getParent();
139                            }
140                    }
141    
142                    if (callerClassLoaderClassName.equals(_ClASS_NAME_JASPER_LOADER)) {
143                            callerClassLoader = callerClassLoader.getParent();
144                    }
145                    else if (ServerDetector.isResin()) {
146                            if (callerClassLoaderClassName.equals(
147                                            _ClASS_NAME_DYNAMIC_CLASS_LOADER)) {
148    
149                                    callerClassLoader = callerClassLoader.getParent();
150                            }
151                    }
152                    else if (ServerDetector.isWebLogic()) {
153                            if (callerClassLoaderClassName.equals(
154                                            _CLASS_NAME_JSP_CLASS_LOADER)) {
155    
156                                    // weblogic.servlet.jsp.TagFileClassLoader
157    
158                                    callerClassLoader = callerClassLoader.getParent();
159    
160                                    // weblogic.utils.classloaders.ChangeAwareClassLoader
161    
162                                    callerClassLoader = callerClassLoader.getParent();
163                            }
164                    }
165                    else if (ServerDetector.isWebSphere()) {
166                            if (callerClassLoaderClassName.equals(
167                                            _CLASS_NAME_JSP_EXTENSION_CLASS_LOADER)) {
168    
169                                    callerClassLoader = callerClassLoader.getParent();
170                            }
171                    }
172    
173                    return callerClassLoader;
174            }
175    
176            private PACLPolicy _getPACLPolicyByReflection(boolean deep, boolean debug) {
177                    PACLPolicy paclPolicy = null;
178    
179                    boolean initialPortalClassLoaderPhase = true;
180    
181                    // int i = 0 always returns sun.reflect.Reflection
182    
183                    for (int i = 1;; i++) {
184                            Class<?> callerClass = Reflection.getCallerClass(i);
185    
186                            if (callerClass == null) {
187                                    break;
188                            }
189    
190                            if (debug) {
191                                    _log.debug(
192                                            "Frame " + i + " has caller class " +
193                                                    callerClass.getName());
194                            }
195    
196                            if (ProxyUtil.isProxyClass(callerClass)) {
197                                    if (debug) {
198                                            _log.debug("Skipping frame because it is proxy class");
199                                    }
200    
201                                    continue;
202                            }
203    
204                            ClassLoader callerClassLoader = _getCallerClassLoader(callerClass);
205    
206                            if (callerClassLoader == null) {
207                                    continue;
208                            }
209    
210                            /*if (debug) {
211                                    StringBundler sb = new StringBundler(10);
212    
213                                    sb.append("Frame ");
214                                    sb.append(i);
215                                    sb.append(" ");
216                                    sb.append(callerClass);
217                                    sb.append(" ");
218                                    sb.append(callerClassLoader);
219                                    sb.append(" ");
220                                    sb.append(callerClassLoader.getClass());
221                                    sb.append(" ");
222                                    sb.append(PACLPolicyManager.getPACLPolicy(callerClassLoader));
223    
224                                    System.out.println(sb.toString());
225                            }*/
226    
227                            if (!initialPortalClassLoaderPhase &&
228                                    (callerClassLoader == _portalClassLoader)) {
229    
230                                    PACLPolicy defaultPACLPolicy =
231                                            PACLPolicyManager.getDefaultPACLPolicy();
232    
233                                    if (paclPolicy == null) {
234                                            if (debug) {
235                                                    _log.debug(
236                                                            "Possibly return default PACL policy " +
237                                                                    defaultPACLPolicy);
238                                            }
239    
240                                            paclPolicy = defaultPACLPolicy;
241                                    }
242    
243                                    if (!deep) {
244                                            break;
245                                    }
246    
247                                    continue;
248                            }
249    
250                            if (initialPortalClassLoaderPhase &&
251                                    (callerClassLoader != _portalClassLoader)) {
252    
253                                    initialPortalClassLoaderPhase = false;
254                            }
255    
256                            if ((callerClassLoader == _commonClassLoader) ||
257                                    (callerClassLoader == _portalClassLoader) ||
258                                    (callerClassLoader == _systemClassLoader)) {
259    
260                                    continue;
261                            }
262    
263                            if (debug) {
264                                    _log.debug(
265                                            "Lookup PACL policy for caller class loader " +
266                                                    callerClassLoader);
267                            }
268    
269                            PACLPolicy callerPACLPolicy = PACLPolicyManager.getPACLPolicy(
270                                    callerClassLoader);
271    
272                            if (callerPACLPolicy != null) {
273                                    paclPolicy = callerPACLPolicy;
274    
275                                    if (debug) {
276                                            _log.debug("Possibly return PACL policy " + paclPolicy);
277                                    }
278    
279                                    if (!deep) {
280                                            break;
281                                    }
282                            }
283                    }
284    
285                    if (debug) {
286                            _log.debug("Returning PACL policy " + paclPolicy);
287                    }
288    
289                    return paclPolicy;
290            }
291    
292            private static final String _ClASS_NAME_DYNAMIC_CLASS_LOADER =
293                    "com.caucho.loader.DynamicClassLoader";
294    
295            private static final String _ClASS_NAME_JASPER_LOADER =
296                    "org.apache.jasper.servlet.JasperLoader";
297    
298            private static final String _CLASS_NAME_JSP_CLASS_LOADER =
299                    "weblogic.servlet.jsp.JspClassLoader";
300    
301            private static final String _CLASS_NAME_JSP_EXTENSION_CLASS_LOADER =
302                    "com.ibm.ws.jsp.webcontainerext.JSPExtensionClassLoader";
303    
304            private static Log _log = LogFactoryUtil.getLog(PACLClassUtil.class);
305    
306            private static PACLClassUtil _instance = new PACLClassUtil();
307    
308            private ClassLoader _commonClassLoader;
309            private ClassLoader _portalClassLoader;
310            private ClassLoader _systemClassLoader;
311    
312    }