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.checker;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.util.StringPool;
020    
021    import java.security.Permission;
022    
023    import java.util.ArrayList;
024    import java.util.List;
025    import java.util.Set;
026    import java.util.regex.Matcher;
027    import java.util.regex.Pattern;
028    
029    import sun.reflect.Reflection;
030    
031    /**
032     * @author Raymond Augé
033     * @author Brian Wing Shun Chan
034     */
035    public class RuntimeChecker extends BaseChecker {
036    
037            public void afterPropertiesSet() {
038                    initEnvironmentVariables();
039            }
040    
041            @Override
042            public AuthorizationProperty generateAuthorizationProperty(
043                    Object... arguments) {
044    
045                    if ((arguments == null) || (arguments.length != 1) ||
046                            !(arguments[0] instanceof Permission)) {
047    
048                            return null;
049                    }
050    
051                    Permission permission = (Permission)arguments[0];
052    
053                    String name = permission.getName();
054    
055                    String key = null;
056                    String value = null;
057    
058                    if (name.startsWith(RUNTIME_PERMISSION_GET_ENV)) {
059                            key = "security-manager-environment-variables";
060    
061                            value = name.substring(RUNTIME_PERMISSION_GET_ENV.length() + 1);
062    
063                            // Since we are using a regular expression, we cannot allow a lone *
064                            // as the rule
065    
066                            if (value.equals(StringPool.STAR)) {
067                                    value = StringPool.DOUBLE_BACK_SLASH + value;
068                            }
069                    }
070                    else {
071                            return null;
072                    }
073    
074                    AuthorizationProperty authorizationProperty =
075                            new AuthorizationProperty();
076    
077                    authorizationProperty.setKey(key);
078                    authorizationProperty.setValue(value);
079    
080                    return authorizationProperty;
081            }
082    
083            public boolean implies(Permission permission) {
084                    String name = permission.getName();
085    
086                    if (name.startsWith(RUNTIME_PERMISSION_ACCESS_CLASS_IN_PACKAGE)) {
087                            int pos = name.indexOf(StringPool.PERIOD);
088    
089                            String pkg = name.substring(pos + 1);
090    
091                            if (!hasAccessClassInPackage(pkg)) {
092                                    logSecurityException(
093                                            _log, "Attempted to access package " + pkg);
094    
095                                    return false;
096                            }
097                    }
098                    else if (name.equals(RUNTIME_PERMISSION_ACCESS_DECLARED_MEMBERS)) {
099                            if (!hasReflect(permission)) {
100                                    logSecurityException(
101                                            _log, "Attempted to access declared members");
102    
103                                    return false;
104                            }
105                    }
106                    else if (name.equals(RUNTIME_PERMISSION_CREATE_CLASS_LOADER)) {
107                            if (!hasCreateClassLoader(permission)) {
108                                    logSecurityException(
109                                            _log, "Attempted to create a class loader");
110    
111                                    return false;
112                            }
113                    }
114                    else if (name.equals(RUNTIME_PERMISSION_CREATE_SECURITY_MANAGER)) {
115                            if (!hasCreateSecurityManager(permission)) {
116                                    logSecurityException(
117                                            _log, "Attempted to create a security manager");
118    
119                                    return false;
120                            }
121                    }
122                    else if (name.startsWith(RUNTIME_PERMISSION_GET_CLASSLOADER)) {
123                            if (!hasGetClassLoader(permission)) {
124                                    logSecurityException(_log, "Attempted to get class loader");
125    
126                                    return false;
127                            }
128                    }
129                    else if (name.startsWith(RUNTIME_PERMISSION_GET_PROTECTION_DOMAIN)) {
130                            if (!hasGetProtectionDomain(permission)) {
131                                    logSecurityException(
132                                            _log, "Attempted to get protection domain");
133    
134                                    return false;
135                            }
136                    }
137                    else if (name.startsWith(RUNTIME_PERMISSION_GET_ENV)) {
138                            int pos = name.indexOf(StringPool.PERIOD);
139    
140                            String envName = name.substring(pos + 1);
141    
142                            if (!hasGetEnv(envName, permission)) {
143                                    logSecurityException(
144                                            _log, "Attempted to get environment name " + envName);
145    
146                                    return false;
147                            }
148                    }
149                    else if (name.startsWith(RUNTIME_PERMISSION_LOAD_LIBRARY)) {
150                            if (!hasLoadLibrary(permission)) {
151                                    logSecurityException(_log, "Attempted to load library");
152    
153                                    return false;
154                            }
155                    }
156                    else if (name.equals(RUNTIME_PERMISSION_READ_FILE_DESCRIPTOR)) {
157                            if (!hasReadFileDescriptor(permission)) {
158                                    logSecurityException(_log, "Attempted to read file descriptor");
159    
160                                    return false;
161                            }
162                    }
163                    else if (name.equals(RUNTIME_PERMISSION_SET_CONTEXT_CLASS_LOADER)) {
164                            if (!hasSetContextClassLoader(permission)) {
165                                    logSecurityException(
166                                            _log, "Attempted to set the context class loader");
167    
168                                    return false;
169                            }
170                    }
171                    else if (name.equals(RUNTIME_PERMISSION_SET_SECURITY_MANAGER)) {
172                            logSecurityException(
173                                    _log, "Attempted to set another security manager");
174    
175                            return false;
176                    }
177                    else if (name.equals(RUNTIME_PERMISSION_WRITE_FILE_DESCRIPTOR)) {
178                            if (!hasWriteFileDescriptor(permission)) {
179                                    logSecurityException(
180                                            _log, "Attempted to write file descriptor");
181    
182                                    return false;
183                            }
184                    }
185                    else {
186                            if (_log.isDebugEnabled()) {
187                                    Thread.dumpStack();
188                            }
189    
190                            logSecurityException(
191                                    _log, "Attempted to " + permission.getName() + " on " +
192                                            permission.getActions());
193    
194                            return false;
195                    }
196    
197                    return true;
198            }
199    
200            protected boolean hasAccessClassInPackage(String pkg) {
201    
202                    // TODO
203    
204                    if (pkg.startsWith("sun.reflect")) {
205                    }
206    
207                    return true;
208            }
209    
210            protected boolean hasCreateClassLoader(Permission permission) {
211                    int stackIndex = getStackIndex(15, 11);
212    
213                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
214    
215                    if (isTrustedCaller(callerClass, permission)) {
216                            return true;
217                    }
218    
219                    return false;
220            }
221    
222            protected boolean hasCreateSecurityManager(Permission permission) {
223                    int stackIndex = getStackIndex(11, 10);
224    
225                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
226    
227                    if (isTrustedCaller(callerClass, permission)) {
228                            return true;
229                    }
230    
231                    return false;
232            }
233    
234            protected boolean hasGetClassLoader(Permission permission) {
235                    int stackIndex = getStackIndex(11, 10);
236    
237                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
238    
239                    if (isTrustedCaller(callerClass, permission)) {
240                            return true;
241                    }
242    
243                    return false;
244            }
245    
246            protected boolean hasGetEnv(String name, Permission permission) {
247                    for (Pattern environmentVariablePattern :
248                                    _environmentVariablePatterns) {
249    
250                            Matcher matcher = environmentVariablePattern.matcher(name);
251    
252                            if (matcher.matches()) {
253                                    return true;
254                            }
255                    }
256    
257                    int stackIndex = getStackIndex(11, 10);
258    
259                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
260    
261                    if (isTrustedCaller(callerClass, permission)) {
262                            return true;
263                    }
264    
265                    return false;
266            }
267    
268            protected boolean hasGetProtectionDomain(Permission permission) {
269                    int stackIndex = getStackIndex(11, 10);
270    
271                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
272    
273                    if (isTrustedCaller(callerClass, permission)) {
274                            return true;
275                    }
276    
277                    return false;
278            }
279    
280            protected boolean hasLoadLibrary(Permission permission) {
281                    int stackIndex = getStackIndex(13, 12);
282    
283                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
284    
285                    if (isTrustedCaller(callerClass, permission)) {
286                            return true;
287                    }
288    
289                    return false;
290            }
291    
292            protected boolean hasReadFileDescriptor(Permission permission) {
293                    int stackIndex = getStackIndex(12, 11);
294    
295                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
296    
297                    if (isTrustedCaller(callerClass, permission)) {
298                            return true;
299                    }
300    
301                    return false;
302            }
303    
304            protected boolean hasReflect(Permission permission) {
305                    int stackIndex = getStackIndex(13, 12);
306    
307                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
308    
309                    if (isTrustedCaller(callerClass, permission)) {
310                            return true;
311                    }
312    
313                    return false;
314            }
315    
316            protected boolean hasSetContextClassLoader(Permission permission) {
317                    int stackIndex = getStackIndex(11, 10);
318    
319                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
320    
321                    if (isTrustedCaller(callerClass, permission)) {
322                            return true;
323                    }
324    
325                    return false;
326            }
327    
328            protected boolean hasWriteFileDescriptor(Permission permission) {
329                    int stackIndex = getStackIndex(12, 11);
330    
331                    Class<?> callerClass = Reflection.getCallerClass(stackIndex);
332    
333                    if (isTrustedCaller(callerClass, permission)) {
334                            return true;
335                    }
336    
337                    return false;
338            }
339    
340            protected void initEnvironmentVariables() {
341                    Set<String> environmentVariables = getPropertySet(
342                            "security-manager-environment-variables");
343    
344                    _environmentVariablePatterns = new ArrayList<Pattern>(
345                            environmentVariables.size());
346    
347                    for (String environmentVariable : environmentVariables) {
348                            Pattern environmentVariablePattern = Pattern.compile(
349                                    environmentVariable);
350    
351                            _environmentVariablePatterns.add(environmentVariablePattern);
352    
353                            if (_log.isDebugEnabled()) {
354                                    _log.debug(
355                                            "Allowing access to environment variables that match " +
356                                                    "the regular expression " + environmentVariable);
357                            }
358                    }
359            }
360    
361            private static Log _log = LogFactoryUtil.getLog(RuntimeChecker.class);
362    
363            private List<Pattern> _environmentVariablePatterns;
364    
365    }