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.permission.PortalServicePermission;
020    import com.liferay.portal.kernel.util.ProxyUtil;
021    import com.liferay.portal.kernel.util.ServerDetector;
022    import com.liferay.portal.kernel.util.SetUtil;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.StringUtil;
025    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
026    import com.liferay.portal.security.pacl.PACLPolicy;
027    import com.liferay.portal.security.pacl.PACLPolicyManager;
028    
029    import java.lang.reflect.Method;
030    
031    import java.security.Permission;
032    
033    import java.util.Collections;
034    import java.util.HashMap;
035    import java.util.Map;
036    import java.util.Properties;
037    import java.util.Set;
038    
039    /**
040     * @author Brian Wing Shun Chan
041     */
042    public class PortalServiceChecker extends BaseChecker {
043    
044            public void afterPropertiesSet() {
045                    initServices();
046            }
047    
048            public void checkPermission(Permission permission) {
049                    PortalServicePermission portalServicePermission =
050                            (PortalServicePermission)permission;
051    
052                    String name = portalServicePermission.getName();
053                    Object object = portalServicePermission.getObject();
054    
055                    if (name.equals(PORTAL_SERVICE_PERMISSION_DYNAMIC_QUERY)) {
056                            Class<?> implClass = (Class<?>)object;
057    
058                            if (!hasDynamicQuery(implClass)) {
059                                    throwSecurityException(
060                                            _log,
061                                            "Attempted to create a dynamic query for " + implClass);
062                            }
063                    }
064            }
065    
066            public boolean hasService(
067                    Object object, Method method, Object[] arguments) {
068    
069                    Class<?> clazz = object.getClass();
070    
071                    if (ProxyUtil.isProxyClass(clazz)) {
072                            Class<?>[] interfaces = clazz.getInterfaces();
073    
074                            if (interfaces.length == 0) {
075                                    return false;
076                            }
077    
078                            clazz = interfaces[0];
079                    }
080    
081                    ClassLoader classLoader = PACLClassLoaderUtil.getClassLoader(clazz);
082    
083                    PACLPolicy paclPolicy = PACLPolicyManager.getPACLPolicy(classLoader);
084    
085                    if (paclPolicy == getPACLPolicy()) {
086                            return true;
087                    }
088    
089                    Set<String> services = getServices(paclPolicy);
090    
091                    String className = getInterfaceName(clazz.getName());
092    
093                    if (services.contains(className)) {
094                            return true;
095                    }
096    
097                    String methodName = method.getName();
098    
099                    if (methodName.equals("invokeMethod")) {
100                            methodName = (String)arguments[0];
101                    }
102    
103                    if (services.contains(
104                                    className.concat(StringPool.POUND).concat(methodName))) {
105    
106                            return true;
107                    }
108    
109                    return false;
110            }
111    
112            protected String getInterfaceName(String className) {
113                    int pos = className.indexOf(".impl.");
114    
115                    if (pos != -1) {
116                            className =
117                                    className.substring(0, pos + 1) + className.substring(pos + 6);
118                    }
119    
120                    if (className.endsWith("Impl")) {
121                            className = className.substring(0, className.length() - 4);
122                    }
123    
124                    return className;
125            }
126    
127            protected Set<String> getServices(PACLPolicy paclPolicy) {
128                    Set<String> services = null;
129    
130                    if (paclPolicy == null) {
131                            services = _portalServices;
132                    }
133                    else {
134                            services = _pluginServices.get(paclPolicy.getServletContextName());
135                    }
136    
137                    return services;
138            }
139    
140            protected boolean hasDynamicQuery(Class<?> clazz) {
141                    ClassLoader classLoader = PACLClassLoaderUtil.getClassLoader(clazz);
142    
143                    PACLPolicy paclPolicy = PACLPolicyManager.getPACLPolicy(classLoader);
144    
145                    if (paclPolicy == getPACLPolicy()) {
146                            return true;
147                    }
148    
149                    /*Set<String> services = getServices(paclPolicy);
150    
151                    String className = getInterfaceName(clazz.getName());
152    
153                    if (services.contains(className)) {
154                            return true;
155                    }*/
156    
157                    return false;
158            }
159    
160            protected void initServices() {
161                    Properties properties = getProperties();
162    
163                    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
164                            String key = (String)entry.getKey();
165                            String value = (String)entry.getValue();
166    
167                            if (!key.startsWith("security-manager-services[")) {
168                                    continue;
169                            }
170    
171                            int x = key.indexOf("[");
172                            int y = key.indexOf("]", x);
173    
174                            String servicesServletContextName = key.substring(x + 1, y);
175    
176                            Set<String> services = SetUtil.fromArray(StringUtil.split(value));
177    
178                            if (servicesServletContextName.equals(
179                                            _PORTAL_SERVLET_CONTEXT_NAME)) {
180    
181                                    _portalServices = services;
182    
183                                    touchServices(_portalServices);
184                            }
185                            else {
186                                    _pluginServices.put(servicesServletContextName, services);
187                            }
188                    }
189            }
190    
191            protected void touchService(String service) {
192                    String className = service;
193    
194                    if (!className.contains(".service.")) {
195                            return;
196                    }
197    
198                    String methodName = null;
199    
200                    if (className.contains(".service.persistence.") &&
201                            (className.endsWith("Persistence") ||
202                             className.contains("Persistence#"))) {
203    
204                            methodName = "getPersistence";
205                    }
206                    else if (className.endsWith("Service") ||
207                                     className.contains("Service#")) {
208    
209                            methodName = "getService";
210                    }
211                    else {
212                            _log.error("Invalid service " + service);
213    
214                            return;
215                    }
216    
217                    int pos = className.indexOf(StringPool.POUND);
218    
219                    if (pos != -1) {
220                            className = className.substring(0, pos);
221                    }
222    
223                    if (className.endsWith("Persistence")) {
224                            className = className.substring(0, className.length() - 11);
225                    }
226    
227                    className += "Util";
228    
229                    if (_log.isDebugEnabled()) {
230                            _log.debug("Invoking " + className + "#" + methodName);
231                    }
232    
233                    // Invoke method since it will attempt to access declared members
234    
235                    ClassLoader classLoader = getCommonClassLoader();
236    
237                    if (ServerDetector.isGeronimo() || ServerDetector.isJBoss()) {
238                            classLoader = getPortalClassLoader();
239                    }
240    
241                    try {
242                            Class<?> clazz = classLoader.loadClass(className);
243    
244                            Method method = clazz.getMethod(methodName);
245    
246                            method.invoke(clazz);
247                    }
248                    catch (Exception e) {
249                            _log.error(e, e);
250                    }
251            }
252    
253            protected void touchServices(Set<String> services) {
254                    for (String service : services) {
255                            touchService(service);
256                    }
257            }
258    
259            private static final String _PORTAL_SERVLET_CONTEXT_NAME = "portal";
260    
261            private static Log _log = LogFactoryUtil.getLog(PortalServiceChecker.class);
262    
263            private Map<String, Set<String>> _pluginServices =
264                    new HashMap<String, Set<String>>();
265            private Set<String> _portalServices = Collections.emptySet();
266    
267    }