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 PACLPolicy getPACLPolicy(boolean deep, boolean debug) {
078                    PACLPolicy paclPolicy =
079                            PortalSecurityManagerThreadLocal.getPACLPolicy();
080    
081                    if (paclPolicy != null) {
082                            return paclPolicy;
083                    }
084    
085                    return getPACLPolicyByReflection(deep, debug);
086            }
087    
088            public static PACLPolicy getPACLPolicyByReflection(
089                    boolean deep, boolean debug) {
090    
091                    boolean enabled = PortalSecurityManagerThreadLocal.isEnabled();
092    
093                    try {
094                            PortalSecurityManagerThreadLocal.setEnabled(false);
095    
096                            return _instance._getPACLPolicyByReflection(deep, debug);
097                    }
098                    finally {
099                            PortalSecurityManagerThreadLocal.setEnabled(enabled);
100                    }
101            }
102    
103            private PACLClassUtil() {
104                    _systemClassLoader = ClassLoader.getSystemClassLoader();
105    
106                    _portalClassLoader = PACLAdvice.class.getClassLoader();
107    
108                    _commonClassLoader = _portalClassLoader.getParent();
109            }
110    
111            private ClassLoader _getCallerClassLoader(Class<?> callerClass) {
112                    ClassLoader callerClassLoader = callerClass.getClassLoader();
113    
114                    if (callerClassLoader == null) {
115                            return null;
116                    }
117    
118                    Class<?> callerClassLoaderClass = callerClassLoader.getClass();
119    
120                    String callerClassLoaderClassName = callerClassLoaderClass.getName();
121    
122                    if (callerClassLoader instanceof FilterClassLoader) {
123                            callerClassLoader = callerClassLoader.getParent();
124    
125                            if (callerClassLoader instanceof AggregateClassLoader) {
126                                    callerClassLoader = callerClassLoader.getParent();
127                            }
128                    }
129    
130                    if (callerClassLoaderClassName.equals(_ClASS_NAME_JASPER_LOADER)) {
131                            callerClassLoader = callerClassLoader.getParent();
132                    }
133                    else if (ServerDetector.isResin()) {
134                            if (callerClassLoaderClassName.equals(
135                                            _ClASS_NAME_DYNAMIC_CLASS_LOADER)) {
136    
137                                    callerClassLoader = callerClassLoader.getParent();
138                            }
139                    }
140                    else if (ServerDetector.isWebLogic()) {
141                            if (callerClassLoaderClassName.equals(
142                                            _CLASS_NAME_JSP_CLASS_LOADER)) {
143    
144                                    // weblogic.servlet.jsp.TagFileClassLoader
145    
146                                    callerClassLoader = callerClassLoader.getParent();
147    
148                                    // weblogic.utils.classloaders.ChangeAwareClassLoader
149    
150                                    callerClassLoader = callerClassLoader.getParent();
151                            }
152                    }
153                    else if (ServerDetector.isWebSphere()) {
154                            if (callerClassLoaderClassName.equals(
155                                            _CLASS_NAME_JSP_EXTENSION_CLASS_LOADER)) {
156    
157                                    callerClassLoader = callerClassLoader.getParent();
158                            }
159                    }
160    
161                    return callerClassLoader;
162            }
163    
164            private PACLPolicy _getPACLPolicyByReflection(boolean deep, boolean debug) {
165                    PACLPolicy paclPolicy = null;
166    
167                    boolean initialPortalClassLoaderPhase = true;
168    
169                    // int i = 0 always returns sun.reflect.Reflection
170    
171                    for (int i = 1;; i++) {
172                            Class<?> callerClass = Reflection.getCallerClass(i);
173    
174                            if (callerClass == null) {
175                                    break;
176                            }
177    
178                            if (debug) {
179                                    _log.debug(
180                                            "Frame " + i + " has caller class " +
181                                                    callerClass.getName());
182                            }
183    
184                            if (ProxyUtil.isProxyClass(callerClass)) {
185                                    if (debug) {
186                                            _log.debug("Skipping frame because it is proxy class");
187                                    }
188    
189                                    continue;
190                            }
191    
192                            ClassLoader callerClassLoader = _getCallerClassLoader(callerClass);
193    
194                            if (callerClassLoader == null) {
195                                    continue;
196                            }
197    
198                            /*if (debug) {
199                                    StringBundler sb = new StringBundler(10);
200    
201                                    sb.append("Frame ");
202                                    sb.append(i);
203                                    sb.append(" ");
204                                    sb.append(callerClass);
205                                    sb.append(" ");
206                                    sb.append(callerClassLoader);
207                                    sb.append(" ");
208                                    sb.append(callerClassLoader.getClass());
209                                    sb.append(" ");
210                                    sb.append(PACLPolicyManager.getPACLPolicy(callerClassLoader));
211    
212                                    System.out.println(sb.toString());
213                            }*/
214    
215                            if (!initialPortalClassLoaderPhase &&
216                                    (callerClassLoader == _portalClassLoader)) {
217    
218                                    PACLPolicy defaultPACLPolicy =
219                                            PACLPolicyManager.getDefaultPACLPolicy();
220    
221                                    if (paclPolicy == null) {
222                                            if (debug) {
223                                                    _log.debug(
224                                                            "Possibly return default PACL policy " +
225                                                                    defaultPACLPolicy);
226                                            }
227    
228                                            paclPolicy = defaultPACLPolicy;
229                                    }
230    
231                                    if (!deep) {
232                                            break;
233                                    }
234    
235                                    continue;
236                            }
237    
238                            if (initialPortalClassLoaderPhase &&
239                                    (callerClassLoader != _portalClassLoader)) {
240    
241                                    initialPortalClassLoaderPhase = false;
242                            }
243    
244                            if ((callerClassLoader == _commonClassLoader) ||
245                                    (callerClassLoader == _portalClassLoader) ||
246                                    (callerClassLoader == _systemClassLoader)) {
247    
248                                    continue;
249                            }
250    
251                            if (debug) {
252                                    _log.debug(
253                                            "Lookup PACL policy for caller class loader " +
254                                                    callerClassLoader);
255                            }
256    
257                            PACLPolicy callerPACLPolicy = PACLPolicyManager.getPACLPolicy(
258                                    callerClassLoader);
259    
260                            if (callerPACLPolicy != null) {
261                                    paclPolicy = callerPACLPolicy;
262    
263                                    if (debug) {
264                                            _log.debug("Possibly return PACL policy " + paclPolicy);
265                                    }
266    
267                                    if (!deep) {
268                                            break;
269                                    }
270                            }
271                    }
272    
273                    if (debug) {
274                            _log.debug("Returning PACL policy " + paclPolicy);
275                    }
276    
277                    return paclPolicy;
278            }
279    
280            private static final String _ClASS_NAME_DYNAMIC_CLASS_LOADER =
281                    "com.caucho.loader.DynamicClassLoader";
282    
283            private static final String _ClASS_NAME_JASPER_LOADER =
284                    "org.apache.jasper.servlet.JasperLoader";
285    
286            private static final String _CLASS_NAME_JSP_CLASS_LOADER =
287                    "weblogic.servlet.jsp.JspClassLoader";
288    
289            private static final String _CLASS_NAME_JSP_EXTENSION_CLASS_LOADER =
290                    "com.ibm.ws.jsp.webcontainerext.JSPExtensionClassLoader";
291    
292            private static Log _log = LogFactoryUtil.getLog(PACLClassUtil.class);
293    
294            private static PACLClassUtil _instance = new PACLClassUtil();
295    
296            private ClassLoader _commonClassLoader;
297            private ClassLoader _portalClassLoader;
298            private ClassLoader _systemClassLoader;
299    
300    }