/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.security.pacl;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.url.URLContainer;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.PropsUtil;
import com.liferay.portal.kernel.util.SetUtil;
import com.liferay.portal.kernel.util.SortedProperties;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.security.pacl.checker.Checker;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.Permission;
import java.security.Permissions;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.security.Provider;
import java.security.Security;
import java.security.URIParameter;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
/**
* @author Brian Wing Shun Chan
*/
public abstract class BasePACLPolicy implements PACLPolicy {
public BasePACLPolicy(
String contextName, URLContainer urlContainer, ClassLoader classLoader,
Properties properties) {
_contextName = contextName;
_urlContainer = urlContainer;
_classLoader = classLoader;
_properties = properties;
try {
initCheckers();
initPolicy();
}
catch (Exception e) {
_log.error(e, e);
}
}
@Override
public ClassLoader getClassLoader() {
return _classLoader;
}
@Override
public String getContextName() {
return _contextName;
}
@Override
public Policy getPolicy() {
return _policy;
}
@Override
public Properties getProperties() {
return _properties;
}
@Override
public String getProperty(String key) {
return _properties.getProperty(key);
}
@Override
public String[] getPropertyArray(String key) {
return StringUtil.split(getProperty(key));
}
@Override
public boolean getPropertyBoolean(String key) {
return GetterUtil.getBoolean(getProperty(key));
}
@Override
public Set<String> getPropertySet(String key) {
return new TreeSet<>(SetUtil.fromArray(getPropertyArray(key)));
}
@Override
public URLContainer getURLContainer() {
return _urlContainer;
}
@Override
public List<URL> getURLs() {
return _urls;
}
@Override
public boolean isCheckablePermission(Permission permission) {
Class<?> clazz = permission.getClass();
return _checkers.containsKey(clazz.getName());
}
@Override
public String toString() {
StringBundler sb = new StringBundler(7);
sb.append("{active=");
sb.append(isActive());
sb.append(", contextName=");
sb.append(_contextName);
sb.append(", hashCode=");
sb.append(hashCode());
sb.append("}");
return sb.toString();
}
protected void checkForAllPermission(Policy policy, URL rootURL)
throws MalformedURLException {
CodeSource codeSource = new CodeSource(rootURL, new Certificate[0]);
ProtectionDomain protectionDomain = new ProtectionDomain(
codeSource, new Permissions());
if (policy.implies(protectionDomain, new AllPermission())) {
throw new IllegalStateException(
"The plugin's Java policy tried to declared all permissions");
}
}
protected Checker getChecker(Class<? extends Permission> clazz) {
return _checkers.get(clazz.getName());
}
protected Provider getProvider() {
String providerName = "SUN";
return Security.getProvider(providerName);
}
protected Checker initChecker(Checker checker) {
checker.setPACLPolicy(this);
checker.afterPropertiesSet();
return checker;
}
protected void initCheckers() throws Exception {
Class<?> clazz = getClass();
ClassLoader classLoader = clazz.getClassLoader();
Properties portalProperties = PropsUtil.getProperties(
"portal.security.manager.pacl.policy.checker", false);
portalProperties = new SortedProperties(portalProperties);
if (_log.isInfoEnabled()) {
_log.info(
"Registering " + portalProperties.size() +
" PACL policy checkers");
}
for (Map.Entry<Object, Object> entry : portalProperties.entrySet()) {
String key = (String)entry.getKey();
int x = key.indexOf("[");
int y = key.indexOf("]");
String permissionClassName = key.substring(x + 1, y);
String checkerClassName = (String)entry.getValue();
Class<?> checkerClass = classLoader.loadClass(checkerClassName);
Checker checker = (Checker)checkerClass.newInstance();
initChecker(checker);
if (_log.isInfoEnabled()) {
_log.info(
"Registering permission " + permissionClassName +
" with PACL policy " + checkerClassName);
}
_checkers.put(permissionClassName, checker);
}
}
protected void initPolicy() throws Exception {
URL url = _urlContainer.getResource("/WEB-INF/java.policy");
if (url == null) {
return;
}
// Set a system property to match the servletContextName so that the
// plugin can use it in it's Java security policy file for setting the
// code base
URL rootURL = _urlContainer.getResource(StringPool.SLASH);
System.setProperty(_contextName, rootURL.getPath());
try {
URIParameter parameter = new URIParameter(url.toURI());
Policy policy = Policy.getInstance(
"JavaPolicy", parameter, getProvider());
checkForAllPermission(policy, rootURL);
_policy = policy;
}
catch (Exception e) {
_log.error("Unable to initialize Java policy " + url.toString(), e);
}
}
private static final Log _log = LogFactoryUtil.getLog(BasePACLPolicy.class);
private final Map<String, Checker> _checkers = new HashMap<>();
private final ClassLoader _classLoader;
private final String _contextName;
private Policy _policy;
private final Properties _properties;
private final URLContainer _urlContainer;
private final List<URL> _urls = new ArrayList<>();
}