/** * 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.concurrent.ConcurrentReferenceValueHashMap; import com.liferay.portal.kernel.memory.FinalizeManager; import com.liferay.portal.kernel.security.pacl.permission.PortalHookPermission; import com.liferay.portal.kernel.security.pacl.permission.PortalMessageBusPermission; import com.liferay.portal.kernel.security.pacl.permission.PortalRuntimePermission; import com.liferay.portal.kernel.security.pacl.permission.PortalServicePermission; import com.liferay.portal.kernel.util.JavaDetector; import java.lang.reflect.Field; import java.security.AccessControlException; import java.security.AccessController; import java.security.AllPermission; import java.security.CodeSource; import java.security.Permission; import java.security.PermissionCollection; import java.security.Policy; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; import java.util.Enumeration; import java.util.concurrent.ConcurrentMap; /** * @author Raymond Augé */ public class PortalPolicy extends Policy { public PortalPolicy(Policy policy) throws PrivilegedActionException { if (policy instanceof PortalPolicy) { throw new IllegalArgumentException( "Liferay's PortalPolicy class should not wrap itself"); } _policy = policy; _field = AccessController.doPrivileged( new FieldPrivilegedExceptionAction()); } public Policy getOriginalPolicy() { return _policy; } @Override public PermissionCollection getPermissions(CodeSource codeSource) { if ((codeSource == null) || (codeSource.getLocation() == null)) { return new LenientPermissionCollection(); } URLWrapper urlWrapper = new URLWrapper(codeSource.getLocation()); PermissionCollection permissionCollection = _urlPermissionCollections.get(urlWrapper); if (permissionCollection != null) { return permissionCollection; } PACLPolicy paclPolicy = PACLPolicyManager.getPACLPolicy( codeSource.getLocation()); if (paclPolicy != null) { permissionCollection = new PortalPermissionCollection(paclPolicy); } else { permissionCollection = new LenientPermissionCollection(); } _urlPermissionCollections.put(urlWrapper, permissionCollection); return permissionCollection; } @Override public PermissionCollection getPermissions( ProtectionDomain protectionDomain) { if (protectionDomain == null) { return new LenientPermissionCollection(); } Object key = _getKey(protectionDomain); PermissionCollection permissionCollection = null; if (key != null) { permissionCollection = _permissionCollections.get(key); } if (permissionCollection == null) { CodeSource codeSource = protectionDomain.getCodeSource(); if ((codeSource != null) && (codeSource.getLocation() != null)) { permissionCollection = _urlPermissionCollections.get( new URLWrapper(codeSource.getLocation())); } } if (permissionCollection != null) { return permissionCollection; } PACLPolicy paclPolicy = PACLPolicyManager.getPACLPolicy( protectionDomain); if (paclPolicy != null) { permissionCollection = new PortalPermissionCollection(paclPolicy); } else { if (JavaDetector.isIBM()) { permissionCollection = _policy.getPermissions(protectionDomain); } else { permissionCollection = new LenientPermissionCollection(); } } if (key != null) { _permissionCollections.put(key, permissionCollection); } return permissionCollection; } @Override public boolean implies( ProtectionDomain protectionDomain, Permission permission) { if (_started.get()) { return true; } try { _started.set(true); PermissionCollection permissionCollection = null; if (JavaDetector.isIBM()) { permissionCollection = getPermissions(protectionDomain); if ((permissionCollection != null) && !(permissionCollection instanceof PortalPermissionCollection)) { Enumeration<Permission> enumeration = permissionCollection.elements(); while (enumeration.hasMoreElements()) { Permission curPermission = enumeration.nextElement(); if (curPermission instanceof AllPermission) { return true; } } } } if (!(permission instanceof PACLUtil.Permission) && !_paclPolicy.isCheckablePermission(permission)) { return _checkWithParentPolicy(protectionDomain, permission); } if (!JavaDetector.isIBM()) { permissionCollection = getPermissions(protectionDomain); } if (permissionCollection instanceof PortalPermissionCollection) { if (permissionCollection.implies(permission) || _checkWithPACLPolicyPolicy( protectionDomain, permission, permissionCollection)) { return true; } throw new AccessControlException( "Access denied " + permission, permission); } return _checkWithParentPolicy(protectionDomain, permission); } finally { _started.remove(); } } @Override public void refresh() { if (_policy != null) { _policy.refresh(); } synchronized (_permissionCollections) { _permissionCollections.clear(); _urlPermissionCollections.clear(); } } private boolean _checkWithPACLPolicyPolicy( ProtectionDomain protectionDomain, Permission permission, PermissionCollection permissionCollection) { PortalPermissionCollection portalPermissionCollection = (PortalPermissionCollection)permissionCollection; Policy policy = portalPermissionCollection.getPolicy(); ClassLoader classLoader = portalPermissionCollection.getClassLoader(); if ((policy != null) && (classLoader == protectionDomain.getClassLoader())) { return policy.implies(protectionDomain, permission); } return false; } @SuppressWarnings("deprecation") private boolean _checkWithParentPolicy( ProtectionDomain protectionDomain, Permission permission) { if ((_policy != null) && !(permission instanceof PortalHookPermission) && !(permission instanceof PortalMessageBusPermission) && !(permission instanceof PortalRuntimePermission) && !(permission instanceof PortalServicePermission) && !(permission instanceof PACLUtil.Permission)) { return _policy.implies(protectionDomain, permission); } return true; } private Object _getKey(ProtectionDomain protectionDomain) { try { return _field.get(protectionDomain); } catch (Exception e) { return null; } } private static final ThreadLocal<Boolean> _started = new ThreadLocal<Boolean>() { @Override protected Boolean initialValue() { return Boolean.FALSE; } }; private final Field _field; private final PACLPolicy _paclPolicy = PACLPolicyManager.getDefaultPACLPolicy(); private final ConcurrentMap<Object, PermissionCollection> _permissionCollections = new ConcurrentReferenceValueHashMap<>( FinalizeManager.WEAK_REFERENCE_FACTORY); private final Policy _policy; private final ConcurrentMap<URLWrapper, PermissionCollection> _urlPermissionCollections = new ConcurrentReferenceValueHashMap<>( FinalizeManager.WEAK_REFERENCE_FACTORY); private static class FieldPrivilegedExceptionAction implements PrivilegedExceptionAction<Field> { @Override public Field run() throws Exception { Field field = ProtectionDomain.class.getDeclaredField("key"); field.setAccessible(true); return field; } } }