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.lang;
016    
017    import com.liferay.portal.jndi.pacl.PACLInitialContextFactoryBuilder;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.security.pacl.PACLConstants;
021    import com.liferay.portal.kernel.security.pacl.permission.PortalHookPermission;
022    import com.liferay.portal.kernel.security.pacl.permission.PortalRuntimePermission;
023    import com.liferay.portal.kernel.servlet.taglib.FileAvailabilityUtil;
024    import com.liferay.portal.kernel.util.JavaDetector;
025    import com.liferay.portal.security.pacl.PACLClassUtil;
026    import com.liferay.portal.security.pacl.PACLPolicy;
027    import com.liferay.portal.security.pacl.PACLPolicyManager;
028    import com.liferay.portal.security.pacl.checker.CheckerUtil;
029    
030    import java.lang.reflect.Field;
031    
032    import java.security.Permission;
033    
034    import javax.naming.spi.InitialContextFactoryBuilder;
035    import javax.naming.spi.NamingManager;
036    
037    /**
038     * This is the portal's implementation of a security manager. The goal is to
039     * protect portal resources from plugins and prevent security issues by forcing
040     * plugin developers to openly declare their requirements. Where a
041     * SecurityManager exists, we set that as the parent and delegate to it as a
042     * fallback. This class will not delegate checks to super when there is no
043     * parent so as to avoid forcing the need for a default policy.
044     *
045     * @author Brian Wing Shun Chan
046     * @author Raymond Augé
047     */
048    public class PortalSecurityManager extends SecurityManager {
049    
050            public PortalSecurityManager() {
051                    _parentSecurityManager = System.getSecurityManager();
052    
053                    initClasses();
054    
055                    try {
056                            initInitialContextFactoryBuilder();
057                    }
058                    catch (Exception e) {
059                            if (_log.isInfoEnabled()) {
060                                    _log.info(
061                                            "Unable to override the initial context factory builder " +
062                                                    "because one already exists. JNDI security is not " +
063                                                            "enabled.");
064                            }
065    
066                            if (_log.isWarnEnabled()) {
067                                    _log.warn(e, e);
068                            }
069                    }
070            }
071    
072            @Override
073            public void checkPermission(Permission permission) {
074                    checkPermission(permission, null);
075            }
076    
077            @Override
078            public void checkPermission(Permission permission, Object context) {
079                    if (!PACLPolicyManager.isActive() ||
080                            !PortalSecurityManagerThreadLocal.isEnabled()) {
081    
082                            parentCheckPermission(permission, context);
083    
084                            return;
085                    }
086    
087                    PACLPolicy paclPolicy = PACLPolicyManager.getDefaultPACLPolicy();
088    
089                    if (!paclPolicy.isCheckablePermission(permission)) {
090                            parentCheckPermission(permission, context);
091    
092                            return;
093                    }
094    
095                    paclPolicy = getPACLPolicy(permission);
096    
097                    if ((paclPolicy == null) || !paclPolicy.isActive()) {
098                            parentCheckPermission(permission, context);
099    
100                            return;
101                    }
102    
103                    paclPolicy.checkPermission(permission);
104    
105                    parentCheckPermission(permission, context);
106            }
107    
108            protected PACLPolicy getPACLPolicy(Permission permission) {
109                    PACLPolicy paclPolicy =
110                            PortalSecurityManagerThreadLocal.getPACLPolicy();
111    
112                    if (paclPolicy != null) {
113                            return paclPolicy;
114                    }
115    
116                    if (permission instanceof PortalHookPermission) {
117                            PortalHookPermission portalHookPermission =
118                                    (PortalHookPermission)permission;
119    
120                            ClassLoader classLoader = portalHookPermission.getClassLoader();
121    
122                            paclPolicy = PACLPolicyManager.getPACLPolicy(classLoader);
123    
124                            if (paclPolicy == null) {
125                                    paclPolicy = PACLPolicyManager.getDefaultPACLPolicy();
126                            }
127    
128                            return paclPolicy;
129                    }
130                    else if (permission instanceof PortalRuntimePermission) {
131                            PortalRuntimePermission portalRuntimePermission =
132                                    (PortalRuntimePermission)permission;
133    
134                            String name = portalRuntimePermission.getName();
135    
136                            if (name.equals(
137                                            PACLConstants.PORTAL_RUNTIME_PERMISSION_EXPANDO_BRIDGE)) {
138    
139                                    return PACLClassUtil.getPACLPolicyByReflection(
140                                            true, _log.isDebugEnabled());
141                            }
142    
143                            /*if (name.equals(
144                                                    PACLConstants.
145                                                            PORTAL_RUNTIME_PERMISSION_SET_BEAN_PROPERTY)) {
146    
147                                    paclPolicy = PACLClassUtil.getPACLPolicyByReflection(
148                                            false, true);
149    
150                                    System.out.println("PACL policy " + paclPolicy);
151    
152                                    return paclPolicy;
153                            }*/
154                    }
155    
156                    return PACLClassUtil.getPACLPolicyByReflection(
157                            false, _log.isDebugEnabled());
158            }
159    
160            protected void initClasses() {
161    
162                    // Load dependent classes to prevent ClassCircularityError
163    
164                    _log.debug("Loading " + FileAvailabilityUtil.class.getName());
165                    _log.debug("Loading " + PortalHookPermission.class.getName());
166    
167                    // Touch dependent classes to prevent NoClassDefError
168    
169                    CheckerUtil.isAccessControllerDoPrivileged(0);
170                    PACLClassUtil.getPACLPolicyByReflection(false, false);
171            }
172    
173            protected void initInitialContextFactoryBuilder() throws Exception {
174                    if (!NamingManager.hasInitialContextFactoryBuilder()) {
175                            PACLInitialContextFactoryBuilder paclInitialContextFactoryBuilder =
176                                    new PACLInitialContextFactoryBuilder();
177    
178                            if (_log.isInfoEnabled()) {
179                                    _log.info("Overriding the initial context factory builder");
180                            }
181    
182                            NamingManager.setInitialContextFactoryBuilder(
183                                    paclInitialContextFactoryBuilder);
184                    }
185    
186                    Class<?> clazz = NamingManager.class;
187    
188                    String fieldName = "initctx_factory_builder";
189    
190                    if (JavaDetector.isIBM()) {
191                            fieldName = "icfb";
192                    }
193    
194                    Field field = clazz.getDeclaredField(fieldName);
195    
196                    field.setAccessible(true);
197    
198                    InitialContextFactoryBuilder initialContextFactoryBuilder =
199                            (InitialContextFactoryBuilder)field.get(null);
200    
201                    if (initialContextFactoryBuilder
202                                    instanceof PACLInitialContextFactoryBuilder) {
203    
204                            return;
205                    }
206    
207                    PACLInitialContextFactoryBuilder paclInitialContextFactoryBuilder =
208                            new PACLInitialContextFactoryBuilder();
209    
210                    paclInitialContextFactoryBuilder.setInitialContextFactoryBuilder(
211                            initialContextFactoryBuilder);
212    
213                    field.set(null, paclInitialContextFactoryBuilder);
214    
215                    if (_log.isInfoEnabled()) {
216                            _log.info(
217                                    "Overriding the initial context factory builder using " +
218                                            "reflection");
219                    }
220            }
221    
222            protected void parentCheckPermission(
223                    Permission permission, Object context) {
224    
225                    if (_parentSecurityManager != null) {
226                            if (context == null) {
227                                    context = getSecurityContext();
228                            }
229    
230                            _parentSecurityManager.checkPermission(permission, context);
231                    }
232            }
233    
234            private static Log _log = LogFactoryUtil.getLog(
235                    PortalSecurityManager.class.getName());
236    
237            private SecurityManager _parentSecurityManager;
238    
239    }