001    /**
002     * Copyright (c) 2000-2013 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.servlet.ServletContextPool;
020    import com.liferay.portal.kernel.util.GetterUtil;
021    import com.liferay.portal.kernel.util.JavaDetector;
022    import com.liferay.portal.kernel.util.PropsUtil;
023    import com.liferay.portal.kernel.util.SetUtil;
024    import com.liferay.portal.kernel.util.SortedProperties;
025    import com.liferay.portal.kernel.util.StringBundler;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.security.pacl.checker.Checker;
028    import com.liferay.portal.security.pacl.checker.FileChecker;
029    
030    import java.io.FilePermission;
031    
032    import java.net.MalformedURLException;
033    import java.net.URL;
034    
035    import java.security.AllPermission;
036    import java.security.CodeSource;
037    import java.security.Permission;
038    import java.security.Permissions;
039    import java.security.Policy;
040    import java.security.ProtectionDomain;
041    import java.security.Provider;
042    import java.security.Security;
043    import java.security.URIParameter;
044    import java.security.cert.Certificate;
045    
046    import java.util.HashMap;
047    import java.util.Map;
048    import java.util.Properties;
049    import java.util.Set;
050    import java.util.TreeSet;
051    
052    import javax.servlet.ServletContext;
053    
054    /**
055     * @author Brian Wing Shun Chan
056     */
057    public abstract class BasePACLPolicy implements PACLPolicy {
058    
059            public BasePACLPolicy(
060                    String servletContextName, ClassLoader classLoader,
061                    Properties properties) {
062    
063                    _servletContextName = servletContextName;
064                    _classLoader = classLoader;
065                    _properties = properties;
066    
067                    try {
068                            initCheckers();
069    
070                            initPolicy(servletContextName, classLoader);
071                    }
072                    catch (Exception e) {
073                            _log.error(e, e);
074                    }
075            }
076    
077            public ClassLoader getClassLoader() {
078                    return _classLoader;
079            }
080    
081            public Policy getPolicy() {
082                    return _policy;
083            }
084    
085            public Properties getProperties() {
086                    return _properties;
087            }
088    
089            public String getProperty(String key) {
090                    return _properties.getProperty(key);
091            }
092    
093            public String[] getPropertyArray(String key) {
094                    return StringUtil.split(getProperty(key));
095            }
096    
097            public boolean getPropertyBoolean(String key) {
098                    return GetterUtil.getBoolean(getProperty(key));
099            }
100    
101            public Set<String> getPropertySet(String key) {
102                    return new TreeSet<String>(SetUtil.fromArray(getPropertyArray(key)));
103            }
104    
105            public String getServletContextName() {
106                    return _servletContextName;
107            }
108    
109            public boolean isCheckablePermission(Permission permission) {
110                    Class<?> clazz = permission.getClass();
111    
112                    return _checkers.containsKey(clazz.getName());
113            }
114    
115            @Override
116            public String toString() {
117                    StringBundler sb = new StringBundler(7);
118    
119                    sb.append("{active=");
120                    sb.append(isActive());
121                    sb.append(", hashCode=");
122                    sb.append(hashCode());
123                    sb.append(", servletContextName=");
124                    sb.append(_servletContextName);
125                    sb.append("}");
126    
127                    return sb.toString();
128            }
129    
130            protected void checkForAllPermission(Policy policy, String rootDir)
131                    throws MalformedURLException {
132    
133                    URL rootURL = new URL("file", null, rootDir);
134    
135                    ProtectionDomain protectionDomain = new ProtectionDomain(
136                            new CodeSource(rootURL, new Certificate[0]), new Permissions());
137    
138                    if (policy.implies(protectionDomain, new AllPermission())) {
139                            throw new IllegalStateException(
140                                    "The plugin's Java policy tried to declared all " +
141                                            "permissions");
142                    }
143            }
144    
145            protected Checker getChecker(Class<? extends Permission> clazz) {
146                    return _checkers.get(clazz.getName());
147            }
148    
149            protected Provider getProvider() {
150                    String providerName = "SUN";
151    
152                    if (JavaDetector.isIBM() && JavaDetector.isJDK6()) {
153                            providerName = "Policy";
154                    }
155    
156                    return Security.getProvider(providerName);
157            }
158    
159            protected Checker initChecker(Checker checker) {
160                    checker.setPACLPolicy(this);
161    
162                    checker.afterPropertiesSet();
163    
164                    return checker;
165            }
166    
167            protected void initCheckers() throws Exception {
168                    Class<?> clazz = getClass();
169    
170                    ClassLoader classLoader = clazz.getClassLoader();
171    
172                    Properties portalProperties = PropsUtil.getProperties(
173                            "portal.security.manager.pacl.policy.checker", false);
174    
175                    portalProperties = new SortedProperties(portalProperties);
176    
177                    if (_log.isInfoEnabled()) {
178                            _log.info(
179                                    "Registering " + portalProperties.size() +
180                                            " PACL policy checkers");
181                    }
182    
183                    for (Map.Entry<Object, Object> entry : portalProperties.entrySet()) {
184                            String key = (String)entry.getKey();
185    
186                            int x = key.indexOf("[");
187                            int y = key.indexOf("]");
188    
189                            String permissionClassName = key.substring(x + 1, y);
190    
191                            String checkerClassName = (String)entry.getValue();
192    
193                            Class<?> checkerClass = classLoader.loadClass(checkerClassName);
194    
195                            Checker checker = (Checker)checkerClass.newInstance();
196    
197                            initChecker(checker);
198    
199                            if (_log.isInfoEnabled()) {
200                                    _log.info(
201                                            "Registering permission " + permissionClassName +
202                                                    " with PACL policy " + checkerClassName);
203                            }
204    
205                            _checkers.put(permissionClassName, checker);
206                    }
207            }
208    
209            protected void initPolicy(
210                            String servletContextName, ClassLoader classLoader)
211                    throws Exception {
212    
213                    ServletContext servletContext = ServletContextPool.get(
214                            servletContextName);
215    
216                    if (servletContext == null) {
217                            return;
218                    }
219    
220                    URL url = servletContext.getResource("/WEB-INF/java.policy");
221    
222                    if (url == null) {
223                            return;
224                    }
225    
226                    FileChecker fileChecker = (FileChecker)_checkers.get(
227                            FilePermission.class.getName());
228    
229                    if (fileChecker == null) {
230                            return;
231                    }
232    
233                    // Set a system property to match the servletContextName so that the
234                    // plugin can use it in it's Java security policy file for setting the
235                    // code base
236    
237                    String rootDir = fileChecker.getRootDir();
238    
239                    System.setProperty(servletContextName, rootDir);
240    
241                    try {
242                            URIParameter parameter = new URIParameter(url.toURI());
243    
244                            Policy policy = Policy.getInstance(
245                                    "JavaPolicy", parameter, getProvider());
246    
247                            checkForAllPermission(policy, rootDir);
248    
249                            _policy = policy;
250                    }
251                    catch (Exception e) {
252                            _log.error("Unable to initialize Java policy " + url.toString(), e);
253                    }
254            }
255    
256            private static Log _log = LogFactoryUtil.getLog(BasePACLPolicy.class);
257    
258            private Map<String, Checker> _checkers = new HashMap<String, Checker>();
259    
260            private ClassLoader _classLoader;
261            private Policy _policy;
262            private Properties _properties;
263            private String _servletContextName;
264    
265    }