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.security.lang.PortalSecurityManagerThreadLocal;
020    import com.liferay.portal.service.impl.PortalServiceImpl;
021    import com.liferay.portal.spring.aop.ChainableMethodAdvice;
022    import com.liferay.portal.util.ClassLoaderUtil;
023    
024    import java.lang.reflect.Method;
025    
026    import org.aopalliance.intercept.MethodInvocation;
027    
028    /**
029     * @author Brian Wing Shun Chan
030     */
031    public class PACLAdvice extends ChainableMethodAdvice {
032    
033            @Override
034            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
035                    if (!PortalSecurityManagerThreadLocal.isEnabled()) {
036    
037                            // Proceed so that we do not remove the advice
038    
039                            try {
040                                    return methodInvocation.proceed();
041                            }
042                            catch (Throwable throwable) {
043                                    throw throwable;
044                            }
045                    }
046    
047                    if (!PACLPolicyManager.isActive()) {
048                            serviceBeanAopCacheManager.removeMethodInterceptor(
049                                    methodInvocation, this);
050    
051                            try {
052                                    return methodInvocation.proceed();
053                            }
054                            catch (Throwable throwable) {
055                                    throw throwable;
056                            }
057                    }
058    
059                    Object thisObject = methodInvocation.getThis();
060                    Method method = methodInvocation.getMethod();
061                    Object[] arguments = methodInvocation.getArguments();
062    
063                    boolean debug = false;
064    
065                    if (_log.isDebugEnabled()) {
066                            Class<?> clazz = thisObject.getClass();
067    
068                            String className = clazz.getName();
069    
070                            if (className.equals(PortalServiceImpl.class.getName()) ||
071                                    className.equals(_ENTRY_LOCAL_SERVICE_IMPL_CLASS_NAME) ||
072                                    className.equals(_STATUS_LOCAL_SERVICE_IMPL_CLASS_NAME)) {
073    
074                                    debug = true;
075    
076                                    _log.debug(
077                                            "Intercepting " + className + "#" + method.getName());
078                            }
079                    }
080    
081                    if (method.getDeclaringClass() == Object.class) {
082                            String methodName = method.getName();
083    
084                            if (methodName.equals("equals")) {
085                                    if (thisObject == arguments[0]) {
086                                            return true;
087                                    }
088                                    else {
089                                            return false;
090                                    }
091                            }
092                            else if (methodName.equals("toString")) {
093                                    return method.invoke(thisObject, arguments);
094                            }
095                    }
096    
097                    if (!PACLPolicyManager.isActive()) {
098                            return method.invoke(thisObject, arguments);
099                    }
100    
101                    PACLPolicy paclPolicy = PACLClassUtil.getPACLPolicy(false, debug);
102    
103                    if (debug) {
104                            if (paclPolicy != null) {
105                                    _log.debug(
106                                            "Retrieved PACL policy for " +
107                                                    paclPolicy.getServletContextName());
108                            }
109                    }
110    
111                    if (paclPolicy == null) {
112                            return methodInvocation.proceed();
113                    }
114    
115                    if (!paclPolicy.hasPortalService(thisObject, method, arguments)) {
116                            throw new SecurityException("Attempted to invoke " + method);
117                    }
118    
119                    boolean checkSQL = PortalSecurityManagerThreadLocal.isCheckSQL();
120    
121                    try {
122                            Class<?> thisObjectClass = thisObject.getClass();
123    
124                            if (paclPolicy.getClassLoader() !=
125                                            ClassLoaderUtil.getClassLoader(thisObjectClass)) {
126    
127                                    // Disable the portal security manager so that PACLDataSource
128                                    // does not try to check access to tables that can be accessed
129                                    // since the service is already approved
130    
131                                    PortalSecurityManagerThreadLocal.setCheckSQL(false);
132                            }
133    
134                            return methodInvocation.proceed();
135                    }
136                    finally {
137                            PortalSecurityManagerThreadLocal.setCheckSQL(checkSQL);
138                    }
139            }
140    
141            private static final String _ENTRY_LOCAL_SERVICE_IMPL_CLASS_NAME =
142                    "com.liferay.chat.service.impl.EntryLocalServiceImpl";
143    
144            private static final String _STATUS_LOCAL_SERVICE_IMPL_CLASS_NAME =
145                    "com.liferay.chat.service.impl.StatusLocalServiceImpl";
146    
147            private static Log _log = LogFactoryUtil.getLog(PACLAdvice.class);
148    
149    }