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