From 3d6a0f8e22b8c6d209e9f4f0c0b28c2c4af06515 Mon Sep 17 00:00:00 2001 From: Dmitry Grigoriev Date: Thu, 22 Aug 2019 21:21:24 +0300 Subject: [PATCH 1/2] master1264: temporary fix for branch 'master' (where BPM_PROCESS_DEFINITION_VER table does NOT yet exist). --- .../security/logic/AuthorizationLogic.java | 139 ++++++++++++++---- .../af/web/tag/ManagePermissionsFormTag.java | 1 - 2 files changed, 108 insertions(+), 32 deletions(-) diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthorizationLogic.java b/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthorizationLogic.java index afb310d096..6088c85d6e 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthorizationLogic.java +++ b/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthorizationLogic.java @@ -20,18 +20,20 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.mysema.commons.lang.CloseableIterator; -import com.querydsl.core.Tuple; import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.Tuple; import com.querydsl.jpa.JPQLQuery; import com.querydsl.jpa.hibernate.HibernateDeleteClause; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import lombok.val; import org.dom4j.Document; import org.dom4j.Element; import org.springframework.beans.factory.annotation.Autowired; @@ -133,6 +135,7 @@ public List getIssuedPermissions(User user, Executor performer, Secu return permissionDao.getIssuedPermissions(performer, securedObject); } + /** * Exports permissions to xml, see: manage_datafile, ExportDataFileAction. *

@@ -153,7 +156,7 @@ public void exportDataFile(User user, Document script) { singletonTypes.add(t); } } - exportDataFileImpl(parentElement, queryFactory.select(pm.permission, e.name, pm.objectType) + exportDataFilePermissions(parentElement, queryFactory.select(pm.permission, e.name, pm.objectType) .from(pm, e) .where(pm.objectType.in(singletonTypes).and(pm.objectId.eq(0L)).and(pm.executor.eq(e))) .orderBy(pm.objectType.asc(), e.name.asc(), pm.permission.asc())); @@ -162,7 +165,7 @@ public void exportDataFile(User user, Document script) { // Export ACTOR and GROUP permissions. { QExecutor e2 = new QExecutor("e2"); // same table as `e`, but different alias - exportDataFileImpl(parentElement, queryFactory.select(pm.permission, e.name, pm.objectType, e2.name) + exportDataFilePermissions(parentElement, queryFactory.select(pm.permission, e.name, pm.objectType, e2.name) .from(pm, e, e2) .where(pm.objectType.eq(EXECUTOR).and(pm.objectId.eq(e2.id)).and(pm.executor.eq(e))) .orderBy(pm.objectType.asc(), e2.name.asc(), e.name.asc(), pm.permission.asc())); @@ -170,51 +173,125 @@ public void exportDataFile(User user, Document script) { // Export DEFINITION permissions. { + // ******************************************************************************************************************************** + // ***** !!!!! DON'T MERGE THIS INTO develop !!!!! This is temporary solution, before table BPM_PROCESS_DEFINITION_VER was created. + // ******************************************************************************************************************************** + + // Table PERMISSION_MAPPING (PM) for TYPE='DEFINITION' stores OBJECT_ID = Deployment.getIdentifiableId() which is name hash. + // So we cannot join on (PM.OBJECT_ID = BPM_PROCESS_DEFINITION.ID) on SQL side. + val definitionNamesByIdentifiableIds = new HashMap(); QDeployment d = QDeployment.deployment; - exportDataFileImpl(parentElement, queryFactory.select(pm.permission, e.name, pm.objectType, d.name) - .from(pm, e, d) + for (val name : queryFactory.selectDistinct(d.name).from(d).fetch()) { + definitionNamesByIdentifiableIds.put((long) name.hashCode(), name); + } + + val tuples = queryFactory.select(pm.permission, e.name, pm.objectType, pm.objectId) + .from(pm, e) .where(pm.objectType.eq(DEFINITION).and(pm.executor.eq(e))) - .orderBy(d.name.asc(), e.name.asc(), pm.permission.asc())); + // exportDataFilePermissions() requires that rows are ordered by (object, executor) first, permission last. + .orderBy(pm.objectId.asc(), e.name.asc(), pm.permission.asc()) + .fetch(); + val rows = new ArrayList(tuples.size()); + for (val t : tuples) { + val objectName = definitionNamesByIdentifiableIds.get(t.get(3, Long.class)); + if (objectName != null) { + rows.add(new ExportDataFilePermissionRow(t, objectName)); + } + } + + exportDataFilePermissions(parentElement, rows); + } + } + + private static class ExportDataFilePermissionRow { + final Permission permission; + final String executorName; + final SecuredObjectType objectType; + String objectName; + + ExportDataFilePermissionRow(Tuple t) { + this(t, t.size() == 4 ? t.get(3, String.class) : null); + } + + ExportDataFilePermissionRow(Tuple t, String objectName) { + permission = t.get(0, Permission.class); + executorName = t.get(1, String.class); + objectType = t.get(2, SecuredObjectType.class); + this.objectName = objectName; } } /** - * * @param parentElement Parent for "addPermissions" elements. * @param query Must return fields in order: permission, executorName, objectType, [objectName]. */ - private void exportDataFileImpl(Element parentElement, JPQLQuery query) { + private void exportDataFilePermissions(Element parentElement, JPQLQuery query) { + try (final CloseableIterator it = query.iterate()) { + exportDataFilePermissionsImpl(parentElement, new CloseableIterator() { + @Override + public void close() { + it.close(); + } + + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public ExportDataFilePermissionRow next() { + return new ExportDataFilePermissionRow(it.next()); + } + }); + } + } + + private void exportDataFilePermissions(Element parentElement, ArrayList rows) { + val it = rows.iterator(); + exportDataFilePermissionsImpl(parentElement, new CloseableIterator() { + @Override + public void close() { + } + + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public ExportDataFilePermissionRow next() { + return it.next(); + } + }); + } + + private void exportDataFilePermissionsImpl(Element parentElement, CloseableIterator it) { SecuredObjectType lastObjectType = null; String lastObjectName = null; String lastExecutorName = null; Element addPermissionsElement = null; - try (CloseableIterator i = query.iterate()) { - while (i.hasNext()) { - Tuple t = i.next(); - Permission permission = t.get(0, Permission.class); - String executorName = t.get(1, String.class); - SecuredObjectType objectType = t.get(2, SecuredObjectType.class); - String objectName = t.size() == 4 ? t.get(3, String.class) : null; - - // Manually group by objectType, objectName, executorName. - if (objectType != lastObjectType || !Objects.equals(objectName, lastObjectName) || !Objects.equals(executorName, lastExecutorName)) { - lastObjectType = objectType; - lastObjectName = objectName; - lastExecutorName = executorName; - - addPermissionsElement = parentElement.addElement("addPermissions", XmlUtils.RUNA_NAMESPACE); - //noinspection ConstantConditions - addPermissionsElement.addAttribute("type", objectType.getName()); - if (objectName != null) { - addPermissionsElement.addAttribute("name", objectName); - } - addPermissionsElement.addAttribute("executor", executorName); - } + while (it.hasNext()) { + val row = it.next(); + + // Manually group by objectType, objectName, executorName. + if (row.objectType != lastObjectType || !Objects.equals(row.objectName, lastObjectName) || !Objects.equals(row.executorName, + lastExecutorName)) { + lastObjectType = row.objectType; + lastObjectName = row.objectName; + lastExecutorName = row.executorName; + addPermissionsElement = parentElement.addElement("addPermissions", XmlUtils.RUNA_NAMESPACE); //noinspection ConstantConditions - addPermissionsElement.addElement("permission", XmlUtils.RUNA_NAMESPACE).addAttribute("name", permission.getName()); + addPermissionsElement.addAttribute("type", row.objectType.getName()); + if (row.objectName != null) { + addPermissionsElement.addAttribute("name", row.objectName); + } + addPermissionsElement.addAttribute("executor", row.executorName); } + + //noinspection ConstantConditions + addPermissionsElement.addElement("permission", XmlUtils.RUNA_NAMESPACE).addAttribute("name", row.permission.getName()); } } diff --git a/wfe-web/src/main/java/ru/runa/af/web/tag/ManagePermissionsFormTag.java b/wfe-web/src/main/java/ru/runa/af/web/tag/ManagePermissionsFormTag.java index c0a9fec490..3223311479 100644 --- a/wfe-web/src/main/java/ru/runa/af/web/tag/ManagePermissionsFormTag.java +++ b/wfe-web/src/main/java/ru/runa/af/web/tag/ManagePermissionsFormTag.java @@ -26,7 +26,6 @@ import ru.runa.common.web.html.PermissionTableBuilder; import ru.runa.common.web.tag.SecuredObjectFormTag2; import ru.runa.wfe.security.Permission; -import ru.runa.wfe.security.SecuredSingleton; import ru.runa.wfe.service.delegate.Delegates; @org.tldgen.annotations.Tag(bodyContent = BodyContent.JSP, name = "managePermissionsForm") From 45177737eacc0186024f242046c4317ec449bee5 Mon Sep 17 00:00:00 2001 From: Dmitry Grigoriev Date: Thu, 22 Aug 2019 21:49:28 +0300 Subject: [PATCH 2/2] master1264: comments --- .../ru/runa/wfe/security/logic/AuthorizationLogic.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthorizationLogic.java b/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthorizationLogic.java index 6088c85d6e..525329fc36 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthorizationLogic.java +++ b/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthorizationLogic.java @@ -203,6 +203,9 @@ public void exportDataFile(User user, Document script) { } } + // ******************************************************************************************************************************** + // ***** !!!!! DON'T MERGE THIS INTO develop !!!!! This is temporary solution, before table BPM_PROCESS_DEFINITION_VER was created. + // ******************************************************************************************************************************** private static class ExportDataFilePermissionRow { final Permission permission; final String executorName; @@ -225,6 +228,9 @@ private static class ExportDataFilePermissionRow { * @param parentElement Parent for "addPermissions" elements. * @param query Must return fields in order: permission, executorName, objectType, [objectName]. */ + // ******************************************************************************************************************************** + // ***** !!!!! DON'T MERGE THIS INTO develop !!!!! This is temporary solution, before table BPM_PROCESS_DEFINITION_VER was created. + // ******************************************************************************************************************************** private void exportDataFilePermissions(Element parentElement, JPQLQuery query) { try (final CloseableIterator it = query.iterate()) { exportDataFilePermissionsImpl(parentElement, new CloseableIterator() { @@ -246,6 +252,9 @@ public ExportDataFilePermissionRow next() { } } + // ******************************************************************************************************************************** + // ***** !!!!! DON'T MERGE THIS INTO develop !!!!! This is temporary solution, before table BPM_PROCESS_DEFINITION_VER was created. + // ******************************************************************************************************************************** private void exportDataFilePermissions(Element parentElement, ArrayList rows) { val it = rows.iterator(); exportDataFilePermissionsImpl(parentElement, new CloseableIterator() {