/** * 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.verify; import com.liferay.portal.dao.orm.common.SQLTransformer; import com.liferay.portal.kernel.dao.db.DB; import com.liferay.portal.kernel.dao.db.DBManagerUtil; import com.liferay.portal.kernel.dao.db.DBType; import com.liferay.portal.kernel.dao.jdbc.AutoBatchPreparedStatementUtil; import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery; import com.liferay.portal.kernel.dao.orm.DynamicQuery; import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil; import com.liferay.portal.kernel.dao.orm.EntityCacheUtil; import com.liferay.portal.kernel.dao.orm.FinderCacheUtil; import com.liferay.portal.kernel.dao.orm.Property; import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil; import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.Group; import com.liferay.portal.kernel.model.Layout; import com.liferay.portal.kernel.model.LayoutConstants; import com.liferay.portal.kernel.model.Organization; import com.liferay.portal.kernel.model.PortletConstants; import com.liferay.portal.kernel.model.ResourceConstants; import com.liferay.portal.kernel.model.ResourcePermission; import com.liferay.portal.kernel.model.Role; import com.liferay.portal.kernel.model.RoleConstants; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.model.UserGroup; import com.liferay.portal.kernel.security.permission.ActionKeys; import com.liferay.portal.kernel.security.permission.ResourceActionsUtil; import com.liferay.portal.kernel.service.LayoutLocalServiceUtil; import com.liferay.portal.kernel.service.ResourceActionLocalServiceUtil; import com.liferay.portal.kernel.service.ResourcePermissionLocalServiceUtil; import com.liferay.portal.kernel.service.RoleLocalServiceUtil; import com.liferay.portal.kernel.util.CharPool; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.LoggingTimer; import com.liferay.portal.kernel.util.PortalUtil; 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.service.impl.ResourcePermissionLocalServiceImpl; import com.liferay.portal.util.PortalInstances; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; /** * @author Tobias Kaefer * @author Douglas Wong * @author Matthew Kong * @author Raymond Augé */ public class VerifyPermission extends VerifyProcess { protected void checkPermissions() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { List<String> modelNames = ResourceActionsUtil.getModelNames(); for (String modelName : modelNames) { List<String> actionIds = ResourceActionsUtil.getModelResourceActions(modelName); ResourceActionLocalServiceUtil.checkResourceActions( modelName, actionIds, true); } List<String> portletNames = ResourceActionsUtil.getPortletNames(); for (String portletName : portletNames) { List<String> actionIds = ResourceActionsUtil.getPortletResourceActions(portletName); ResourceActionLocalServiceUtil.checkResourceActions( portletName, actionIds, true); } } } protected void deleteConflictingUserDefaultRolePermissions( long companyId, long powerUserRoleId, long userRoleId, long userClassNameId, long userGroupClassNameId) throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { StringBundler sb = new StringBundler(14); sb.append("select resourcePermission1.resourcePermissionId from "); sb.append("ResourcePermission resourcePermission1 inner join "); sb.append("ResourcePermission resourcePermission2 on "); sb.append("resourcePermission1.companyId = "); sb.append("resourcePermission2.companyId and "); sb.append("resourcePermission1.name = resourcePermission2.name "); sb.append("and resourcePermission1.scope = "); sb.append("resourcePermission2.scope and "); sb.append("resourcePermission1.primKey = "); sb.append("resourcePermission2.primKey inner join Layout on "); sb.append("resourcePermission1.companyId = Layout.companyId and "); sb.append("resourcePermission1.primKey like "); sb.append("replace('[$PLID$]_LAYOUT_%', '[$PLID$]', "); sb.append("cast_text(Layout.plid)) and Layout.type_ = '"); sb.append(LayoutConstants.TYPE_PORTLET); sb.append(CharPool.APOSTROPHE); sb.append(" inner join Group_ on Layout.groupId = Group_.groupId "); sb.append("where resourcePermission1.companyId = "); sb.append(companyId); sb.append(" and resourcePermission1.roleId = "); sb.append(powerUserRoleId); sb.append(" and resourcePermission2.roleId = "); sb.append(userRoleId); sb.append(" and resourcePermission1.scope = "); sb.append(ResourceConstants.SCOPE_INDIVIDUAL); sb.append(" and (Group_.classNameId = "); sb.append(userClassNameId); sb.append(" or Group_.classNameId = "); sb.append(userGroupClassNameId); sb.append(")"); try (Statement ps1 = connection.createStatement(); PreparedStatement ps2 = AutoBatchPreparedStatementUtil.concurrentAutoBatch( connection, "delete from ResourcePermission where " + "resourcePermissionId = ?")) { String sql = SQLTransformer.transform(sb.toString()); try (ResultSet rs = ps1.executeQuery(sql)) { while (rs.next()) { ps2.setLong(1, rs.getLong(1)); ps2.addBatch(); } } ps2.executeBatch(); } } } protected void deleteDefaultPrivateLayoutPermissions() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { long[] companyIds = PortalInstances.getCompanyIdsBySQL(); for (long companyId : companyIds) { try { deleteDefaultPrivateLayoutPermissions_6(companyId); } catch (Exception e) { if (_log.isDebugEnabled()) { _log.debug(e, e); } } } } } protected void deleteDefaultPrivateLayoutPermissions_6(long companyId) throws Exception { Role role = RoleLocalServiceUtil.getRole( companyId, RoleConstants.GUEST); ActionableDynamicQuery actionableDynamicQuery = ResourcePermissionLocalServiceUtil.getActionableDynamicQuery(); actionableDynamicQuery.setAddCriteriaMethod( new ActionableDynamicQuery.AddCriteriaMethod() { @Override public void addCriteria(DynamicQuery dynamicQuery) { Property property = PropertyFactoryUtil.forName("roleId"); dynamicQuery.add(property.eq(role.getRoleId())); } }); actionableDynamicQuery.setPerformActionMethod( new ActionableDynamicQuery. PerformActionMethod<ResourcePermission>() { @Override public void performAction(ResourcePermission resourcePermission) throws PortalException { if (isPrivateLayout( resourcePermission.getName(), resourcePermission.getPrimKey())) { ResourcePermissionLocalServiceUtil. deleteResourcePermission( resourcePermission.getResourcePermissionId()); } } }); actionableDynamicQuery.performActions(); } @Override protected void doVerify() throws Exception { deleteDefaultPrivateLayoutPermissions(); checkPermissions(); fixOrganizationRolePermissions(); fixUserDefaultRolePermissions(); } protected void fixOrganizationRolePermissions() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass( ResourcePermission.class); dynamicQuery.add( RestrictionsFactoryUtil.eq( "name", Organization.class.getName())); List<ResourcePermission> resourcePermissions = ResourcePermissionLocalServiceUtil.dynamicQuery(dynamicQuery); for (ResourcePermission resourcePermission : resourcePermissions) { ResourcePermission groupResourcePermission = ResourcePermissionLocalServiceUtil.fetchResourcePermission( resourcePermission.getCompanyId(), Group.class.getName(), resourcePermission.getScope(), resourcePermission.getPrimKey(), resourcePermission.getRoleId()); if (groupResourcePermission == null) { ResourcePermissionLocalServiceUtil.setResourcePermissions( resourcePermission.getCompanyId(), Group.class.getName(), resourcePermission.getScope(), resourcePermission.getPrimKey(), resourcePermission.getRoleId(), ResourcePermissionLocalServiceImpl.EMPTY_ACTION_IDS); groupResourcePermission = ResourcePermissionLocalServiceUtil. getResourcePermission( resourcePermission.getCompanyId(), Group.class.getName(), resourcePermission.getScope(), resourcePermission.getPrimKey(), resourcePermission.getRoleId()); } for (String actionId : _deprecatedOrganizationActionIds) { if (resourcePermission.hasActionId(actionId)) { resourcePermission.removeResourceAction(actionId); groupResourcePermission.addResourceAction(actionId); } } try { resourcePermission.resetOriginalValues(); ResourcePermissionLocalServiceUtil.updateResourcePermission( resourcePermission); groupResourcePermission.resetOriginalValues(); ResourcePermissionLocalServiceUtil.updateResourcePermission( groupResourcePermission); } catch (Exception e) { _log.error(e, e); } } } } protected void fixUserDefaultRolePermissions() throws Exception { DB db = DBManagerUtil.getDB(); DBType dbType = db.getDBType(); try (LoggingTimer loggingTimer = new LoggingTimer()) { long userClassNameId = PortalUtil.getClassNameId(User.class); long userGroupClassNameId = PortalUtil.getClassNameId( UserGroup.class); long[] companyIds = PortalInstances.getCompanyIdsBySQL(); if (dbType == DBType.MYSQL) { fixUserDefaultRolePermissionsMySQL( userClassNameId, userGroupClassNameId, companyIds); return; } if (dbType == DBType.ORACLE) { fixUserDefaultRolePermissionsOracle( userClassNameId, userGroupClassNameId, companyIds); return; } for (long companyId : companyIds) { Role powerUserRole = RoleLocalServiceUtil.getRole( companyId, RoleConstants.POWER_USER); Role userRole = RoleLocalServiceUtil.getRole( companyId, RoleConstants.USER); deleteConflictingUserDefaultRolePermissions( companyId, powerUserRole.getRoleId(), userRole.getRoleId(), userClassNameId, userGroupClassNameId); StringBundler sb = new StringBundler(20); sb.append("update ResourcePermission set roleId = "); sb.append(userRole.getRoleId()); sb.append(" where resourcePermissionId in (select "); sb.append("resourcePermissionId from ResourcePermission "); sb.append("inner join Layout on ResourcePermission.companyId "); sb.append("= Layout.companyId and ResourcePermission.primKey "); sb.append("like replace('[$PLID$]_LAYOUT_%', '[$PLID$]', "); sb.append("cast_text(Layout.plid)) inner join Group_ on "); sb.append("Layout.groupId = Group_.groupId where "); sb.append("ResourcePermission.scope = "); sb.append(ResourceConstants.SCOPE_INDIVIDUAL); sb.append(" and ResourcePermission.roleId = "); sb.append(powerUserRole.getRoleId()); sb.append(" and (Group_.classNameId = "); sb.append(userClassNameId); sb.append(" or Group_.classNameId = "); sb.append(userGroupClassNameId); sb.append(") and Layout.type_ = '"); sb.append(LayoutConstants.TYPE_PORTLET); sb.append("')"); runSQL(sb.toString()); } } finally { EntityCacheUtil.clearCache(); FinderCacheUtil.clearCache(); } } protected void fixUserDefaultRolePermissionsMySQL( long userClassNameId, long userGroupClassNameId, long[] companyIds) throws Exception { for (long companyId : companyIds) { Role powerUserRole = RoleLocalServiceUtil.getRole( companyId, RoleConstants.POWER_USER); Role userRole = RoleLocalServiceUtil.getRole( companyId, RoleConstants.USER); StringBundler sb = new StringBundler(19); sb.append("update ignore ResourcePermission inner join Layout on "); sb.append("ResourcePermission.companyId = Layout.companyId and "); sb.append("ResourcePermission.primKey like "); sb.append("replace('[$PLID$]_LAYOUT_%', '[$PLID$]', "); sb.append("cast_text(Layout.plid)) inner join Group_ on "); sb.append("Layout.groupId = Group_.groupId set "); sb.append("ResourcePermission.roleId = "); sb.append(userRole.getRoleId()); sb.append(" where ResourcePermission.scope = "); sb.append(ResourceConstants.SCOPE_INDIVIDUAL); sb.append(" and ResourcePermission.roleId = "); sb.append(powerUserRole.getRoleId()); sb.append(" and (Group_.classNameId = "); sb.append(userClassNameId); sb.append(" or Group_.classNameId = "); sb.append(userGroupClassNameId); sb.append(") and Layout.type_ = '"); sb.append(LayoutConstants.TYPE_PORTLET); sb.append(StringPool.APOSTROPHE); runSQL(sb.toString()); } } protected void fixUserDefaultRolePermissionsOracle( long userClassNameId, long userGroupClassNameId, long[] companyIds) throws Exception { try { runSQL("alter table ResourcePermission drop column plid"); } catch (SQLException sqle) { if (_log.isDebugEnabled()) { _log.debug(sqle, sqle); } } runSQL("alter table ResourcePermission add plid NUMBER null"); runSQL("create index tmp_res_plid on ResourcePermission(plid)"); StringBundler sb = new StringBundler(6); sb.append("update ResourcePermission r1 set plid = (select "); sb.append("SUBSTR(ResourcePermission.primKey, 0, "); sb.append("INSTR(ResourcePermission.primKey, '_LAYOUT_') -1) from "); sb.append("ResourcePermission where r1.resourcePermissionId = "); sb.append("ResourcePermission.resourcePermissionId and "); sb.append("ResourcePermission.primKey like '%_LAYOUT_%')"); runSQL(sb.toString()); for (long companyId : companyIds) { Role powerUserRole = RoleLocalServiceUtil.getRole( companyId, RoleConstants.POWER_USER); Role userRole = RoleLocalServiceUtil.getRole( companyId, RoleConstants.USER); sb = new StringBundler(24); sb.append("update ResourcePermission r1 set roleId = "); sb.append(userRole.getRoleId()); sb.append(" where exists (select "); sb.append("ResourcePermission.resourcePermissionId from "); sb.append("ResourcePermission inner join Layout on "); sb.append("ResourcePermission.plid = Layout.plid inner join "); sb.append("Group_ on Layout.groupId = Group_.groupId where "); sb.append("r1.resourcePermissionId = ResourcePermission."); sb.append("resourcePermissionId and ResourcePermission.scope = "); sb.append(ResourceConstants.SCOPE_INDIVIDUAL); sb.append(" and ResourcePermission.roleId = "); sb.append(powerUserRole.getRoleId()); sb.append(" and (Group_.classNameId = "); sb.append(userClassNameId); sb.append(" or Group_.classNameId = "); sb.append(userGroupClassNameId); sb.append(") and Layout.type_ = '"); sb.append(LayoutConstants.TYPE_PORTLET); sb.append("') and not exists (select resourcePermissionId from "); sb.append("ResourcePermission r2 where r1.name = r2.name and "); sb.append("r1.scope = r2.scope and r1.primKey = r2.primKey and "); sb.append("r2.roleId = "); sb.append(userRole.getRoleId()); sb.append(")"); runSQL(sb.toString()); } runSQL("alter table ResourcePermission drop column plid"); } protected boolean isPrivateLayout(String name, String primKey) throws PortalException { if (!name.equals(Layout.class.getName()) && !primKey.contains(PortletConstants.LAYOUT_SEPARATOR)) { return false; } if (primKey.contains(PortletConstants.LAYOUT_SEPARATOR)) { primKey = StringUtil.extractFirst( primKey, PortletConstants.LAYOUT_SEPARATOR); } long plid = GetterUtil.getLong(primKey); Layout layout = LayoutLocalServiceUtil.getLayout(plid); if (layout.isPublicLayout() || layout.isTypeControlPanel()) { return false; } return true; } private static final Log _log = LogFactoryUtil.getLog( VerifyPermission.class); private static final List<String> _deprecatedOrganizationActionIds = new ArrayList<>(); static { _deprecatedOrganizationActionIds.add(ActionKeys.MANAGE_ARCHIVED_SETUPS); _deprecatedOrganizationActionIds.add(ActionKeys.MANAGE_LAYOUTS); _deprecatedOrganizationActionIds.add(ActionKeys.MANAGE_STAGING); _deprecatedOrganizationActionIds.add(ActionKeys.MANAGE_TEAMS); _deprecatedOrganizationActionIds.add(ActionKeys.PUBLISH_STAGING); _deprecatedOrganizationActionIds.add("APPROVE_PROPOSAL"); _deprecatedOrganizationActionIds.add("ASSIGN_REVIEWER"); } }