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.FileUtil;
020    import com.liferay.portal.kernel.util.StringBundler;
021    import com.liferay.portal.kernel.util.StringPool;
022    import com.liferay.portal.security.lang.PortalSecurityManagerThreadLocal;
023    import com.liferay.portal.security.pacl.checker.AuthorizationProperty;
024    import com.liferay.portal.security.pacl.checker.Checker;
025    import com.liferay.portal.security.pacl.checker.JNDIChecker;
026    import com.liferay.portal.security.pacl.checker.PortalServiceChecker;
027    import com.liferay.portal.security.pacl.checker.SQLChecker;
028    import com.liferay.portal.util.PropsValues;
029    
030    import java.io.IOException;
031    
032    import java.lang.reflect.Method;
033    
034    import java.security.Permission;
035    
036    import java.util.Enumeration;
037    import java.util.Map;
038    import java.util.Properties;
039    import java.util.Set;
040    import java.util.concurrent.ConcurrentSkipListMap;
041    import java.util.concurrent.locks.ReentrantLock;
042    
043    /**
044     * @author Raymond Augé
045     */
046    public class GeneratingPACLPolicy extends ActivePACLPolicy {
047    
048            public GeneratingPACLPolicy(
049                    String servletContextName, ClassLoader classLoader,
050                    Properties properties) {
051    
052                    super(servletContextName, classLoader, properties);
053            }
054    
055            @Override
056            public void checkPermission(Permission permission) {
057                    Checker checker = getChecker(permission.getClass());
058    
059                    try {
060                            checker.checkPermission(permission);
061                    }
062                    catch (SecurityException se) {
063                            try {
064                                    AuthorizationProperty authorizationProperty =
065                                            checker.generateAuthorizationProperty(permission);
066    
067                                    mergeAuthorizationProperty(authorizationProperty);
068                            }
069                            catch (Exception e) {
070                                    throw se;
071                            }
072                    }
073            }
074    
075            @Override
076            public boolean hasJNDI(String name) {
077                    JNDIChecker jndiChecker = getJndiChecker();
078    
079                    if (!jndiChecker.hasJNDI(name)) {
080                            AuthorizationProperty authorizationProperty =
081                                    jndiChecker.generateAuthorizationProperty(name);
082    
083                            mergeAuthorizationProperty(authorizationProperty);
084                    }
085    
086                    return true;
087            }
088    
089            @Override
090            public boolean hasPortalService(
091                    Object object, Method method, Object[] arguments) {
092    
093                    PortalServiceChecker portalServiceChecker = getPortalServiceChecker();
094    
095                    if (!portalServiceChecker.hasService(object, method, arguments)) {
096                            AuthorizationProperty authorizationProperty =
097                                    portalServiceChecker.generateAuthorizationProperty(
098                                            object, method, arguments);
099    
100                            mergeAuthorizationProperty(authorizationProperty);
101                    }
102    
103                    return true;
104            }
105    
106            @Override
107            public boolean hasSQL(String sql) {
108                    SQLChecker sqlChecker = getSqlChecker();
109    
110                    if (!sqlChecker.hasSQL(sql)) {
111                            AuthorizationProperty authorizationProperty =
112                                    sqlChecker.generateAuthorizationProperty(sql);
113    
114                            mergeAuthorizationProperty(authorizationProperty);
115                    }
116    
117                    return true;
118            }
119    
120            protected void mergeAuthorizationProperty(
121                    AuthorizationProperty authorizationProperty) {
122    
123                    if (authorizationProperty == null) {
124                            return;
125                    }
126    
127                    String key = authorizationProperty.getKey();
128    
129                    Set<String> values = _properties.get(key);
130    
131                    boolean modified = false;
132    
133                    if (values == null) {
134                            values = getPropertySet(key);
135    
136                            modified = true;
137                    }
138    
139                    for (String value : authorizationProperty.getValues()) {
140                            if (!values.contains(value)) {
141                                    values.add(value);
142    
143                                    modified = true;
144                            }
145                    }
146    
147                    if (!modified) {
148                            return;
149                    }
150    
151                    _reentrantLock.lock();
152    
153                    try {
154                            if (_log.isDebugEnabled()) {
155                                    _log.debug(
156                                            getServletContextName() +
157                                                    " generated authorization property " +
158                                                            authorizationProperty);
159                            }
160    
161                            _properties.put(key, values);
162    
163                            mergeExistingProperties();
164    
165                            writePACLPolicyFile();
166                    }
167                    finally {
168                            _reentrantLock.unlock();
169                    }
170            }
171    
172            protected void mergeExistingProperties() {
173    
174                    // Merge existing properties so that the the written policy is the
175                    // complete picture rather than only a list of the modified properties.
176                    // Therefore, the developer needs only to copy the entire policy.
177    
178                    Properties properties = getProperties();
179    
180                    Enumeration<Object> enumeration = properties.keys();
181    
182                    while (enumeration.hasMoreElements()) {
183                            String key = (String)enumeration.nextElement();
184    
185                            if (_properties.containsKey(key) ||
186                                    !key.startsWith("security-manager-") ||
187                                    key.equals("security-manager-enabled")) {
188    
189                                    continue;
190                            }
191    
192                            _properties.put(key, getPropertySet(key));
193                    }
194            }
195    
196            protected void writePACLPolicyFile() {
197                    boolean enabled = PortalSecurityManagerThreadLocal.isEnabled();
198    
199                    try {
200                            PortalSecurityManagerThreadLocal.setEnabled(false);
201    
202                            StringBundler sb = new StringBundler();
203    
204                            for (Map.Entry<String, Set<String>> entry :
205                                            _properties.entrySet()) {
206    
207                                    String key = entry.getKey();
208    
209                                    sb.append(key);
210                                    sb.append(StringPool.EQUAL);
211    
212                                    Set<String> values = entry.getValue();
213    
214                                    for (String value : values) {
215                                            sb.append(StringPool.BACK_SLASH);
216                                            sb.append(StringPool.NEW_LINE);
217                                            sb.append(StringPool.FOUR_SPACES);
218                                            sb.append(value);
219                                            sb.append(StringPool.COMMA);
220                                    }
221    
222                                    sb.setIndex(sb.index() - 1);
223    
224                                    sb.append(StringPool.NEW_LINE + StringPool.NEW_LINE);
225                            }
226    
227                            if (sb.length() > 0) {
228                                    sb.setIndex(sb.index() - 1);
229                            }
230    
231                            FileUtil.write(
232                                    PropsValues.LIFERAY_HOME + "/pacl-policy",
233                                    getServletContextName() + ".pacl-policy", sb.toString());
234                    }
235                    catch (IOException ioe) {
236                            _log.error(ioe, ioe);
237                    }
238                    finally {
239                            PortalSecurityManagerThreadLocal.setEnabled(enabled);
240                    }
241            }
242    
243            private static Log _log = LogFactoryUtil.getLog(GeneratingPACLPolicy.class);
244    
245            private Map<String, Set<String>> _properties =
246                    new ConcurrentSkipListMap<String, Set<String>>();
247            private ReentrantLock _reentrantLock = new ReentrantLock();
248    
249    }