/** * 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.permission; import com.liferay.exportimport.kernel.lar.ExportImportThreadLocal; import com.liferay.portal.kernel.cache.MultiVMPoolUtil; import com.liferay.portal.kernel.cache.PortalCache; import com.liferay.portal.kernel.cache.PortalCacheHelperUtil; import com.liferay.portal.kernel.cache.index.IndexEncoder; import com.liferay.portal.kernel.cache.index.PortalCacheIndexer; import com.liferay.portal.kernel.cluster.ClusterExecutorUtil; import com.liferay.portal.kernel.cluster.ClusterInvokeThreadLocal; import com.liferay.portal.kernel.cluster.ClusterRequest; import com.liferay.portal.kernel.model.ResourceConstants; import com.liferay.portal.kernel.model.Role; import com.liferay.portal.kernel.security.permission.PermissionThreadLocal; import com.liferay.portal.kernel.security.permission.ResourceBlockIdsBag; import com.liferay.portal.kernel.security.permission.UserBag; import com.liferay.portal.kernel.util.HashUtil; import com.liferay.portal.kernel.util.MethodHandler; import com.liferay.portal.kernel.util.MethodKey; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.util.PropsValues; import java.io.Serializable; import java.util.Arrays; import java.util.Objects; /** * @author Charles May * @author Michael Young * @author Shuyang Zhou * @author Connor McKay * @author László Csontos */ public class PermissionCacheUtil { public static final String PERMISSION_CACHE_NAME = PermissionCacheUtil.class.getName() + "_PERMISSION"; public static final String PERMISSION_CHECKER_BAG_CACHE_NAME = PermissionCacheUtil.class.getName() + "_PERMISSION_CHECKER_BAG"; public static final String RESOURCE_BLOCK_IDS_BAG_CACHE_NAME = PermissionCacheUtil.class.getName() + "_RESOURCE_BLOCK_IDS_BAG"; public static final String USER_BAG_CACHE_NAME = PermissionCacheUtil.class.getName() + "_USER_BAG"; public static final String USER_PRIMARY_KEY_ROLE_CACHE_NAME = PermissionCacheUtil.class.getName() + "_USER_PRIMARY_KEY_ROLE"; public static final String USER_ROLE_CACHE_NAME = PermissionCacheUtil.class.getName() + "_USER_ROLE"; public static void clearCache() { if (ExportImportThreadLocal.isImportInProcess()) { return; } _userRolePortalCache.removeAll(); _userGroupRoleIdsPortalCache.removeAll(); _permissionPortalCache.removeAll(); _resourceBlockIdsBagCache.removeAll(); _userBagPortalCache.removeAll(); _userPrimaryKeyRolePortalCache.removeAll(); } public static void clearCache(long... userIds) { if (ExportImportThreadLocal.isImportInProcess()) { return; } for (long userId : userIds) { _userBagPortalCache.remove(userId); _userGroupRoleIdsPortalCacheIndexer.removeKeys(userId); _userPrimaryKeyRolePortalCacheUserIdIndexer.removeKeys(userId); _userRolePortalCacheIndexer.removeKeys(userId); } _permissionPortalCache.removeAll(); _resourceBlockIdsBagCache.removeAll(); _sendClearCacheClusterMessage(_clearCacheMethodKey, userIds); } public static void clearPrimaryKeyRoleCache() { if (ExportImportThreadLocal.isImportInProcess()) { return; } _permissionPortalCache.removeAll(); _resourceBlockIdsBagCache.removeAll(); _userPrimaryKeyRolePortalCache.removeAll(); } public static void clearResourceBlockCache( long companyId, long groupId, String name) { if (ExportImportThreadLocal.isImportInProcess() || !PermissionThreadLocal.isFlushResourceBlockEnabled( companyId, groupId, name)) { return; } _resourceBlockIdsBagCacheIndexer.removeKeys( ResourceBlockIdsBagKeyIndexEncoder.encode( companyId, groupId, name)); _sendClearCacheClusterMessage( _clearResourceBlockCacheMethodKey, companyId, groupId, name); } public static void clearResourceCache() { if (!ExportImportThreadLocal.isImportInProcess()) { _resourceBlockIdsBagCache.removeAll(); _permissionPortalCache.removeAll(); } } public static void clearResourcePermissionCache( int scope, String name, String primKey) { if (ExportImportThreadLocal.isImportInProcess() || !PermissionThreadLocal.isFlushResourcePermissionEnabled( name, primKey)) { return; } if (scope == ResourceConstants.SCOPE_INDIVIDUAL) { _permissionPortalCacheNamePrimKeyIndexer.removeKeys( PermissionKeyNamePrimKeyIndexEncoder.encode(name, primKey)); _sendClearCacheClusterMessage( _clearResourcePermissionCacheMethodKey, scope, name, primKey); } else if (scope == ResourceConstants.SCOPE_GROUP) { _permissionPortalCacheGroupIdIndexer.removeKeys( Long.valueOf(primKey)); _sendClearCacheClusterMessage( _clearResourcePermissionCacheMethodKey, scope, name, primKey); } else { _permissionPortalCache.removeAll(); } } public static Boolean getPermission( long groupId, String name, String primKey, long[] roleIds, String actionId) { PermissionKey permissionKey = new PermissionKey( groupId, name, primKey, roleIds, actionId); return _permissionPortalCache.get(permissionKey); } public static ResourceBlockIdsBag getResourceBlockIdsBag( long companyId, long groupId, long userId, String name) { ResourceBlockIdsBagKey resourceBlockIdsBagKey = new ResourceBlockIdsBagKey(companyId, groupId, userId, name); return _resourceBlockIdsBagCache.get(resourceBlockIdsBagKey); } public static UserBag getUserBag(long userId) { return _userBagPortalCache.get(userId); } public static long[] getUserGroupRoleIds(long userId, long groupId) { UserGroupRoleIdsKey userGroupRoleIdsKey = new UserGroupRoleIdsKey( userId, groupId); return _userGroupRoleIdsPortalCache.get(userGroupRoleIdsKey); } public static Boolean getUserPrimaryKeyRole( long userId, long primaryKey, String roleName) { UserPrimaryKeyRoleKey userPrimaryKeyRoleKey = new UserPrimaryKeyRoleKey( userId, primaryKey, roleName); return _userPrimaryKeyRolePortalCache.get(userPrimaryKeyRoleKey); } public static Boolean getUserRole(long userId, Role role) { UserRoleKey userRoleKey = new UserRoleKey(userId, role.getRoleId()); Boolean userRole = _userRolePortalCache.get(userRoleKey); if (userRole != null) { return userRole; } UserBag userBag = getUserBag(userId); if (userBag == null) { return null; } userRole = userBag.hasRole(role); PortalCacheHelperUtil.putWithoutReplicator( _userRolePortalCache, userRoleKey, userRole); return userRole; } public static void putPermission( long groupId, String name, String primKey, long[] roleIds, String actionId, Boolean value) { PermissionKey permissionKey = new PermissionKey( groupId, name, primKey, roleIds, actionId); PortalCacheHelperUtil.putWithoutReplicator( _permissionPortalCache, permissionKey, value); } public static void putResourceBlockIdsBag( long companyId, long groupId, long userId, String name, ResourceBlockIdsBag resourceBlockIdsBag) { if (resourceBlockIdsBag == null) { return; } ResourceBlockIdsBagKey resourceBlockIdsBagKey = new ResourceBlockIdsBagKey(companyId, groupId, userId, name); PortalCacheHelperUtil.putWithoutReplicator( _resourceBlockIdsBagCache, resourceBlockIdsBagKey, resourceBlockIdsBag); } public static void putUserBag(long userId, UserBag userBag) { PortalCacheHelperUtil.putWithoutReplicator( _userBagPortalCache, userId, userBag); } public static void putUserGroupRoleIds( long userId, long groupId, long[] roleIds) { if (roleIds == null) { return; } UserGroupRoleIdsKey userGroupRoleIdsKey = new UserGroupRoleIdsKey( userId, groupId); PortalCacheHelperUtil.putWithoutReplicator( _userGroupRoleIdsPortalCache, userGroupRoleIdsKey, roleIds); } public static void putUserPrimaryKeyRole( long userId, long primaryKey, String roleName, Boolean value) { if (value == null) { return; } UserPrimaryKeyRoleKey userPrimaryKeyRoleKey = new UserPrimaryKeyRoleKey( userId, primaryKey, roleName); PortalCacheHelperUtil.putWithoutReplicator( _userPrimaryKeyRolePortalCache, userPrimaryKeyRoleKey, value); } public static void putUserRole(long userId, Role role, Boolean value) { if (value == null) { return; } UserRoleKey userRoleKey = new UserRoleKey(userId, role.getRoleId()); PortalCacheHelperUtil.putWithoutReplicator( _userRolePortalCache, userRoleKey, value); } public static void removePermission( long groupId, String name, String primKey, long[] roleIds, String actionId) { PermissionKey permissionKey = new PermissionKey( groupId, name, primKey, roleIds, actionId); _permissionPortalCache.remove(permissionKey); } public static void removeResourceBlockIdsBag( long companyId, long groupId, long userId, String name) { ResourceBlockIdsBagKey resourceBlockIdsBagKey = new ResourceBlockIdsBagKey(companyId, groupId, userId, name); _resourceBlockIdsBagCache.remove(resourceBlockIdsBagKey); } public static void removeUserBag(long userId) { _userBagPortalCache.remove(userId); } public static void removeUserGroupRoleIds(long userId, long groupId) { UserGroupRoleIdsKey userGroupRoleIdsKey = new UserGroupRoleIdsKey( userId, groupId); _userGroupRoleIdsPortalCache.remove(userGroupRoleIdsKey); } public static void removeUserPrimaryKeyRole( long userId, long primaryKey, String roleName) { UserPrimaryKeyRoleKey userPrimaryKeyRoleKey = new UserPrimaryKeyRoleKey( userId, primaryKey, roleName); _userPrimaryKeyRolePortalCache.remove(userPrimaryKeyRoleKey); } private static void _sendClearCacheClusterMessage( MethodKey methodKey, Object... arguments) { if (!ClusterInvokeThreadLocal.isEnabled()) { return; } ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest( new MethodHandler(methodKey, arguments), true); clusterRequest.setFireAndForget(true); ClusterExecutorUtil.execute(clusterRequest); } private static final MethodKey _clearCacheMethodKey = new MethodKey( PermissionCacheUtil.class, "clearCache", long[].class); private static final MethodKey _clearResourceBlockCacheMethodKey = new MethodKey( PermissionCacheUtil.class, "clearResourceBlockCache", long.class, long.class, String.class); private static final MethodKey _clearResourcePermissionCacheMethodKey = new MethodKey( PermissionCacheUtil.class, "clearResourcePermissionCache", int.class, String.class, String.class); private static final PortalCache<PermissionKey, Boolean> _permissionPortalCache = MultiVMPoolUtil.getPortalCache( PERMISSION_CACHE_NAME, PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE); private static final PortalCacheIndexer<Long, PermissionKey, Boolean> _permissionPortalCacheGroupIdIndexer = new PortalCacheIndexer<>( new PermissionKeyGroupIdIndexEncoder(), _permissionPortalCache); private static final PortalCacheIndexer<String, PermissionKey, Boolean> _permissionPortalCacheNamePrimKeyIndexer = new PortalCacheIndexer<>( new PermissionKeyNamePrimKeyIndexEncoder(), _permissionPortalCache); private static final PortalCache<ResourceBlockIdsBagKey, ResourceBlockIdsBag> _resourceBlockIdsBagCache = MultiVMPoolUtil.getPortalCache( RESOURCE_BLOCK_IDS_BAG_CACHE_NAME, PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE); private static final PortalCacheIndexer <String, ResourceBlockIdsBagKey, ResourceBlockIdsBag> _resourceBlockIdsBagCacheIndexer = new PortalCacheIndexer<>( new ResourceBlockIdsBagKeyIndexEncoder(), _resourceBlockIdsBagCache); private static final PortalCache<Long, UserBag> _userBagPortalCache = MultiVMPoolUtil.getPortalCache( USER_BAG_CACHE_NAME, PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE); private static final PortalCache<UserGroupRoleIdsKey, long[]> _userGroupRoleIdsPortalCache = MultiVMPoolUtil.getPortalCache( PERMISSION_CHECKER_BAG_CACHE_NAME, PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE); private static final PortalCacheIndexer<Long, UserGroupRoleIdsKey, long[]> _userGroupRoleIdsPortalCacheIndexer = new PortalCacheIndexer<>( new UserGroupRoleIdsKeyIndexEncoder(), _userGroupRoleIdsPortalCache); private static final PortalCache<UserPrimaryKeyRoleKey, Boolean> _userPrimaryKeyRolePortalCache = MultiVMPoolUtil.getPortalCache( USER_PRIMARY_KEY_ROLE_CACHE_NAME, PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE); private static final PortalCacheIndexer <Long, UserPrimaryKeyRoleKey, Boolean> _userPrimaryKeyRolePortalCacheUserIdIndexer = new PortalCacheIndexer<>( new UserGroupRoleKeyUserIdEncoder(), _userPrimaryKeyRolePortalCache); private static final PortalCache<UserRoleKey, Boolean> _userRolePortalCache = MultiVMPoolUtil.getPortalCache( USER_ROLE_CACHE_NAME, PropsValues.PERMISSIONS_OBJECT_BLOCKING_CACHE); private static final PortalCacheIndexer<Long, UserRoleKey, Boolean> _userRolePortalCacheIndexer = new PortalCacheIndexer<>( new UserRoleKeyIndexEncoder(), _userRolePortalCache); private static class PermissionKey implements Serializable { @Override public boolean equals(Object obj) { PermissionKey permissionKey = (PermissionKey)obj; if ((permissionKey._groupId == _groupId) && Objects.equals(permissionKey._name, _name) && Objects.equals(permissionKey._primKey, _primKey) && Arrays.equals(permissionKey._roleIds, _roleIds) && Objects.equals(permissionKey._actionId, _actionId)) { return true; } return false; } @Override public int hashCode() { int hashCode = HashUtil.hash(0, _groupId); hashCode = HashUtil.hash(hashCode, _name); hashCode = HashUtil.hash(hashCode, _primKey); hashCode = HashUtil.hash(hashCode, _roleIds.length); for (long roleId : _roleIds) { hashCode = HashUtil.hash(hashCode, roleId); } hashCode = HashUtil.hash(hashCode, _actionId); return hashCode; } private PermissionKey( long groupId, String name, String primKey, long[] roleIds, String actionId) { _groupId = groupId; _name = name; _primKey = primKey; _roleIds = roleIds; _actionId = actionId; } private static final long serialVersionUID = 1L; private final String _actionId; private final long _groupId; private final String _name; private final String _primKey; private final long[] _roleIds; } private static class PermissionKeyGroupIdIndexEncoder implements IndexEncoder<Long, PermissionKey> { @Override public Long encode(PermissionKey permissionKey) { return permissionKey._groupId; } } private static class PermissionKeyNamePrimKeyIndexEncoder implements IndexEncoder<String, PermissionKey> { public static String encode(String name, String primKey) { return name.concat(StringPool.UNDERLINE).concat(primKey); } @Override public String encode(PermissionKey permissionKey) { return encode(permissionKey._name, permissionKey._primKey); } } private static class ResourceBlockIdsBagKey implements Serializable { @Override public boolean equals(Object obj) { ResourceBlockIdsBagKey resourceBlockIdsKey = (ResourceBlockIdsBagKey)obj; if ((resourceBlockIdsKey._companyId == _companyId) && (resourceBlockIdsKey._groupId == _groupId) && (resourceBlockIdsKey._userId == _userId) && Objects.equals(resourceBlockIdsKey._name, _name)) { return true; } return false; } @Override public int hashCode() { int hashCode = HashUtil.hash(0, _companyId); hashCode = HashUtil.hash(hashCode, _groupId); hashCode = HashUtil.hash(hashCode, _userId); hashCode = HashUtil.hash(hashCode, _name); return hashCode; } private ResourceBlockIdsBagKey( long companyId, long groupId, long userId, String name) { _companyId = companyId; _groupId = groupId; _userId = userId; _name = name; } private static final long serialVersionUID = 1L; private final long _companyId; private final long _groupId; private final String _name; private final long _userId; } private static class ResourceBlockIdsBagKeyIndexEncoder implements IndexEncoder<String, ResourceBlockIdsBagKey> { public static String encode(long companyId, long groupId, String name) { StringBundler sb = new StringBundler(5); sb.append(companyId); sb.append(StringPool.UNDERLINE); sb.append(groupId); sb.append(StringPool.UNDERLINE); sb.append(name); return sb.toString(); } @Override public String encode(ResourceBlockIdsBagKey resourceBlockIdsBagKey) { return encode( resourceBlockIdsBagKey._companyId, resourceBlockIdsBagKey._groupId, resourceBlockIdsBagKey._name); } } private static class UserGroupRoleIdsKey implements Serializable { @Override public boolean equals(Object obj) { UserGroupRoleIdsKey userGroupRoleIdsKey = (UserGroupRoleIdsKey)obj; if ((userGroupRoleIdsKey._userId == _userId) && (userGroupRoleIdsKey._groupId == _groupId)) { return true; } return false; } @Override public int hashCode() { int hashCode = HashUtil.hash(0, _userId); return HashUtil.hash(hashCode, _groupId); } private UserGroupRoleIdsKey(long userId, long groupId) { _userId = userId; _groupId = groupId; } private static final long serialVersionUID = 1L; private final long _groupId; private final long _userId; } private static class UserGroupRoleIdsKeyIndexEncoder implements IndexEncoder<Long, UserGroupRoleIdsKey> { @Override public Long encode(UserGroupRoleIdsKey userGroupRoleIdsKey) { return userGroupRoleIdsKey._userId; } } private static class UserGroupRoleKeyUserIdEncoder implements IndexEncoder<Long, UserPrimaryKeyRoleKey> { @Override public Long encode(UserPrimaryKeyRoleKey key) { return key._userId; } } private static class UserPrimaryKeyRoleKey implements Serializable { @Override public boolean equals(Object obj) { UserPrimaryKeyRoleKey userPrimaryKeyRoleKey = (UserPrimaryKeyRoleKey)obj; if ((userPrimaryKeyRoleKey._userId == _userId) && (userPrimaryKeyRoleKey._primaryKey == _primaryKey) && Objects.equals(userPrimaryKeyRoleKey._name, _name)) { return true; } return false; } @Override public int hashCode() { int hashCode = HashUtil.hash(0, _userId); hashCode = HashUtil.hash(hashCode, _primaryKey); hashCode = HashUtil.hash(hashCode, _name); return hashCode; } private UserPrimaryKeyRoleKey( long userId, long primaryKey, String name) { _userId = userId; _primaryKey = primaryKey; _name = name; } private static final long serialVersionUID = 1L; private final String _name; private final long _primaryKey; private final long _userId; } private static class UserRoleKey implements Serializable { @Override public boolean equals(Object obj) { UserRoleKey userRoleKey = (UserRoleKey)obj; if ((userRoleKey._userId == _userId) && (userRoleKey._roleId == _roleId)) { return true; } return false; } @Override public int hashCode() { int hashCode = HashUtil.hash(0, _userId); return HashUtil.hash(hashCode, _roleId); } private UserRoleKey(long userId, long roleId) { _userId = userId; _roleId = roleId; } private static final long serialVersionUID = 1L; private final long _roleId; private final long _userId; } private static class UserRoleKeyIndexEncoder implements IndexEncoder<Long, UserRoleKey> { @Override public Long encode(UserRoleKey userRoleKey) { return userRoleKey._userId; } } }