diff --git a/wfe-core/src/main/java/ru/runa/wfe/commons/IoCommons.java b/wfe-core/src/main/java/ru/runa/wfe/commons/IoCommons.java index 62502a237c..f06e5f34a1 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/commons/IoCommons.java +++ b/wfe-core/src/main/java/ru/runa/wfe/commons/IoCommons.java @@ -134,6 +134,16 @@ public static String getExtensionDirPath() { return path + "wfe.custom"; } + public static String getExcelStorageDirPath() { + String path = IoCommons.getAppServerDirPath(); + if (path != null) { + path += "/"; + } else { + path = ""; + } + return path + "wfe.excelstorage"; + } + public static File[] getJarFiles(File directory) { return directory.listFiles(new PatternFilenameFilter(".*\\.jar")); } diff --git a/wfe-core/src/main/java/ru/runa/wfe/commons/SystemProperties.java b/wfe-core/src/main/java/ru/runa/wfe/commons/SystemProperties.java index c62aebd3a2..d7e494fe03 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/commons/SystemProperties.java +++ b/wfe-core/src/main/java/ru/runa/wfe/commons/SystemProperties.java @@ -32,6 +32,10 @@ public class SystemProperties { public static PropertyResources getResources() { return RESOURCES; } + + public static boolean isTaskDelegationEnabled() { + return RESOURCES.getBooleanProperty("task.delegation.enabled", true); + } /** * Production or development mode? diff --git a/wfe-core/src/main/java/ru/runa/wfe/datasource/DataSourceStorage.java b/wfe-core/src/main/java/ru/runa/wfe/datasource/DataSourceStorage.java index f5f089658b..c8f4891e4a 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/datasource/DataSourceStorage.java +++ b/wfe-core/src/main/java/ru/runa/wfe/datasource/DataSourceStorage.java @@ -4,6 +4,7 @@ import com.google.common.collect.Sets; import java.io.File; import java.io.FileFilter; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; @@ -26,6 +27,7 @@ import ru.runa.wfe.InternalApplicationException; import ru.runa.wfe.commons.IoCommons; import ru.runa.wfe.commons.xml.XmlUtils; +import ru.runa.wfe.var.VariableProvider; public class DataSourceStorage implements DataSourceStuff { @@ -60,7 +62,7 @@ private static synchronized void registerDrivers() { if (urls.isEmpty()) { return; } - URLClassLoader urlClassLoader = new URLClassLoader(urls.toArray(new URL[] {})); + URLClassLoader urlClassLoader = new URLClassLoader(urls.toArray(new URL[]{})); JdbcDataSourceType[] dsTypes = JdbcDataSourceType.values(); for (JdbcDataSourceType dsType : dsTypes) { if (!registeredDsTypes.contains(dsType)) { @@ -137,6 +139,16 @@ public static DataSource getDataSource(String dsName) { return dataSource; } + public static DataSource parseDataSource(String s, VariableProvider variableProvider) { + if (!s.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE) && !s.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE_VARIABLE)) { + return null; + } + final String dsName = s.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE) ? + s.substring(s.indexOf(':') + 1) : + (String) variableProvider.getValue(s.substring(s.indexOf(':') + 1)); + return DataSourceStorage.getDataSource(dsName); + } + public static List getAllDataSources() { List all = Lists.newArrayList(); for (String dsName : getNames()) { @@ -166,13 +178,10 @@ public static void save(byte[] content) { /** * Saves the data source properties to the local storage. - * - * @param content - * - the data source properties content. - * @param force - * - force to overwrite if the data source already exists. - * @param preservePassword - * - if true is passed then the old data source password won't be changed. + * + * @param content - the data source properties content. + * @param force - force to overwrite if the data source already exists. + * @param preservePassword - if true is passed then the old data source password won't be changed. * @return true if the method succeed, false if the data source with the given name has existed and the force argument is false. */ public static boolean save(byte[] content, boolean force, boolean preservePassword) { @@ -217,6 +226,12 @@ public static boolean save(byte[] content, boolean force, boolean preservePasswo public static byte[] restore(String dsName) { try { return FileCopyUtils.copyToByteArray(new File(getStorageDir(), dsName + DATA_SOURCE_FILE_SUFFIX)); + } catch (FileNotFoundException e) { + if (DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME.equals(dsName)) { + log.warn(DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME + " does not exist. Creating one", e); + return ExcelStorageInitiator.init(); + } + throw new InternalApplicationException(e); } catch (IOException e) { throw new InternalApplicationException(e); } diff --git a/wfe-core/src/main/java/ru/runa/wfe/datasource/DataSourceStuff.java b/wfe-core/src/main/java/ru/runa/wfe/datasource/DataSourceStuff.java index 811481e89c..349def3916 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/datasource/DataSourceStuff.java +++ b/wfe-core/src/main/java/ru/runa/wfe/datasource/DataSourceStuff.java @@ -28,6 +28,8 @@ public interface DataSourceStuff { String JNDI_NAME_SAMPLE = "jboss/datasources/"; + String INTERNAL_STORAGE_DATA_SOURCE_NAME = "InternalStorage"; + static String adjustUrl(JdbcDataSource jds) { String url = jds.getUrl(); String dbName = Strings.isNullOrEmpty(jds.getDbName()) ? "__DB_UNDEFINED__" : jds.getDbName(); diff --git a/wfe-core/src/main/java/ru/runa/wfe/datasource/ExcelStorageInitiator.java b/wfe-core/src/main/java/ru/runa/wfe/datasource/ExcelStorageInitiator.java new file mode 100644 index 0000000000..de8c89900b --- /dev/null +++ b/wfe-core/src/main/java/ru/runa/wfe/datasource/ExcelStorageInitiator.java @@ -0,0 +1,38 @@ +package ru.runa.wfe.datasource; + +import java.io.File; +import lombok.extern.apachecommons.CommonsLog; +import org.dom4j.Document; +import org.dom4j.DocumentHelper; +import org.dom4j.io.OutputFormat; +import ru.runa.wfe.commons.IoCommons; +import ru.runa.wfe.commons.xml.XmlUtils; + +/** + * @author Alekseev Mikhail + * @since #1766 + */ +@CommonsLog +public class ExcelStorageInitiator { + @SuppressWarnings("ResultOfMethodCallIgnored") + public static synchronized byte[] init() { + if (DataSourceStorage.getNames().contains(DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME)) { + return DataSourceStorage.restore(DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME); + } + + final String excelStorageDirPath = IoCommons.getExcelStorageDirPath(); + new File(excelStorageDirPath).mkdir(); + log.info("Created " + excelStorageDirPath); + + final Document document = DocumentHelper.createDocument(); + document.addElement(DataSourceStuff.ELEMENT_DATA_SOURCE) + .addAttribute(DataSourceStuff.ATTR_NAME, DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME) + .addAttribute(DataSourceStuff.ATTR_TYPE, DataSourceType.Excel.name()) + .addElement(DataSourceStuff.ELEMENT_FILE_PATH).addText(excelStorageDirPath); + final byte[] internalStorageDs = XmlUtils.save(document, OutputFormat.createPrettyPrint()); + DataSourceStorage.save(internalStorageDs, true, false); + log.info(DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME + " is saved"); + + return internalStorageDs; + } +} diff --git a/wfe-core/src/main/java/ru/runa/wfe/definition/bpmn/BpmnXmlReader.java b/wfe-core/src/main/java/ru/runa/wfe/definition/bpmn/BpmnXmlReader.java index c743b23f7f..7787e99189 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/definition/bpmn/BpmnXmlReader.java +++ b/wfe-core/src/main/java/ru/runa/wfe/definition/bpmn/BpmnXmlReader.java @@ -4,6 +4,7 @@ import com.google.common.base.Throwables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import java.util.Collections; import java.util.List; import java.util.Map; import org.dom4j.Document; @@ -45,6 +46,7 @@ import ru.runa.wfe.lang.Transition; import ru.runa.wfe.lang.VariableContainerNode; import ru.runa.wfe.lang.bpmn2.CatchEventNode; +import ru.runa.wfe.lang.bpmn2.DataStore; import ru.runa.wfe.lang.bpmn2.EndToken; import ru.runa.wfe.lang.bpmn2.ExclusiveGateway; import ru.runa.wfe.lang.bpmn2.MessageEventType; @@ -56,6 +58,7 @@ public class BpmnXmlReader { private static final String RUNA_NAMESPACE = "http://runa.ru/wfe/xml"; private static final String PROCESS = "process"; + private static final String DATA_STORE = "dataStore"; private static final String EXTENSION_ELEMENTS = "extensionElements"; private static final String IS_EXECUTABLE = "isExecutable"; private static final String PROPERTY = "property"; @@ -130,6 +133,7 @@ public class BpmnXmlReader { private final Document document; private static Map> nodeTypes = Maps.newHashMap(); + static { nodeTypes.put(USER_TASK, TaskNode.class); nodeTypes.put(MULTI_TASK, MultiTaskNode.class); @@ -138,6 +142,7 @@ public class BpmnXmlReader { nodeTypes.put(EXCLUSIVE_GATEWAY, ExclusiveGateway.class); nodeTypes.put(PARALLEL_GATEWAY, ParallelGateway.class); nodeTypes.put(TEXT_ANNOTATION, TextAnnotation.class); + nodeTypes.put(DATA_STORE, DataStore.class); // back compatibility v < 4.3.0 nodeTypes.put(SEND_TASK, SendMessageNode.class); nodeTypes.put(RECEIVE_TASK, CatchEventNode.class); @@ -154,6 +159,7 @@ public BpmnXmlReader(Document document) { public ProcessDefinition readProcessDefinition(ProcessDefinition processDefinition) { try { Element definitionsElement = document.getRootElement(); + readDataStores(processDefinition, definitionsElement.elements(DATA_STORE)); Element process = definitionsElement.element(PROCESS); processDefinition.setName(process.attributeValue(NAME)); Map processProperties = parseExtensionProperties(process); @@ -521,4 +527,11 @@ private void readActionHandlers(ProcessDefinition processDefinition, GraphElemen } } + private void readDataStores(ProcessDefinition processDefinition, List dataStoreElements) { + for (Element dataStoreElement : dataStoreElements) { + final Node node = ApplicationContextFactory.createAutowiredBean(nodeTypes.get(DATA_STORE)); + node.setProcessDefinition(processDefinition); + readNode(processDefinition, dataStoreElement, Collections.emptyMap(), node); + } + } } diff --git a/wfe-core/src/main/java/ru/runa/wfe/lang/bpmn2/DataStore.java b/wfe-core/src/main/java/ru/runa/wfe/lang/bpmn2/DataStore.java new file mode 100644 index 0000000000..594965d070 --- /dev/null +++ b/wfe-core/src/main/java/ru/runa/wfe/lang/bpmn2/DataStore.java @@ -0,0 +1,17 @@ +package ru.runa.wfe.lang.bpmn2; + +import ru.runa.wfe.execution.ExecutionContext; +import ru.runa.wfe.lang.Node; +import ru.runa.wfe.lang.NodeType; + +public class DataStore extends Node { + @Override + public NodeType getNodeType() { + return NodeType.TEXT_ANNOTATION; + } + + @Override + protected void execute(ExecutionContext executionContext) throws Exception { + throw new UnsupportedOperationException(); + } +} diff --git a/wfe-core/src/main/java/ru/runa/wfe/presentation/hibernate/HibernateCompilerHqlBuider.java b/wfe-core/src/main/java/ru/runa/wfe/presentation/hibernate/HibernateCompilerHqlBuider.java index 699300b0a5..535c58fcc7 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/presentation/hibernate/HibernateCompilerHqlBuider.java +++ b/wfe-core/src/main/java/ru/runa/wfe/presentation/hibernate/HibernateCompilerHqlBuider.java @@ -318,7 +318,7 @@ private List addFilters() { // TODO Largely duplicates PermissionDAO logic. After (if ever) BatchPresentation uses QueryDSL, try to merge duplicates. private List addSecureCheck() { List result = new LinkedList<>(); - RestrictionsToPermissions pp = parameters.getPermissionRestrictions(); + RestrictionsToPermissions pp = (parameters.getPermissionRestrictions()==null)?null:parameters.getPermissionRestrictions().cloneCheckRequired(); if (pp == null) { return result; } diff --git a/wfe-core/src/main/java/ru/runa/wfe/presentation/hibernate/RestrictionsToPermissions.java b/wfe-core/src/main/java/ru/runa/wfe/presentation/hibernate/RestrictionsToPermissions.java index 4975ed601e..cb00200097 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/presentation/hibernate/RestrictionsToPermissions.java +++ b/wfe-core/src/main/java/ru/runa/wfe/presentation/hibernate/RestrictionsToPermissions.java @@ -1,14 +1,17 @@ package ru.runa.wfe.presentation.hibernate; +import java.util.Arrays; import org.springframework.util.Assert; import ru.runa.wfe.security.Permission; import ru.runa.wfe.security.SecuredObjectType; +import ru.runa.wfe.security.SecurityCheckProperties; import ru.runa.wfe.user.User; /** * Restrictions to load only objects with specified permission granted for user. */ public class RestrictionsToPermissions { + /** * User which must has permission on queried objects. Queries only objects with condition: at least one executor from (user + its groups) * must have 'permission' with 'securedObjectTypes'. Can be null. @@ -35,4 +38,23 @@ public RestrictionsToPermissions(User user, Permission permission, SecuredObject this.permission = permission; this.types = types; } + + protected RestrictionsToPermissions cloneCheckRequired() { + SecuredObjectType[] resTypes = new SecuredObjectType[types.length]; + int n = 0; + for (int i = 0; i < types.length; i++) { + if (types[i] != null && SecurityCheckProperties.isPermissionCheckRequired(types[i])) { + resTypes[n] = types[i]; + n++; + } + } + if (n == 0) { + return null; + } else { + resTypes = Arrays.copyOf(resTypes, n); + } + RestrictionsToPermissions res = new RestrictionsToPermissions(this.user, this.permission, resTypes); + return res; + } + } diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/ApplicablePermissions.java b/wfe-core/src/main/java/ru/runa/wfe/security/ApplicablePermissions.java index 5fa3ec6939..b14250232e 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/security/ApplicablePermissions.java +++ b/wfe-core/src/main/java/ru/runa/wfe/security/ApplicablePermissions.java @@ -44,6 +44,7 @@ import static ru.runa.wfe.security.Permission.UPDATE_ACTOR_STATUS; import static ru.runa.wfe.security.Permission.VIEW_LOGS; import static ru.runa.wfe.security.Permission.VIEW_TASKS; +import static ru.runa.wfe.security.Permission.DELEGATE_TASKS; /** * Extracted from class Permission because permission-to-securedObjectType applicability is separate piece of logic, @@ -216,15 +217,15 @@ public static void check(SecuredObject obj, Collection permissions) .defaults(READ) .hidden(READ_PERMISSIONS); - add(SecuredObjectType.EXECUTOR, READ, UPDATE_PERMISSIONS, UPDATE, UPDATE_ACTOR_STATUS, VIEW_TASKS) + add(SecuredObjectType.EXECUTOR, READ, UPDATE_PERMISSIONS, UPDATE, UPDATE_ACTOR_STATUS, VIEW_TASKS, DELEGATE_TASKS) .defaults(READ) .hidden(READ_PERMISSIONS); - add(SecuredObjectType.PROCESS, READ, UPDATE_PERMISSIONS, CANCEL) + add(SecuredObjectType.PROCESS, READ, UPDATE_PERMISSIONS, CANCEL, UPDATE, DELETE, START_PROCESS, CANCEL_PROCESS) .defaults(READ) .hidden(READ_PERMISSIONS); - add(SecuredObjectType.RELATION, READ, UPDATE_PERMISSIONS, UPDATE) + add(SecuredObjectType.RELATION, READ, UPDATE_PERMISSIONS, UPDATE, DELETE) .defaults(READ) .hidden(READ_PERMISSIONS); @@ -243,5 +244,9 @@ public static void check(SecuredObject obj, Collection permissions) add(SecuredObjectType.SYSTEM, READ, UPDATE_PERMISSIONS, LOGIN, CHANGE_SELF_PASSWORD, CREATE_EXECUTOR, CREATE_DEFINITION, VIEW_LOGS) .defaults(LOGIN) .hidden(READ_PERMISSIONS); + + add(SecuredObjectType.DATASOURCES, READ, UPDATE_PERMISSIONS, UPDATE) + .defaults(READ) + .hidden(READ_PERMISSIONS); } } diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/Permission.java b/wfe-core/src/main/java/ru/runa/wfe/security/Permission.java index 744e64455d..e2358752a8 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/security/Permission.java +++ b/wfe-core/src/main/java/ru/runa/wfe/security/Permission.java @@ -203,4 +203,8 @@ public boolean equals(Object obj) { public static final Permission UPDATE_PERMISSIONS = new Permission("UPDATE_PERMISSIONS"); public static final Permission VIEW_TASKS = new Permission("VIEW_TASKS"); + + public static final Permission DELEGATE_TASKS = new Permission("DELEGATE_TASKS"); + + public static final Permission ADD_ACTOR_TO_GROUP = new Permission("ADD_ACTOR_TO_GROUP"); } diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/SecuredObjectFactory.java b/wfe-core/src/main/java/ru/runa/wfe/security/SecuredObjectFactory.java index 8fd7b9ba47..8b8067a387 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/security/SecuredObjectFactory.java +++ b/wfe-core/src/main/java/ru/runa/wfe/security/SecuredObjectFactory.java @@ -140,10 +140,11 @@ public List getIdsByNames(SecuredObjectType type, Set names) { Set missingNames = new HashSet<>(names); boolean isDef = type.equals(SecuredObjectType.DEFINITION); for (Tuple t : tt) { - if(isDef) + if(isDef) { foundIds.add(ApplicationContextFactory.getDeploymentDAO().getNotNull(t.get(0, Long.class)).getIdentifiableId()); - else + } else { foundIds.add(t.get(0, Long.class)); + } missingNames.remove(t.get(1, String.class)); } if (!missingNames.isEmpty()) { @@ -235,5 +236,7 @@ public SecuredObject findById(Long id) { }); add(SecuredSingleton.SYSTEM); + + add(SecuredSingleton.DATASOURCES); } } diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/SecuredObjectType.java b/wfe-core/src/main/java/ru/runa/wfe/security/SecuredObjectType.java index 864e305d28..6c6b845c4f 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/security/SecuredObjectType.java +++ b/wfe-core/src/main/java/ru/runa/wfe/security/SecuredObjectType.java @@ -132,6 +132,9 @@ public boolean equals(Object obj) { public static final SecuredObjectType REPORTS = new SecuredObjectType("REPORTS", true); public static final SecuredObjectType REPORT = new SecuredObjectType("REPORT", REPORTS); - + public static final SecuredObjectType SYSTEM = new SecuredObjectType("SYSTEM", true); + + public static final SecuredObjectType DATASOURCES = new SecuredObjectType("DATASOURCES", true); + } diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/SecuredSingleton.java b/wfe-core/src/main/java/ru/runa/wfe/security/SecuredSingleton.java index 86cdd886e2..f7bbff62a6 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/security/SecuredSingleton.java +++ b/wfe-core/src/main/java/ru/runa/wfe/security/SecuredSingleton.java @@ -60,4 +60,5 @@ public final SecuredObjectType getSecuredObjectType() { public static final SecuredSingleton RELATIONS = new SecuredSingleton(SecuredObjectType.RELATIONS); public static final SecuredSingleton REPORTS = new SecuredSingleton(SecuredObjectType.REPORTS); public static final SecuredSingleton SYSTEM = new SecuredSingleton(SecuredObjectType.SYSTEM); + public static final SecuredSingleton DATASOURCES = new SecuredSingleton(SecuredObjectType.DATASOURCES); } diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/SecurityCheckProperties.java b/wfe-core/src/main/java/ru/runa/wfe/security/SecurityCheckProperties.java new file mode 100644 index 0000000000..2fae1ab38d --- /dev/null +++ b/wfe-core/src/main/java/ru/runa/wfe/security/SecurityCheckProperties.java @@ -0,0 +1,12 @@ +package ru.runa.wfe.security; + +import ru.runa.wfe.commons.PropertyResources; + +public class SecurityCheckProperties { + public static final String CONFIG_FILE_NAME = "securitycheck.properties"; + private static final PropertyResources RESOURCES = new PropertyResources(CONFIG_FILE_NAME); + + public static boolean isPermissionCheckRequired(SecuredObjectType securedObjectType) { + return RESOURCES.getBooleanProperty("permission.check.required." + securedObjectType.getName(), false); + } +} diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/auth/InternalDbNameLoginModule.java b/wfe-core/src/main/java/ru/runa/wfe/security/auth/InternalDbNameLoginModule.java new file mode 100644 index 0000000000..a98b41d9db --- /dev/null +++ b/wfe-core/src/main/java/ru/runa/wfe/security/auth/InternalDbNameLoginModule.java @@ -0,0 +1,32 @@ +package ru.runa.wfe.security.auth; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.login.LoginException; +import ru.runa.wfe.user.Actor; + +/** + * LoginModule for based on actor name and password information provided by + * ExecutorService. + * + */ +public class InternalDbNameLoginModule extends LoginModuleBase { + + @Override + protected Actor login(CallbackHandler callbackHandler) throws Exception { + Callback[] callbacks = new Callback[1]; + callbacks[0] = new NameCallback("actor name: "); + callbackHandler.handle(callbacks); + String actorName = ((NameCallback) callbacks[0]).getName(); + if (actorName == null) { + return null; + } + Actor actor = executorDao.getActor(actorName); + if (actor != null) { + return actor; + } + throw new LoginException("Invalid login or password"); + } + +} diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/dao/DelegateTaskPermissionRule.java b/wfe-core/src/main/java/ru/runa/wfe/security/dao/DelegateTaskPermissionRule.java new file mode 100644 index 0000000000..dc3357f9e7 --- /dev/null +++ b/wfe-core/src/main/java/ru/runa/wfe/security/dao/DelegateTaskPermissionRule.java @@ -0,0 +1,26 @@ +package ru.runa.wfe.security.dao; + +import ru.runa.wfe.commons.SystemProperties; +import ru.runa.wfe.security.Permission; +import ru.runa.wfe.security.SecuredObjectType; + +public class DelegateTaskPermissionRule extends PermissionRule { + + public DelegateTaskPermissionRule() { + super(); + } + + public DelegateTaskPermissionRule(SecuredObjectType type, Permission perm, Boolean isAdmin) { + super(type, perm, isAdmin); + } + + @Override + public boolean isAllowed(SecuredObjectType type, Long id, Boolean isAdmin, Permission perm) { + if (SystemProperties.isTaskDelegationEnabled()) { + return super.isAllowed(type, id, isAdmin, perm); + } else { + return false; + } + } + +} diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/dao/PermissionDao.java b/wfe-core/src/main/java/ru/runa/wfe/security/dao/PermissionDao.java index a997a77d9d..4407d0fed5 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/security/dao/PermissionDao.java +++ b/wfe-core/src/main/java/ru/runa/wfe/security/dao/PermissionDao.java @@ -50,6 +50,8 @@ import ru.runa.wfe.security.PermissionSubstitutions; import ru.runa.wfe.security.SecuredObject; import ru.runa.wfe.security.SecuredObjectType; +import ru.runa.wfe.security.SecurityCheckProperties; +import ru.runa.wfe.user.Actor; import ru.runa.wfe.user.Executor; import ru.runa.wfe.user.User; import ru.runa.wfe.user.dao.ExecutorDao; @@ -74,7 +76,78 @@ public class PermissionDao extends CommonDao { private final Map> privelegedExecutors = new HashMap<>(); private final Set privelegedExecutorIds = new HashSet<>(); - + private static final List requiredRules = new ArrayList<>(); + private static final List implicitRules = new ArrayList<>(); + + static { + requiredRules.add(new PermissionRule(SecuredObjectType.EXECUTOR, Permission.UPDATE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.EXECUTOR, Permission.UPDATE_ACTOR_STATUS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.EXECUTOR, Permission.READ_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.EXECUTOR, Permission.UPDATE_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.EXECUTOR, Permission.VIEW_TASKS, true)); + requiredRules.add(new DelegateTaskPermissionRule(SecuredObjectType.EXECUTOR, Permission.DELEGATE_TASKS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.SYSTEM, Permission.CREATE_EXECUTOR, true)); + + requiredRules.add(new PermissionRule(SecuredObjectType.SYSTEM, Permission.LOGIN, null)); + requiredRules.add(new PermissionRule(SecuredObjectType.SYSTEM, Permission.READ, true)); + + requiredRules.add(new PermissionRule(SecuredObjectType.REPORTS, Permission.UPDATE_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.REPORTS, Permission.READ_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.REPORTS, Permission.UPDATE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.REPORT, Permission.UPDATE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.REPORT, Permission.READ_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.REPORT, Permission.UPDATE_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.REPORT, Permission.DELETE, true)); + + requiredRules.add(new PermissionRule(SecuredObjectType.RELATIONS, Permission.READ_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.RELATIONS, Permission.UPDATE_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.RELATIONS, Permission.UPDATE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.RELATION, Permission.READ, null)); + requiredRules.add(new PermissionRule(SecuredObjectType.RELATION, Permission.UPDATE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.RELATION, Permission.DELETE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.RELATION, Permission.READ_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.RELATION, Permission.UPDATE_PERMISSIONS, true)); + + requiredRules.add(new PermissionRule(SecuredObjectType.BOTSTATIONS, Permission.READ, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.BOTSTATIONS, Permission.UPDATE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.BOTSTATIONS, Permission.UPDATE_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.BOTSTATIONS, Permission.READ_PERMISSIONS, true)); + + requiredRules.add(new PermissionRule(SecuredObjectType.SYSTEM, Permission.CREATE_DEFINITION, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.DEFINITION, Permission.UPDATE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.DEFINITION, Permission.DELETE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.DEFINITION, Permission.START_PROCESS, null)); + requiredRules.add(new PermissionRule(SecuredObjectType.DEFINITION, Permission.CANCEL_PROCESS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.DEFINITION, Permission.READ_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.DEFINITION, Permission.UPDATE_PERMISSIONS, true)); + + requiredRules.add(new PermissionRule(SecuredObjectType.PROCESS, Permission.START_PROCESS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.PROCESS, Permission.CANCEL_PROCESS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.PROCESS, Permission.CANCEL, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.PROCESS, Permission.UPDATE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.PROCESS, Permission.READ_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.PROCESS, Permission.UPDATE_PERMISSIONS, true)); + + requiredRules.add(new PermissionRule(SecuredObjectType.DATASOURCES, Permission.READ_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.DATASOURCES, Permission.UPDATE_PERMISSIONS, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.DATASOURCES, Permission.UPDATE, true)); + requiredRules.add(new PermissionRule(SecuredObjectType.DATASOURCES, Permission.READ, true)); + + implicitRules.add(new DelegateTaskPermissionRule(SecuredObjectType.EXECUTOR, Permission.DELEGATE_TASKS, true)); + + implicitRules.add(new PermissionRule(SecuredObjectType.RELATIONS, Permission.READ_PERMISSIONS, true)); + implicitRules.add(new PermissionRule(SecuredObjectType.RELATIONS, Permission.UPDATE_PERMISSIONS, true)); + implicitRules.add(new PermissionRule(SecuredObjectType.RELATIONS, Permission.UPDATE, true)); + implicitRules.add(new PermissionRule(SecuredObjectType.RELATION, Permission.UPDATE, true)); + implicitRules.add(new PermissionRule(SecuredObjectType.RELATION, Permission.DELETE, true)); + + implicitRules.add(new PermissionRule(SecuredObjectType.DATASOURCES, Permission.UPDATE, true)); + implicitRules.add(new PermissionRule(SecuredObjectType.DATASOURCES, Permission.READ, true)); + implicitRules.add(new PermissionRule(SecuredObjectType.DATASOURCES, Permission.READ_PERMISSIONS, true)); + implicitRules.add(new PermissionRule(SecuredObjectType.DATASOURCES, Permission.UPDATE_PERMISSIONS, true)); + + implicitRules.add(new PermissionRule(SecuredObjectType.SYSTEM, Permission.LOGIN, null)); + } public PermissionDao() { for (SecuredObjectType type : SecuredObjectType.values()) { privelegedExecutors.put(type, new HashSet<>()); @@ -166,6 +239,14 @@ public void checkAllowed(User user, Permission permission, SecuredObjectType typ * Throws if user has no permission to {type, all given ids}. */ public void checkAllowedForAll(User user, Permission permission, SecuredObjectType type, List ids) { + if (!SecurityCheckProperties.isPermissionCheckRequired(type)) { + for (Long id: ids) { + if (!checkRequiredRules(user.getActor(), permission, type, id) ) { + throw new AuthorizationException("User " + user + " does not have " + permission + " on all of (" + type + ", " + id + ")"); + } + } + return; + } Assert.notNull(ids); List notAllowed = CollectionUtil.diffList(ids, filterAllowedIds(user.getActor(), permission, type, ids)); if (!notAllowed.isEmpty()) { @@ -178,36 +259,139 @@ public void checkAllowedForAll(User user, Permission permission, SecuredObjectTy * Returns true if user have permission to object. */ public boolean isAllowed(User user, Permission permission, SecuredObject object) { + if (!SecurityCheckProperties.isPermissionCheckRequired(object.getSecuredObjectType())) { + return checkRequiredRules(user.getActor(), permission, object.getSecuredObjectType(), object.getIdentifiableId()); + } return isAllowed(user.getActor(), permission, object.getSecuredObjectType(), object.getIdentifiableId()); } public boolean isAllowed(User user, Permission permission, SecuredObjectType type, Long id) { + if (!SecurityCheckProperties.isPermissionCheckRequired(type)) { + return checkRequiredRules(user.getActor(), permission, type, id); + } return isAllowed(user.getActor(), permission, type, id); } public boolean isAllowed(Executor executor, Permission permission, SecuredObjectType type, Long id) { + if (!SecurityCheckProperties.isPermissionCheckRequired(type)) { + return checkRequiredRules(executor, permission, type, id); + } Assert.notNull(id); return !filterAllowedIds(executor, permission, type, Collections.singletonList(id)).isEmpty(); } public boolean isAllowed(Executor executor, Permission permission, SecuredObject object, boolean checkPrivileged) { + if (!SecurityCheckProperties.isPermissionCheckRequired(object.getSecuredObjectType())) { + return checkRequiredRules(executor, permission, object.getSecuredObjectType(), object.getIdentifiableId()); + } Long id = object.getIdentifiableId(); SecuredObjectType type = object.getSecuredObjectType(); Assert.notNull(id); - return !filterAllowedIds(executor, permission, type, Collections.singletonList(id), checkPrivileged).isEmpty(); + return !(filterAllowedIds(executor, permission, type, Collections.singletonList(id), checkPrivileged)).isEmpty(); } /** * Returns true if user have permission to {type, any id}. */ public boolean isAllowedForAny(User user, Permission permission, SecuredObjectType type) { + if (!SecurityCheckProperties.isPermissionCheckRequired(type)) { + return checkRequiredRules(user.getActor(), permission, type, (Long)null); + } return !filterAllowedIds(user.getActor(), permission, type, null).isEmpty(); } - + public Set filterAllowedIds(Executor executor, Permission permission, SecuredObjectType type, List idsOrNull) { return filterAllowedIds(executor, permission, type, idsOrNull, true); } + + private boolean checkRequiredRules(Executor executor, Permission permission, SecuredObjectType type, Long idOrNull) { + boolean isAdmin = false; + if (executor instanceof Actor) { + isAdmin = executorDao.isAdministrator((Actor) executor); + } + for (PermissionRule r : requiredRules) { + if (permission.equals(r.getPermission()) && type.equals(r.getObjectType())) { + if (!r.isAllowed(type, idOrNull, isAdmin, permission)) { + return false; + } + } + } + return true; + } + + private Set checkRequiredRules(Executor executor, Permission permission, SecuredObjectType type, Collection idsOrNull) { + boolean isAdmin = false; + if (executor instanceof Actor) { + isAdmin = executorDao.isAdministrator((Actor) executor); + } + if (idsOrNull == null) { + for (PermissionRule r : requiredRules) { + if (permission.equals(r.getPermission()) && type.equals(r.getObjectType())) { + if (!r.isAllowed(type, null, isAdmin, permission)) { + return Collections.emptySet(); + } + } + } + return Collections.emptySet(); + } + Set res = new HashSet(idsOrNull.size()); + for (Long idOrNull : idsOrNull) { + boolean bOk = true; + for (PermissionRule r : requiredRules) { + if (permission.equals(r.getPermission()) && type.equals(r.getObjectType())) { + if (!r.isAllowed(type, idOrNull, isAdmin, permission)) { + bOk = false; + break; + } + } + } + if (bOk) { + res.add(idOrNull); + } + } + return res; + } + private Set checkImplicitRules(Executor executor, Permission permission, SecuredObjectType type, Collection idsOrNull) { + boolean isAdmin = false; + if (executor instanceof Actor) { + isAdmin = executorDao.isAdministrator((Actor) executor); + } + if (idsOrNull == null) { + for (PermissionRule r : implicitRules) { + if (permission.equals(r.getPermission()) && type.equals(r.getObjectType())) { + if (!r.isAllowed(type, null, isAdmin, permission)) { + return Collections.emptySet(); + } + } + } + return Collections.emptySet(); + } + Set res = new HashSet(idsOrNull.size()); + for (Long idOrNull : idsOrNull) { + boolean bOk = true; + for (PermissionRule r : implicitRules) { + if (permission.equals(r.getPermission()) && type.equals(r.getObjectType())) { + if (!r.isAllowed(type, idOrNull, isAdmin, permission)) { + bOk = false; + break; + } + } + } + if (bOk) { + res.add(idOrNull); + } + } + return res; + } + + public Set selectAllowedIds(Executor executor, Permission permission, SecuredObjectType type, List idsOrNull, boolean checkPrivileged) { + if (!SecurityCheckProperties.isPermissionCheckRequired(type)) { + return checkRequiredRules(executor, permission, type, idsOrNull); + } + return filterAllowedIds(executor, permission, type, idsOrNull, checkPrivileged); + } + /** * Returns subset of `idsOrNull` for which `actor` has `permission`. If `idsOrNull` is null (e.g. when called from isAllowedForAny()), * non-empty set (containing arbitrary value) means positive check result. @@ -220,7 +404,7 @@ public Set filterAllowedIds(Executor executor, Permission permission, Secu if (permission == Permission.NONE) { // Optimization; see comments at NONE definition. - return Collections.emptySet(); + return checkImplicitRules(executor, permission, type, idsOrNull); } final Set executorWithGroups = getExecutorWithAllHisGroups(executor); @@ -245,7 +429,7 @@ public Set filterAllowedIds(Executor executor, Permission permission, Secu Set result = new HashSet<>(); for (List idsPart : haveIds ? Lists.partition(idsOrNull, SystemProperties.getDatabaseParametersCount()) : nonEmptyListList) { - JPQLQuery q = queryFactory.select(pm.id).from(pm) + JPQLQuery q = queryFactory.select(pm.objectId).from(pm) .where(pm.executor.in(executorWithGroups) .and(pm.objectType.eq(type)) .and(pm.permission.in(subst.selfPermissions))); @@ -255,7 +439,7 @@ public Set filterAllowedIds(Executor executor, Permission permission, Secu return nonEmptySet; } } - return result; + return checkImplicitRules(executor, permission, type, result); } /** @@ -328,7 +512,11 @@ public boolean[] isAllowed(User user, Permission permi .fetch()); } for (int i = 0; i < securedObjects.size(); i++) { - result[i] = allowedIdentifiableIds.contains(securedObjects.get(i).getIdentifiableId()); + if (!SecurityCheckProperties.isPermissionCheckRequired(securedObjects.get(i).getSecuredObjectType())) { + result[i] = checkRequiredRules(user.getActor(), permission, securedObjects.get(i).getSecuredObjectType(), securedObjects.get(i).getIdentifiableId()); + } else { + result[i] = allowedIdentifiableIds.contains(securedObjects.get(i).getIdentifiableId()); + } } return result; } diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/dao/PermissionRule.java b/wfe-core/src/main/java/ru/runa/wfe/security/dao/PermissionRule.java new file mode 100644 index 0000000000..bd0f5c249c --- /dev/null +++ b/wfe-core/src/main/java/ru/runa/wfe/security/dao/PermissionRule.java @@ -0,0 +1,55 @@ +package ru.runa.wfe.security.dao; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import ru.runa.wfe.security.Permission; +import ru.runa.wfe.security.SecuredObjectType; +import ru.runa.wfe.user.Executor; + +@Getter +@Setter +@NoArgsConstructor +public class PermissionRule { + + private Permission permission; + private SecuredObjectType objectType; + private Long objectId; + private Boolean isAdministrator; + private Executor executor; + + public PermissionRule(SecuredObjectType type, Permission perm, Boolean isAdmin) { + this.objectType = type; + this.permission = perm; + this.isAdministrator = isAdmin; + } + + public boolean isAllowed(SecuredObjectType type, Long id, Boolean isAdmin, Permission perm) { + if (permission != null) { + if (! permission.equals(perm) ) { + return false; + } + } + + if (objectType != null) { + if ( !objectType.equals(type)) { + return false; + } + } + + if (objectId != null) { + if (!objectId.equals(id)) { + return false; + } + } + + if (isAdministrator != null) { + if (!isAdministrator.equals(isAdmin)) { + return false; + } + } + + return true; + } +} diff --git a/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthenticationLogic.java b/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthenticationLogic.java index b2deb6dc94..84850cbfef 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthenticationLogic.java +++ b/wfe-core/src/main/java/ru/runa/wfe/security/logic/AuthenticationLogic.java @@ -19,6 +19,7 @@ package ru.runa.wfe.security.logic; import java.security.Principal; +import java.util.Collections; import java.util.List; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; @@ -27,6 +28,9 @@ import org.springframework.beans.factory.annotation.Required; import ru.runa.wfe.commons.logic.CommonLogic; import ru.runa.wfe.security.AuthenticationException; +import ru.runa.wfe.security.SecuredObjectType; +import ru.runa.wfe.security.SecurityCheckProperties; +import ru.runa.wfe.security.auth.InternalDbNameLoginModule; import ru.runa.wfe.security.auth.KerberosCallbackHandler; import ru.runa.wfe.security.auth.LoginModuleConfiguration; import ru.runa.wfe.security.auth.PasswordLoginModuleCallbackHandler; @@ -40,6 +44,7 @@ * Created on 14.03.2005 */ public class AuthenticationLogic extends CommonLogic { + private List loginHandlers; @Required @@ -56,6 +61,17 @@ public User authenticate(byte[] kerberosToken) throws AuthenticationException { } public User authenticate(String name, String password) throws AuthenticationException { + if (!SecurityCheckProperties.isPermissionCheckRequired(SecuredObjectType.SYSTEM)) { + Actor curActor = this.executorDao.getActor(name); + if (curActor != null) { + if (this.executorDao.hasPassword(curActor)) { + return authenticate(new PasswordLoginModuleCallbackHandler(name, password), AuthType.DB); + } else { + return authenticateByName(new PasswordLoginModuleCallbackHandler(name, password), AuthType.DB); + } + } + return authenticateByName(new PasswordLoginModuleCallbackHandler(name, password), AuthType.DB); + } return authenticate(new PasswordLoginModuleCallbackHandler(name, password), AuthType.DB); } @@ -77,6 +93,24 @@ private User authenticate(CallbackHandler callbackHandler, AuthType authType) th throw new AuthenticationException(e); } } + + private User authenticateByName(CallbackHandler callbackHandler, AuthType authType) throws AuthenticationException { + try { + ru.runa.wfe.security.auth.LoginModuleConfiguration config = new ru.runa.wfe.security.auth.LoginModuleConfiguration(); + config.setLoginModuleClassNames(Collections.singletonList(InternalDbNameLoginModule.class.getName())); + + LoginContext loginContext = new LoginContext(LoginModuleConfiguration.APP_NAME, null, callbackHandler, config); + loginContext.login(); + Subject subject = loginContext.getSubject(); + User user = SubjectPrincipalsHelper.getUser(subject); + SubjectPrincipalsHelper.validateUser(user); + callHandlers(user.getActor(), authType); + log.debug(user.getName() + " successfully authenticated"); + return user; + } catch (Exception e) { + throw new AuthenticationException(e); + } + } private void callHandlers(Actor actor, AuthType type) { for (LoginHandler handler : loginHandlers) { 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 1b26f8421f..e316d3b791 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 @@ -94,6 +94,10 @@ public int hashCode() { return Objects.hash(id, permission); } } + + public Set selectAllowedIds(Executor executor, Permission permission, SecuredObjectType securedObjectType, List idsOrNull) { + return permissionDao.selectAllowedIds(executor, permission, securedObjectType, idsOrNull, true); + } public boolean isAllowed(User user, Permission permission, SecuredObject object) { return permissionDao.isAllowed(user, permission, object.getSecuredObjectType(), object.getIdentifiableId()); diff --git a/wfe-core/src/main/java/ru/runa/wfe/task/logic/TaskLogic.java b/wfe-core/src/main/java/ru/runa/wfe/task/logic/TaskLogic.java index 6c2043328a..79cae15d95 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/task/logic/TaskLogic.java +++ b/wfe-core/src/main/java/ru/runa/wfe/task/logic/TaskLogic.java @@ -77,6 +77,10 @@ public class TaskLogic extends WfCommonLogic { private TaskAssigner taskAssigner; @Autowired private ExecutorLogic executorLogic; + + public boolean isTaskDelegationEnabled() { + return SystemProperties.isTaskDelegationEnabled(); + } public WfTask completeTask(User user, Long taskId, Map variables) throws TaskDoesNotExistException { Task task = taskDao.getNotNull(taskId); diff --git a/wfe-core/src/main/java/ru/runa/wfe/user/dao/ExecutorDao.java b/wfe-core/src/main/java/ru/runa/wfe/user/dao/ExecutorDao.java index 66f68319fc..21d63266f3 100644 --- a/wfe-core/src/main/java/ru/runa/wfe/user/dao/ExecutorDao.java +++ b/wfe-core/src/main/java/ru/runa/wfe/user/dao/ExecutorDao.java @@ -309,14 +309,19 @@ public T create(T executor) { * New actor password. */ public void setPassword(Actor actor, String password) { - Preconditions.checkNotNull(password, "Password must be specified."); ActorPassword actorPassword = getActorPassword(actor); if (actorPassword == null) { - actorPassword = new ActorPassword(actor, password); - sessionFactory.getCurrentSession().save(actorPassword); + if (!Strings.isNullOrEmpty(password)) { + actorPassword = new ActorPassword(actor, password); + sessionFactory.getCurrentSession().save(actorPassword); + } } else { - actorPassword.setPassword(password); - sessionFactory.getCurrentSession().merge(actorPassword); + if (!Strings.isNullOrEmpty(password)) { + actorPassword.setPassword(password); + sessionFactory.getCurrentSession().merge(actorPassword); + } else { + sessionFactory.getCurrentSession().delete(actorPassword); + } } } @@ -621,6 +626,11 @@ public void remove(Executor executor) { executor = (Executor) sessionFactory.getCurrentSession().get(Executor.class, executor.getId()); sessionFactory.getCurrentSession().delete(executor); } + + public boolean hasPassword(Actor actor) { + ActorPassword actorPassword = getActorPassword(actor); + return actorPassword != null && actorPassword.getPassword().length > 0; + } /** * Generates code for actor, if code not set (equals 0). If code is already set, when throws {@linkplain ExecutorAlreadyExistsException} if diff --git a/wfe-core/src/main/resources/securitycheck.properties b/wfe-core/src/main/resources/securitycheck.properties new file mode 100644 index 0000000000..0a88533e59 --- /dev/null +++ b/wfe-core/src/main/resources/securitycheck.properties @@ -0,0 +1,11 @@ +# Enable security check +permission.check.required.EXECUTOR=false +permission.check.required.DEFINITION=false +permission.check.required.PROCESS=false +permission.check.required.REPORT=false +permission.check.required.REPORTS=false +permission.check.required.RELATIONS=false +permission.check.required.RELATION=false +permission.check.required.BOTSTATIONS=false +permission.check.required.SYSTEM=false +permission.check.required.DATASOURCES=false \ No newline at end of file diff --git a/wfe-core/src/main/resources/system.properties b/wfe-core/src/main/resources/system.properties index 058af1c56a..830aaf7cd7 100644 --- a/wfe-core/src/main/resources/system.properties +++ b/wfe-core/src/main/resources/system.properties @@ -21,6 +21,7 @@ escalation.default.hierarchy.loader=ru.runa.wfe.extension.orgfunction.TestOrgFun task.default.deadline=2 hours task.almostDeadlinePercents=90 task.assignment.strict.rules.enabled = true +task.delegation.enabled=true # used to prevent cyclic fork execution token.maximum.depth = 100 diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/shared/FilesSupplierConfig.java b/wfe-office/src/main/java/ru/runa/wfe/office/shared/FilesSupplierConfig.java index be800426db..47d52cde22 100644 --- a/wfe-office/src/main/java/ru/runa/wfe/office/shared/FilesSupplierConfig.java +++ b/wfe-office/src/main/java/ru/runa/wfe/office/shared/FilesSupplierConfig.java @@ -47,6 +47,10 @@ public void setOutputFileVariableName(String outputFileVariableName) { this.outputFileVariableName = outputFileVariableName; } + public String getOutputFileVariableName() { + return outputFileVariableName; + } + protected abstract MediaType getContentType(); public abstract String getDefaultOutputFileName(); diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/ConditionProcessor.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/ConditionProcessor.java index 872920d8ea..b30768482c 100644 --- a/wfe-office/src/main/java/ru/runa/wfe/office/storage/ConditionProcessor.java +++ b/wfe-office/src/main/java/ru/runa/wfe/office/storage/ConditionProcessor.java @@ -19,9 +19,9 @@ public class ConditionProcessor { public static final char UNICODE_CHARACTER_OVERLINE = '\u203E'; - private static final String LIKE_EXPR_END = ".toLowerCase()) >= 0"; + private static final String LIKE_EXPR_END = ") != null"; - private static final String LIKE_EXPR_START = ".toLowerCase().indexOf("; + private static final String LIKE_EXPR_START = ".match("; private static final String LIKE_LITERAL = "like"; @@ -43,6 +43,7 @@ public class ConditionProcessor { private static String previousOperator = ""; private static ScriptEngine engine; + static { ScriptEngineManager engineManager = new ScriptEngineManager(); engine = engineManager.getEngineByName("JavaScript"); @@ -83,16 +84,16 @@ private static String parse(String condition, Map attributes, Va sb = appendAttribute(sb, attributes, token.replace(UNICODE_CHARACTER_OVERLINE, ' ')); } else if (token.equalsIgnoreCase(LIKE_LITERAL)) { previousOperator = LIKE_LITERAL; - sb.append(LIKE_EXPR_START); + sb.append(LIKE_EXPR_START).append("/"); token = st.nextToken(); - sb.append(token); - sb.append(LIKE_EXPR_END); + if (token.startsWith("@")) { + sb.append(extractVariableValue(token, variableProvider, false).replace("%", ".*")); + } else { + sb.append(token.replace("%", ".*")); + } + sb.append("/g").append(LIKE_EXPR_END); } else if (token.startsWith("@")) { - String variableName = token.substring(1); - Object value = variableProvider.getValue(variableName); - String toAppend = formatParameterValue(value); - sb.append(SPACE); - sb.append(toAppend); + sb.append(SPACE).append(extractVariableValue(token, variableProvider, true)); } else { sb.append(SPACE); if (previousAttributeValue != null && previousAttributeValue instanceof Date && operators.contains(previousOperator)) { @@ -109,6 +110,12 @@ private static String parse(String condition, Map attributes, Va return sb.toString(); } + private static String extractVariableValue(String token, VariableProvider variableProvider, boolean adjustValue) { + final String variableName = token.substring(1); + final Object value = variableProvider.getValue(variableName); + return formatParameterValue(value, adjustValue); + } + private static long getTime(String source) { source = source.replaceAll("'", ""); try { @@ -131,14 +138,18 @@ private static StringBuilder appendAttribute(StringBuilder sb, Map outputParams = paramsDef.getOutputParams(); - if (outputParams != null) { - for (Entry entry : outputParams.entrySet()) { - String variableName = entry.getValue().getVariableName(); - if (variable.getDefinition().getName().equals(variableName)) { - return true; - } - } - } - } - } - return false; - } - - protected boolean executeSql(String sql) throws Exception { + protected boolean executeSql(String sql) throws JdbcStoreException { log.info(sql); try (Connection conn = ds.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { return ps.execute() && ps.getResultSet().next() || ps.getUpdateCount() > 0; @@ -160,30 +133,22 @@ protected boolean checkVariableType(WfVariable variable) { return vd.isUserType() || vd.getFormatNotNull() instanceof ListFormat && components != null && components.length > 0; } - protected void initParams(Properties properties, WfVariable variable) throws Exception { + protected void initParams(Properties properties, UserType userType) throws Exception { Preconditions.checkNotNull(properties); - Preconditions.checkNotNull(variable); - Preconditions.checkArgument(checkVariableType(variable), - "Variable '" + variable.getDefinition().getName() + "' must be user type or list of user types."); + Preconditions.checkNotNull(userType); constraints = (ExcelConstraints) properties.get(PROP_CONSTRAINTS); fullPath = properties.getProperty(PROP_PATH); - if (fullPath.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE) || fullPath.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE_VARIABLE)) { - String dsName = null; - if (fullPath.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE)) { - dsName = fullPath.substring(DataSourceStuff.PATH_PREFIX_DATA_SOURCE.length()); - } else { - dsName = (String) variableProvider.getValueNotNull(fullPath.substring(DataSourceStuff.PATH_PREFIX_DATA_SOURCE_VARIABLE.length())); - } - ds = (JdbcDataSource) DataSourceStorage.getDataSource(dsName); - createTableIfNotExist(variable); + ds = (JdbcDataSource) DataSourceStorage.parseDataSource(fullPath, variableProvider); + if (ds != null) { + createTableIfNotExist(userType); } } - protected void createTableIfNotExist(WfVariable variable) throws Exception { + protected void createTableIfNotExist(UserType userType) throws Exception { String tableName = tableName(); if (!executeSql(MessageFormat.format(tableExistsSql(), tableName))) { String columnDefinitions = ""; - for (VariableDefinition vd : userType(variable).getAttributes()) { + for (VariableDefinition vd : userType.getAttributes()) { columnDefinitions += (columnDefinitions.length() > 0 ? SQL_LIST_SEPARATOR : "") + MessageFormat.format(SQL_COLUMN_DEFINITION, adjustIdentifier(vd.getName()), typeMap().get(vd.getFormatNotNull().getClass())); } @@ -204,14 +169,10 @@ protected Object adjustValue(Object value) { abstract protected Map, String> typeMap(); @Override - public ExecutionResult findByFilter(Properties properties, WfVariable variable, String condition) throws Exception { - if (!existOutputParamByVariableName(variable)) { - throw new WrongParameterException(variable.getDefinition().getName()); - } - initParams(properties, variable); + public ExecutionResult findByFilter(Properties properties, UserType userType, String condition) throws Exception { + initParams(properties, userType); String columns = ""; - UserType ut = variable.getDefinition().getFormatComponentUserTypes()[0]; - for (VariableDefinition vd : ut.getAttributes()) { + for (VariableDefinition vd : userType.getAttributes()) { String variableName = adjustIdentifier(vd.getName()); columns += (columns.length() > 0 ? SQL_LIST_SEPARATOR : "") + MessageFormat.format(SQL_COLUMN, variableName); } @@ -220,8 +181,8 @@ public ExecutionResult findByFilter(Properties properties, WfVariable variable, try (ResultSet rs = ps.executeQuery()) { List utmList = Lists.newArrayList(); while (rs.next()) { - UserTypeMap utm = new UserTypeMap(ut); - for (VariableDefinition vd : ut.getAttributes()) { + UserTypeMap utm = new UserTypeMap(userType); + for (VariableDefinition vd : userType.getAttributes()) { String variableName = vd.getName(); utm.put(variableName, adjustValue(rs.getObject(adjustIdentifier(variableName)))); } @@ -235,7 +196,10 @@ public ExecutionResult findByFilter(Properties properties, WfVariable variable, @Override public void update(Properties properties, WfVariable variable, String condition) throws Exception { - initParams(properties, variable); + Preconditions.checkArgument(checkVariableType(variable), + "Variable '" + variable.getDefinition().getName() + "' must be user type or list of user types."); + initParams(properties, userType(variable)); + String columns = ""; for (VariableDefinition vd : variable.getDefinition().getUserType().getAttributes()) { String variableName = vd.getName(); @@ -259,29 +223,21 @@ private String condition(String condition) { String token = st.nextToken(); if (token.startsWith("[") && token.endsWith("]")) { sb.append(SPACE); - sb.append('"').append(token.replace(ConditionProcessor.UNICODE_CHARACTER_OVERLINE, ' ').substring(1, token.length() - 1)).append('"'); + sb.append('"').append(token.replace(ConditionProcessor.UNICODE_CHARACTER_OVERLINE, ' '), 1, token.length() - 1).append('"'); } else if (token.equalsIgnoreCase(LIKE_LITERAL)) { sb.append(SPACE); sb.append(LIKE_LITERAL); sb.append(SPACE); - sb.append(st.nextToken()); - } else if (token.startsWith("@")) { - String variableName = token.substring(1); - String toAppend = ""; - if (variableProvider instanceof ParamBasedVariableProvider) { - ParamsDef paramsDef = ((ParamBasedVariableProvider) variableProvider).getParamsDef(); - if (paramsDef != null) { - if (paramsDef.getInputParam(variableName) != null) { - Object inputParamValue = paramsDef.getInputParamValue(variableName, variableProvider); - toAppend = sqlValue(inputParamValue, variableProvider.getVariable(variableName).getDefinition().getFormatNotNull()); - } else { - WfVariable wfVariable = variableProvider.getVariableNotNull(variableName); - toAppend = sqlValue(wfVariable.getValue(), wfVariable.getDefinition().getFormatNotNull()); - } + if (st.hasMoreTokens()) { + final String nextToken = st.nextToken(); + if (nextToken.startsWith("@")) { + sb.append(extractVariableValue(nextToken)); + } else { + sb.append(nextToken); } - sb.append(SPACE); - sb.append(toAppend); } + } else if (token.startsWith("@")) { + sb.append(SPACE).append(extractVariableValue(token)); } else if (token.equals(DOUBLE_EQUALS)) { sb.append(SPACE); sb.append(EQUALS); @@ -294,14 +250,18 @@ private String condition(String condition) { } @Override - public void delete(Properties properties, WfVariable variable, String condition) throws Exception { - initParams(properties, variable); + public void delete(Properties properties, UserType userType, String condition) throws Exception { + initParams(properties, userType); executeSql(MessageFormat.format(SQL_DELETE, tableName(), condition(condition))); } + @SuppressWarnings("unchecked") @Override public void save(Properties properties, WfVariable variable, boolean appendTo) throws Exception { - initParams(properties, variable); + Preconditions.checkArgument(checkVariableType(variable), + "Variable '" + variable.getDefinition().getName() + "' must be user type or list of user types."); + initParams(properties, userType(variable)); + List data = Lists.newArrayList(); if (variable.getDefinition().isUserType()) { data.add((UserTypeMap) variable.getValue()); @@ -320,4 +280,29 @@ public void save(Properties properties, WfVariable variable, boolean appendTo) t } } + private String extractVariableValue(String token) { + final String variableName = token.substring(1); + String toAppend = ""; + if (variableProvider instanceof ParamBasedVariableProvider) { + ParamsDef paramsDef = ((ParamBasedVariableProvider) variableProvider).getParamsDef(); + if (paramsDef != null) { + if (paramsDef.getInputParam(variableName) != null) { + Object inputParamValue = paramsDef.getInputParamValue(variableName, variableProvider); + toAppend = sqlValue(inputParamValue, variableProvider.getVariable(variableName).getDefinition().getFormatNotNull()); + } else { + WfVariable wfVariable = variableProvider.getVariableNotNull(variableName); + toAppend = sqlValue(wfVariable.getValue(), wfVariable.getDefinition().getFormatNotNull()); + } + } + } else { + WfVariable wfVariable = variableProvider.getVariableNotNull(variableName); + toAppend = sqlValue(wfVariable.getValue(), wfVariable.getDefinition().getFormatNotNull()); + } + return toAppend; + } + + protected UserType userType(WfVariable variable) { + return variable.getDefinition().isUserType() ? variable.getDefinition().getUserType() + : variable.getDefinition().getFormatComponentUserTypes()[0]; + } } diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreHelper.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreHelper.java deleted file mode 100644 index e9fa1a160c..0000000000 --- a/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreHelper.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.runa.wfe.office.storage; - -import ru.runa.wfe.office.storage.binding.DataBinding; -import ru.runa.wfe.office.storage.binding.ExecutionResult; -import ru.runa.wfe.var.dto.WfVariable; -import ru.runa.wfe.var.format.VariableFormat; - -public interface StoreHelper { - - void setVariableFormat(VariableFormat format); - - ExecutionResult execute(DataBinding binding, WfVariable variable); - -} diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreOperation.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreOperation.java deleted file mode 100644 index 8cb7be1054..0000000000 --- a/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreOperation.java +++ /dev/null @@ -1,14 +0,0 @@ -package ru.runa.wfe.office.storage; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import ru.runa.wfe.office.storage.binding.QueryType; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface StoreOperation { - - QueryType value(); -} diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreService.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreService.java index d473ba776a..e934a655eb 100644 --- a/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreService.java +++ b/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreService.java @@ -7,6 +7,7 @@ import java.util.Properties; import java.util.Set; import ru.runa.wfe.office.storage.binding.ExecutionResult; +import ru.runa.wfe.var.UserType; import ru.runa.wfe.var.dto.WfVariable; public interface StoreService { @@ -17,11 +18,11 @@ public interface StoreService { void createFileIfNotExist(String path) throws Exception; - ExecutionResult findByFilter(Properties properties, WfVariable variable, String condition) throws Exception; + ExecutionResult findByFilter(Properties properties, UserType userType, String condition) throws Exception; void update(Properties properties, WfVariable variable, String condition) throws Exception; - void delete(Properties properties, WfVariable variable, String condition) throws Exception; + void delete(Properties properties, UserType userType, String condition) throws Exception; void save(Properties properties, WfVariable variable, boolean appendTo) throws Exception; diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreServiceImpl.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreServiceImpl.java index e4b658f94c..0298049ee6 100644 --- a/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreServiceImpl.java +++ b/wfe-office/src/main/java/ru/runa/wfe/office/storage/StoreServiceImpl.java @@ -25,7 +25,6 @@ import ru.runa.wfe.InternalApplicationException; import ru.runa.wfe.datasource.DataSource; import ru.runa.wfe.datasource.DataSourceStorage; -import ru.runa.wfe.datasource.DataSourceStuff; import ru.runa.wfe.datasource.ExcelDataSource; import ru.runa.wfe.extension.handler.ParamDef; import ru.runa.wfe.extension.handler.ParamsDef; @@ -81,7 +80,7 @@ public void createFileIfNotExist(String path) throws InternalApplicationExceptio } try (Workbook workbook = path.endsWith(XLSX_SUFFIX) ? new XSSFWorkbook() : new HSSFWorkbook(); OutputStream os = new FileOutputStream(path)) { - workbook.createSheet(); + workbook.createSheet(tableName()); workbook.write(os); } catch (Exception e) { log.error("", e); @@ -90,10 +89,7 @@ public void createFileIfNotExist(String path) throws InternalApplicationExceptio } @Override - public ExecutionResult findByFilter(Properties properties, WfVariable variable, String condition) throws Exception { - if (!existOutputParamByVariableName(variable)) { - throw new WrongParameterException(variable.getDefinition().getName()); - } + public ExecutionResult findByFilter(Properties properties, UserType userType, String condition) throws Exception { if (!isConditionValid(condition)) { throw new WrongOperatorException(condition); } @@ -107,34 +103,24 @@ public void update(Properties properties, WfVariable variable, String condition) initParams(properties); Workbook wb = getWorkbook(fullPath); update(wb, constraints, variable.getValue(), format, condition, false); - OutputStream os = null; - try { - os = new FileOutputStream(fullPath); + try (OutputStream os = new FileOutputStream(fullPath)) { wb.write(os); } catch (IOException e) { log.error("", e); throw new BlockedFileException(fullPath); - } finally { - os.close(); } } @Override - public void delete(Properties properties, WfVariable variable, String condition) throws Exception { + public void delete(Properties properties, UserType userType, String condition) throws Exception { initParams(properties); Workbook wb = getWorkbook(fullPath); - update(wb, constraints, variable.getValue(), format, condition, true); - OutputStream os = null; - try { - os = new FileOutputStream(fullPath); + update(wb, constraints, null, format, condition, true); + try (OutputStream os = new FileOutputStream(fullPath)) { wb.write(os); } catch (IOException e) { log.error("", e); throw new BlockedFileException(fullPath); - } finally { - if (os != null) { - os.close(); - } } } @@ -143,17 +129,11 @@ public void save(Properties properties, WfVariable variable, boolean appendTo) t initParams(properties); Workbook wb = getWorkbook(fullPath); save(wb, constraints, format, variable, appendTo); - OutputStream os = null; - try { - os = new FileOutputStream(fullPath); + try (OutputStream os = new FileOutputStream(fullPath)) { wb.write(os); } catch (IOException e) { log.error("", e); throw new BlockedFileException(fullPath); - } finally { - if (os != null) { - os.close(); - } } } @@ -162,18 +142,10 @@ private void initParams(Properties properties) throws InternalApplicationExcepti constraints = (ExcelConstraints) properties.get(PROP_CONSTRAINTS); format = (VariableFormat) properties.get(PROP_FORMAT); fullPath = properties.getProperty(PROP_PATH); - if (fullPath.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE) || fullPath.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE_VARIABLE)) { - String dsName; - if (fullPath.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE)) { - dsName = fullPath.substring(DataSourceStuff.PATH_PREFIX_DATA_SOURCE.length()); - } else { - dsName = (String) variableProvider.getValueNotNull(fullPath.substring(DataSourceStuff.PATH_PREFIX_DATA_SOURCE_VARIABLE.length())); - } - DataSource ds = DataSourceStorage.getDataSource(dsName); - if (ds instanceof ExcelDataSource) { - ExcelDataSource eds = (ExcelDataSource) ds; - fullPath = eds.getFilePath() + "/" + tableName() + XLSX_SUFFIX; - } + final DataSource dataSource = DataSourceStorage.parseDataSource(fullPath, variableProvider); + if (dataSource instanceof ExcelDataSource) { + final ExcelDataSource eds = (ExcelDataSource) dataSource; + fullPath = eds.getFilePath() + "/" + tableName() + XLSX_SUFFIX; } createFileIfNotExist(fullPath); } @@ -181,17 +153,16 @@ private void initParams(Properties properties) throws InternalApplicationExcepti @SuppressWarnings("unchecked") private void update(Workbook workbook, ExcelConstraints constraints, Object variable, VariableFormat variableFormat, String condition, boolean clear) { - List list = findAll(workbook, constraints, variableFormat); + List list = findAll(workbook, constraints, variableFormat); boolean changed = false; + int i = 0; if (Strings.isNullOrEmpty(condition)) { - int i = 0; for (Object object : list) { changeVariable(constraints, variable, clear, list, i, object); i++; } changed = true; } else { - int i = 0; for (Object object : list) { if (variableFormat instanceof UserTypeFormat) { if (ConditionProcessor.filter(condition, (Map) object, variableProvider)) { @@ -207,7 +178,7 @@ private void update(Workbook workbook, ExcelConstraints constraints, Object vari } } - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) private void changeVariable(ExcelConstraints constraints, Object variable, boolean clear, List list, int i, Object object) { if (clear) { list.set(i, null); @@ -487,7 +458,7 @@ private boolean existOutputParamByVariableName(WfVariable variable) { } } } - return false; + return variableProvider.getVariable(variable.getDefinition().getName()) != null; } private String tableName() { diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/ExternalStorageHandler.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/ExternalStorageHandler.java index a7feb942e8..ac5094c2f5 100644 --- a/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/ExternalStorageHandler.java +++ b/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/ExternalStorageHandler.java @@ -3,26 +3,19 @@ import java.util.HashMap; import java.util.Map; import ru.runa.wfe.InternalApplicationException; -import ru.runa.wfe.datasource.DataSource; import ru.runa.wfe.datasource.DataSourceStorage; -import ru.runa.wfe.datasource.DataSourceStuff; -import ru.runa.wfe.datasource.ExcelDataSource; -import ru.runa.wfe.datasource.JdbcDataSource; import ru.runa.wfe.definition.FileDataProvider; import ru.runa.wfe.office.shared.FilesSupplierConfigParser; import ru.runa.wfe.office.shared.OfficeFilesSupplierHandler; -import ru.runa.wfe.office.storage.OracleStoreService; -import ru.runa.wfe.office.storage.PostgreSqlStoreService; -import ru.runa.wfe.office.storage.SqlServerStoreService; -import ru.runa.wfe.office.storage.StoreHelper; import ru.runa.wfe.office.storage.StoreService; -import ru.runa.wfe.office.storage.StoreServiceImpl; import ru.runa.wfe.office.storage.binding.DataBinding; import ru.runa.wfe.office.storage.binding.DataBindings; import ru.runa.wfe.office.storage.binding.ExecutionResult; -import ru.runa.wfe.office.storage.services.StoreHelperImpl; +import ru.runa.wfe.office.storage.services.StoreHelper; +import ru.runa.wfe.var.UserType; import ru.runa.wfe.var.VariableProvider; import ru.runa.wfe.var.dto.WfVariable; +import ru.runa.wfe.var.format.UserTypeFormat; public class ExternalStorageHandler extends OfficeFilesSupplierHandler { @@ -32,50 +25,50 @@ protected FilesSupplierConfigParser createParser() { } @Override - protected Map executeAction(VariableProvider variableProvider, FileDataProvider fileDataProvider) throws Exception { - Map result = new HashMap(); - StoreService storeService = null; - String dsName = config.getInputFilePath(); - if (dsName.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE) || dsName.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE_VARIABLE)) { - if (dsName.startsWith(DataSourceStuff.PATH_PREFIX_DATA_SOURCE)) { - dsName = dsName.substring(dsName.indexOf(':') + 1); - } else { - dsName = (String) variableProvider.getValue(dsName.substring(dsName.indexOf(':') + 1)); - } - DataSource ds = DataSourceStorage.getDataSource(dsName); - if (ds instanceof JdbcDataSource) { - switch (((JdbcDataSource) ds).getDbType()) { - case SqlServer: - storeService = new SqlServerStoreService(variableProvider); - break; - case Oracle: - storeService = new OracleStoreService(variableProvider); - break; - case PostgreSql: - storeService = new PostgreSqlStoreService(variableProvider); - break; - default: - throw new InternalApplicationException("Database type " + ((JdbcDataSource) ds).getDbType().name() + " not supported."); - } - } else if (ds instanceof ExcelDataSource) { - storeService = new StoreServiceImpl(variableProvider); - } else { - throw new InternalApplicationException("Data source type " + ds.getClass().getSimpleName() + " not supported."); - } - } else { - storeService = new StoreServiceImpl(variableProvider); - } - StoreHelper storeHelper = new StoreHelperImpl(config, variableProvider, storeService); + protected Map executeAction(VariableProvider variableProvider, FileDataProvider fileDataProvider) { + final Map result = new HashMap<>(); + final StoreService storeService = StoreServiceFactory.create( + DataSourceStorage.parseDataSource(config.getInputFilePath(), variableProvider), + variableProvider + ); + final StoreHelper storeHelper = new StoreHelper(config, variableProvider, storeService); + for (DataBinding binding : config.getBindings()) { - WfVariable variable = variableProvider.getVariableNotNull(binding.getVariableName()); - binding.getConstraints().applyPlaceholders(variableProvider); - storeHelper.setVariableFormat(variable.getDefinition().getFormatNotNull()); - ExecutionResult executionResult = storeHelper.execute(binding, variable); - if (executionResult.isNeedReturn()) { - result.put(binding.getVariableName(), executionResult.getValue()); + try { + final ExecutionResult executionResult = execute(variableProvider, binding, storeHelper); + if (executionResult.isNeedReturn()) { + result.put(binding.getVariableName(), executionResult.getValue()); + } + } catch (Exception e) { + log.error("Error while executing operation with DataStore", e); + throw new InternalApplicationException(e); } } return result; } + protected ExecutionResult execute(VariableProvider variableProvider, DataBinding binding, StoreHelper storeHelper) throws Exception { + binding.getConstraints().applyPlaceholders(variableProvider); + final WfVariable variable = variableProvider.getVariableNotNull(binding.getVariableName()); + switch (config.getQueryType()) { + case INSERT: { + storeHelper.setVariableFormat(variable.getDefinition().getFormatNotNull()); + return storeHelper.save(binding, variable); + } + case UPDATE: { + storeHelper.setVariableFormat(variable.getDefinition().getFormatNotNull()); + return storeHelper.update(binding, variable, config.getCondition()); + } + case SELECT: { + storeHelper.setVariableFormat(variable.getDefinition().getFormatNotNull()); + return storeHelper.findByFilter(binding, storeHelper.userType(variable), config.getCondition()); + } + case DELETE: + final UserType userType = storeHelper.userType(variable); + storeHelper.setVariableFormat(new UserTypeFormat(userType)); + return storeHelper.delete(binding, userType, config.getCondition()); + default: + throw new IllegalStateException("Unexpected value: " + config.getQueryType()); + } + } } diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/InternalStorageHandler.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/InternalStorageHandler.java new file mode 100644 index 0000000000..3170e1eeb6 --- /dev/null +++ b/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/InternalStorageHandler.java @@ -0,0 +1,86 @@ +package ru.runa.wfe.office.storage.handler; + +import com.google.common.collect.Iterables; +import java.util.HashMap; +import java.util.Map; +import ru.runa.wfe.InternalApplicationException; +import ru.runa.wfe.datasource.DataSourceStorage; +import ru.runa.wfe.definition.FileDataProvider; +import ru.runa.wfe.office.excel.OnSheetConstraints; +import ru.runa.wfe.office.shared.FilesSupplierConfigParser; +import ru.runa.wfe.office.shared.OfficeFilesSupplierHandler; +import ru.runa.wfe.office.storage.StoreService; +import ru.runa.wfe.office.storage.binding.DataBinding; +import ru.runa.wfe.office.storage.binding.DataBindings; +import ru.runa.wfe.office.storage.binding.ExecutionResult; +import ru.runa.wfe.office.storage.services.StoreHelper; +import ru.runa.wfe.var.UserType; +import ru.runa.wfe.var.VariableProvider; +import ru.runa.wfe.var.dto.WfVariable; +import ru.runa.wfe.var.format.UserTypeFormat; + +/** + * @author Alekseev Mikhail + * @since #1507 + */ +public class InternalStorageHandler extends OfficeFilesSupplierHandler { + @Override + protected FilesSupplierConfigParser createParser() { + return new StorageBindingsParser(); + } + + @Override + protected Map executeAction(VariableProvider variableProvider, FileDataProvider fileDataProvider) { + final Map result = new HashMap<>(); + final StoreService storeService = StoreServiceFactory.create( + DataSourceStorage.parseDataSource(config.getInputFilePath(), variableProvider), + variableProvider + ); + final StoreHelper storeHelper = new StoreHelper(config, variableProvider, storeService); + + final DataBinding binding = Iterables.getOnlyElement(config.getBindings()); + try { + final ExecutionResult executionResult = execute(variableProvider, binding, storeHelper); + + if (executionResult.isNeedReturn()) { + result.put(config.getOutputFileVariableName() != null ? + config.getOutputFileVariableName() : binding.getVariableName(), executionResult.getValue()); + } + return result; + } catch (Exception e) { + log.error("Error while executing operation with DataStore", e); + throw new InternalApplicationException(e); + } + } + + protected ExecutionResult execute(VariableProvider variableProvider, DataBinding binding, StoreHelper storeHelper) throws Exception { + binding.getConstraints().applyPlaceholders(variableProvider); + switch (config.getQueryType()) { + case INSERT: { + final WfVariable variable = variableProvider.getVariableNotNull(binding.getVariableName()); + storeHelper.setVariableFormat(variable.getDefinition().getFormatNotNull()); + return storeHelper.save(binding, variable); + } + case UPDATE: { + final WfVariable variable = variableProvider.getVariableNotNull(binding.getVariableName()); + storeHelper.setVariableFormat(variable.getDefinition().getFormatNotNull()); + return storeHelper.update(binding, variable, config.getCondition()); + } + case SELECT: { + final WfVariable variable = variableProvider.getVariableNotNull(config.getOutputFileVariableName()); + storeHelper.setVariableFormat(variable.getDefinition().getFormatNotNull()); + return storeHelper.findByFilter( + binding, + variableProvider.getUserType(((OnSheetConstraints) binding.getConstraints()).getSheetName()), + config.getCondition() + ); + } + case DELETE: + final UserType userType = variableProvider.getUserType(((OnSheetConstraints) binding.getConstraints()).getSheetName()); + storeHelper.setVariableFormat(new UserTypeFormat(userType)); + return storeHelper.delete(binding, userType, config.getCondition()); + default: + throw new IllegalStateException("Unexpected value: " + config.getQueryType()); + } + } +} diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/StorageBindingsParser.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/StorageBindingsParser.java index 5e121d56d6..d8b7b921d9 100644 --- a/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/StorageBindingsParser.java +++ b/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/StorageBindingsParser.java @@ -27,9 +27,6 @@ protected void parseCustom(Element root, DataBindings bindings) throws Exception String className = bindingElement.attributeValue("class"); Preconditions.checkNotNull(className, "Missed 'class' attribute in binding element"); - String variableName = bindingElement.attributeValue("variable"); - Preconditions.checkNotNull(variableName, "Missed 'variable' attribute in binding element"); - ExcelConstraints constraints = ClassLoaderUtil.instantiate(className); Element configElement = bindingElement.element("config"); Preconditions.checkNotNull(configElement, "Missed 'config' element in binding element"); @@ -46,6 +43,11 @@ protected void parseCustom(Element root, DataBindings bindings) throws Exception bindings.setQueryType(QueryType.valueOf(conditionsElement.attributeValue("type"))); } + String variableName = bindingElement.attributeValue("variable"); + if (variableName == null && (bindings.getQueryType() == QueryType.INSERT || bindings.getQueryType() == QueryType.UPDATE)) { + throw new IllegalArgumentException("Missed 'variable' attribute in binding element"); + } + DataBinding binding = new DataBinding(); binding.setConstraints(constraints); binding.setVariableName(variableName); diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/StoreServiceFactory.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/StoreServiceFactory.java new file mode 100644 index 0000000000..e422e54afa --- /dev/null +++ b/wfe-office/src/main/java/ru/runa/wfe/office/storage/handler/StoreServiceFactory.java @@ -0,0 +1,42 @@ +package ru.runa.wfe.office.storage.handler; + +import com.google.common.base.Preconditions; +import ru.runa.wfe.InternalApplicationException; +import ru.runa.wfe.datasource.DataSource; +import ru.runa.wfe.datasource.ExcelDataSource; +import ru.runa.wfe.datasource.JdbcDataSource; +import ru.runa.wfe.office.storage.OracleStoreService; +import ru.runa.wfe.office.storage.PostgreSqlStoreService; +import ru.runa.wfe.office.storage.SqlServerStoreService; +import ru.runa.wfe.office.storage.StoreService; +import ru.runa.wfe.office.storage.StoreServiceImpl; +import ru.runa.wfe.var.VariableProvider; + +/** + * @author Alekseev Mikhail + * @since #1394 + */ +public class StoreServiceFactory { + private StoreServiceFactory() { + } + + public static StoreService create(DataSource dataSource, VariableProvider variableProvider) { + Preconditions.checkNotNull(dataSource, "Can't obtain StoreService: dataSource must not be null"); + if (dataSource instanceof JdbcDataSource) { + switch (((JdbcDataSource) dataSource).getDbType()) { + case SqlServer: + return new SqlServerStoreService(variableProvider); + case Oracle: + return new OracleStoreService(variableProvider); + case PostgreSql: + return new PostgreSqlStoreService(variableProvider); + default: + throw new InternalApplicationException("Database type " + ((JdbcDataSource) dataSource).getDbType().name() + " not supported."); + } + } else if (dataSource instanceof ExcelDataSource) { + return new StoreServiceImpl(variableProvider); + } else { + throw new InternalApplicationException("Data source type " + dataSource.getClass().getSimpleName() + " not supported."); + } + } +} diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/services/StoreHelper.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/services/StoreHelper.java new file mode 100644 index 0000000000..d507e7ae67 --- /dev/null +++ b/wfe-office/src/main/java/ru/runa/wfe/office/storage/services/StoreHelper.java @@ -0,0 +1,88 @@ +package ru.runa.wfe.office.storage.services; + +import com.google.common.collect.Maps; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Properties; +import lombok.extern.apachecommons.CommonsLog; +import ru.runa.wfe.InternalApplicationException; +import ru.runa.wfe.office.storage.StoreService; +import ru.runa.wfe.office.storage.binding.DataBinding; +import ru.runa.wfe.office.storage.binding.DataBindings; +import ru.runa.wfe.office.storage.binding.ExecutionResult; +import ru.runa.wfe.office.storage.binding.QueryType; +import ru.runa.wfe.var.UserType; +import ru.runa.wfe.var.VariableDefinition; +import ru.runa.wfe.var.VariableProvider; +import ru.runa.wfe.var.dto.WfVariable; +import ru.runa.wfe.var.format.ListFormat; +import ru.runa.wfe.var.format.VariableFormat; + +@CommonsLog +public class StoreHelper { + + private Map invocationMap = Maps.newHashMap(); + + StoreService storeService; + + DataBindings config; + + VariableFormat format; + + VariableProvider variableProvider; + + public StoreHelper(DataBindings config, VariableProvider variableProvider, StoreService storeService) { + setConfig(config); + this.variableProvider = variableProvider; + this.storeService = storeService; + } + + public UserType userType(WfVariable variable) throws InternalApplicationException { + final VariableDefinition definition = variable.getDefinition(); + if (definition.isUserType()) { + return definition.getUserType(); + } + + if (ListFormat.class.getName().equals(definition.getFormatClassName()) && definition.getFormatComponentUserTypes() != null + && definition.getFormatComponentUserTypes().length != 0) { + return definition.getFormatComponentUserTypes()[0]; + } + + throw new InternalApplicationException("Variable type" + definition.getFormat() + " not supported"); + } + + public void setVariableFormat(VariableFormat format) { + this.format = format; + } + + public ExecutionResult save(DataBinding binding, WfVariable variable) throws Exception { + storeService.save(extractProperties(binding), variable, true); + return ExecutionResult.EMPTY; + } + + public ExecutionResult findByFilter(DataBinding binding, UserType userType, String condition) throws Exception { + return storeService.findByFilter(extractProperties(binding), userType, condition); + } + + public ExecutionResult update(DataBinding binding, WfVariable variable, String condition) throws Exception { + storeService.update(extractProperties(binding), variable, condition); + return ExecutionResult.EMPTY; + } + + public ExecutionResult delete(DataBinding binding, UserType userType, String condition) throws Exception { + storeService.delete(extractProperties(binding), userType, condition); + return ExecutionResult.EMPTY; + } + + private Properties extractProperties(DataBinding binding) { + Properties properties = new Properties(); + properties.setProperty(StoreService.PROP_PATH, config.getInputFilePath()); + properties.put(StoreService.PROP_CONSTRAINTS, binding.getConstraints()); + properties.put(StoreService.PROP_FORMAT, format); + return properties; + } + + private void setConfig(DataBindings config) { + this.config = config; + } +} diff --git a/wfe-office/src/main/java/ru/runa/wfe/office/storage/services/StoreHelperImpl.java b/wfe-office/src/main/java/ru/runa/wfe/office/storage/services/StoreHelperImpl.java deleted file mode 100644 index d0318c5a7a..0000000000 --- a/wfe-office/src/main/java/ru/runa/wfe/office/storage/services/StoreHelperImpl.java +++ /dev/null @@ -1,119 +0,0 @@ -package ru.runa.wfe.office.storage.services; - -import com.google.common.base.Throwables; -import com.google.common.collect.Maps; -import java.lang.reflect.Method; -import java.util.Map; -import java.util.Properties; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import ru.runa.wfe.extension.handler.ParamDef; -import ru.runa.wfe.office.storage.StoreHelper; -import ru.runa.wfe.office.storage.StoreOperation; -import ru.runa.wfe.office.storage.StoreService; -import ru.runa.wfe.office.storage.binding.DataBinding; -import ru.runa.wfe.office.storage.binding.DataBindings; -import ru.runa.wfe.office.storage.binding.ExecutionResult; -import ru.runa.wfe.office.storage.binding.QueryType; -import ru.runa.wfe.var.VariableDefinition; -import ru.runa.wfe.var.VariableProvider; -import ru.runa.wfe.var.dto.WfVariable; -import ru.runa.wfe.var.format.ListFormat; -import ru.runa.wfe.var.format.VariableFormat; - -public class StoreHelperImpl implements StoreHelper { - - private static final Log log = LogFactory.getLog(StoreHelperImpl.class); - - private Map invocationMap = Maps.newHashMap(); - - StoreService storeService; - - DataBindings config; - - VariableFormat format; - - VariableProvider variableProvider; - - Map inputParams; - - public StoreHelperImpl(DataBindings config, VariableProvider variableProvider, StoreService storeService) { - setConfig(config); - registerHandlers(); - this.variableProvider = variableProvider; - this.storeService = storeService; - } - - private void setConfig(DataBindings config) { - this.config = config; - } - - @Override - public void setVariableFormat(VariableFormat format) { - this.format = format; - } - - @Override - public ExecutionResult execute(DataBinding binding, WfVariable variable) { - VariableDefinition vd = variable.getDefinition(); - if (!vd.isUserType() && (!vd.getFormatClassName().equals(ListFormat.class.getName()) || vd.getFormatComponentUserTypes() == null - || vd.getFormatComponentUserTypes().length == 0)) { - log.error("Variable type" + vd.getFormat() + " not supported."); - return ExecutionResult.EMPTY; - } - try { - Method method = invocationMap.get(config.getQueryType()); - return (ExecutionResult) method.invoke(this, binding, variable, config.getCondition()); - } catch (Exception e) { - throw Throwables.propagate(Throwables.getRootCause(e)); - } - } - - @StoreOperation(QueryType.INSERT) - public ExecutionResult save(DataBinding binding, WfVariable variable, String condition) throws Exception { - storeService.save(extractProperties(binding), variable, true); - return ExecutionResult.EMPTY; - } - - @StoreOperation(QueryType.SELECT) - public ExecutionResult findByFilter(DataBinding binding, WfVariable variable, String condition) throws Exception { - return storeService.findByFilter(extractProperties(binding), variable, condition); - } - - @StoreOperation(QueryType.UPDATE) - public ExecutionResult update(DataBinding binding, WfVariable variable, String condition) throws Exception { - storeService.update(extractProperties(binding), variable, condition); - return ExecutionResult.EMPTY; - } - - @StoreOperation(QueryType.DELETE) - public ExecutionResult delete(DataBinding binding, WfVariable variable, String condition) throws Exception { - storeService.delete(extractProperties(binding), variable, condition); - return ExecutionResult.EMPTY; - } - - private void registerHandlers() { - Method[] methods = this.getClass().getDeclaredMethods(); - for (Method method : methods) { - StoreOperation annotation = method.getAnnotation(StoreOperation.class); - if (annotation != null) { - Class[] parameters = method.getParameterTypes(); - if (parameters == null || parameters.length < 1) { - log.warn("wrong parameters"); - continue; - } - if (!invocationMap.containsKey(annotation.value())) { - invocationMap.put(annotation.value(), method); - } - } - } - } - - private Properties extractProperties(DataBinding binding) { - Properties properties = new Properties(); - properties.setProperty(StoreService.PROP_PATH, config.getInputFilePath()); - properties.put(StoreService.PROP_CONSTRAINTS, binding.getConstraints()); - properties.put(StoreService.PROP_FORMAT, format); - return properties; - } -} diff --git a/wfe-service/src/main/java/ru/runa/wfe/service/AuthorizationService.java b/wfe-service/src/main/java/ru/runa/wfe/service/AuthorizationService.java index 6176d4b7ea..eae7415a57 100644 --- a/wfe-service/src/main/java/ru/runa/wfe/service/AuthorizationService.java +++ b/wfe-service/src/main/java/ru/runa/wfe/service/AuthorizationService.java @@ -35,6 +35,7 @@ * @since 2.0 */ public interface AuthorizationService { + public Set filterAllowedIds(Executor executor, Permission permission, SecuredObjectType securedObjectType, List idsOrNull); void checkAllowed(User user, Permission permission, SecuredObject securedObject); diff --git a/wfe-service/src/main/java/ru/runa/wfe/service/TaskService.java b/wfe-service/src/main/java/ru/runa/wfe/service/TaskService.java index 19b1a219cc..371cd35a4b 100644 --- a/wfe-service/src/main/java/ru/runa/wfe/service/TaskService.java +++ b/wfe-service/src/main/java/ru/runa/wfe/service/TaskService.java @@ -169,4 +169,6 @@ void completeTask(User user, Long taskId, Map variables, Long sw */ List getUnassignedTasks(User user); + boolean isTaskDelegationEnabled(); + } \ No newline at end of file diff --git a/wfe-service/src/main/java/ru/runa/wfe/service/delegate/AuthorizationServiceDelegate.java b/wfe-service/src/main/java/ru/runa/wfe/service/delegate/AuthorizationServiceDelegate.java index b044fa7a7e..5563e2a125 100644 --- a/wfe-service/src/main/java/ru/runa/wfe/service/delegate/AuthorizationServiceDelegate.java +++ b/wfe-service/src/main/java/ru/runa/wfe/service/delegate/AuthorizationServiceDelegate.java @@ -216,4 +216,13 @@ public SecuredObject findSecuredObject(SecuredObjectType type, Long id) { throw handleException(e); } } + + @Override + public Set filterAllowedIds(Executor executor, Permission permission, SecuredObjectType securedObjectType, List idsOrNull) { + try{ + return getAuthorizationService().filterAllowedIds(executor, permission, securedObjectType, idsOrNull); + } catch (Exception e) { + throw handleException(e); + } + } } diff --git a/wfe-service/src/main/java/ru/runa/wfe/service/delegate/TaskServiceDelegate.java b/wfe-service/src/main/java/ru/runa/wfe/service/delegate/TaskServiceDelegate.java index 95d3babb71..6c4c984611 100644 --- a/wfe-service/src/main/java/ru/runa/wfe/service/delegate/TaskServiceDelegate.java +++ b/wfe-service/src/main/java/ru/runa/wfe/service/delegate/TaskServiceDelegate.java @@ -132,4 +132,13 @@ public List getUnassignedTasks(User user) { } } + @Override + public boolean isTaskDelegationEnabled() { + try { + return getTaskService().isTaskDelegationEnabled(); + } catch (Exception e) { + throw handleException(e); + } + } + } diff --git a/wfe-service/src/main/java/ru/runa/wfe/service/impl/AuthorizationServiceBean.java b/wfe-service/src/main/java/ru/runa/wfe/service/impl/AuthorizationServiceBean.java index 4fe14a497a..73816399d6 100644 --- a/wfe-service/src/main/java/ru/runa/wfe/service/impl/AuthorizationServiceBean.java +++ b/wfe-service/src/main/java/ru/runa/wfe/service/impl/AuthorizationServiceBean.java @@ -98,6 +98,12 @@ public boolean[] isAllowed(@NonNull User user, @NonNul Preconditions.checkArgument(!securedObjects.contains(null), "identifiables element"); return authorizationLogic.isAllowed(user, permission, securedObjects); } + + @WebMethod(exclude = true) + @Override + public Set filterAllowedIds(Executor executor, Permission permission, SecuredObjectType securedObjectType, List idsOrNull) { + return authorizationLogic.selectAllowedIds(executor, permission, securedObjectType, idsOrNull); + } @WebMethod(exclude = true) @Override diff --git a/wfe-service/src/main/java/ru/runa/wfe/service/impl/TaskServiceBean.java b/wfe-service/src/main/java/ru/runa/wfe/service/impl/TaskServiceBean.java index c2ead24db3..683a3126fb 100644 --- a/wfe-service/src/main/java/ru/runa/wfe/service/impl/TaskServiceBean.java +++ b/wfe-service/src/main/java/ru/runa/wfe/service/impl/TaskServiceBean.java @@ -150,4 +150,9 @@ public void delegateTasks(@NonNull User user, @NonNull Set taskIds, boolea public List getUnassignedTasks(@WebParam(name = "user") @NonNull User user) { return taskLogic.getUnassignedTasks(user); } + + @Override + public boolean isTaskDelegationEnabled() { + return taskLogic.isTaskDelegationEnabled(); + } } \ No newline at end of file diff --git a/wfe-web/src/main/java/ru/runa/af/web/form/UpdatePasswordForm.java b/wfe-web/src/main/java/ru/runa/af/web/form/UpdatePasswordForm.java index a8cc824284..4609adfa81 100644 --- a/wfe-web/src/main/java/ru/runa/af/web/form/UpdatePasswordForm.java +++ b/wfe-web/src/main/java/ru/runa/af/web/form/UpdatePasswordForm.java @@ -17,19 +17,16 @@ */ package ru.runa.af.web.form; +import com.google.common.base.Strings; import javax.servlet.http.HttpServletRequest; - import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; - import ru.runa.common.WebResources; import ru.runa.common.web.MessagesException; import ru.runa.common.web.form.IdForm; -import com.google.common.base.Strings; - /** * Created on 24.08.2004 * @@ -50,7 +47,7 @@ public class UpdatePasswordForm extends IdForm { public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = super.validate(mapping, request); if (Strings.isNullOrEmpty(password)) { - errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(MessagesException.ERROR_FILL_REQUIRED_VALUES.getKey())); + // ok, allow empty passwords } else if (password.length() > WebResources.VALIDATOR_STRING_255) { errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(MessagesException.ERROR_VALIDATION.getKey())); } else if (passwordConfirm == null || passwordConfirm.length() < 1) { @@ -70,7 +67,7 @@ public String getPasswordConfirm() { } public void setPassword(String string) { - password = string; + password = Strings.nullToEmpty(string).trim(); } public void setPasswordConfirm(String string) { diff --git a/wfe-web/src/main/java/ru/runa/af/web/html/DataSourceTableBuilder.java b/wfe-web/src/main/java/ru/runa/af/web/html/DataSourceTableBuilder.java index 1a6f2bfbf7..28082d0f11 100644 --- a/wfe-web/src/main/java/ru/runa/af/web/html/DataSourceTableBuilder.java +++ b/wfe-web/src/main/java/ru/runa/af/web/html/DataSourceTableBuilder.java @@ -36,6 +36,7 @@ import ru.runa.wfe.commons.web.PortletUrlType; import ru.runa.wfe.datasource.DataSource; import ru.runa.wfe.datasource.DataSourceStorage; +import ru.runa.wfe.datasource.DataSourceStuff; import ru.runa.wfe.datasource.DataSourceType; import ru.runa.wfe.datasource.ExcelDataSource; import ru.runa.wfe.datasource.JdbcDataSource; @@ -55,7 +56,9 @@ public Table build() { table.setWidth("100%"); table.addElement(createTableHeaderTR()); for (DataSource ds : DataSourceStorage.getAllDataSources()) { - table.addElement(createTR(ds)); + if (!DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME.equals(ds.getName())) { + table.addElement(createTR(ds)); + } } return table; } diff --git a/wfe-web/src/main/java/ru/runa/af/web/html/PasswordTableBuilder.java b/wfe-web/src/main/java/ru/runa/af/web/html/PasswordTableBuilder.java index 3a80f65ec1..b424e93988 100644 --- a/wfe-web/src/main/java/ru/runa/af/web/html/PasswordTableBuilder.java +++ b/wfe-web/src/main/java/ru/runa/af/web/html/PasswordTableBuilder.java @@ -38,9 +38,9 @@ public PasswordTableBuilder(boolean disabled, PageContext pageContext) { public Table build() { Table table = new Table(); table.setClass(ru.runa.common.web.Resources.CLASS_LIST_TABLE); - Input passwordInput = HTMLUtils.createInput(Input.PASSWORD, UpdatePasswordForm.PASSWORD_INPUT_NAME, "", enabled, true); + Input passwordInput = HTMLUtils.createInput(Input.PASSWORD, UpdatePasswordForm.PASSWORD_INPUT_NAME, "", enabled, false); table.addElement(HTMLUtils.createRow(MessagesCommon.PASSWORD.message(pageContext), passwordInput)); - Input passwordConfirmInput = HTMLUtils.createInput(Input.PASSWORD, UpdatePasswordForm.PASSWORD_CONFIRM_INPUT_NAME, "", enabled, true); + Input passwordConfirmInput = HTMLUtils.createInput(Input.PASSWORD, UpdatePasswordForm.PASSWORD_CONFIRM_INPUT_NAME, "", enabled, false); table.addElement(HTMLUtils.createRow(MessagesCommon.PASSWORD_CONFIRM.message(pageContext), passwordConfirmInput)); return table; } diff --git a/wfe-web/src/main/java/ru/runa/af/web/tag/DeployDataSourceTag.java b/wfe-web/src/main/java/ru/runa/af/web/tag/DeployDataSourceTag.java index 1e6bb98e49..34d449c712 100644 --- a/wfe-web/src/main/java/ru/runa/af/web/tag/DeployDataSourceTag.java +++ b/wfe-web/src/main/java/ru/runa/af/web/tag/DeployDataSourceTag.java @@ -28,6 +28,8 @@ import ru.runa.common.web.tag.TitledFormTag; import ru.runa.wf.web.MessagesDataSource; import ru.runa.wfe.security.AuthorizationException; +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.EMPTY, name = "deployDataSource") @@ -37,7 +39,7 @@ public class DeployDataSourceTag extends TitledFormTag { @Override protected boolean isSubmitButtonEnabled() { - return Delegates.getExecutorService().isAdministrator(getUser()); + return Delegates.getExecutorService().isAdministrator(getUser()) && Delegates.getAuthorizationService().isAllowed(getUser(), Permission.UPDATE, SecuredSingleton.DATASOURCES); } @Override diff --git a/wfe-web/src/main/java/ru/runa/af/web/tag/ListRelationPairsFormTag.java b/wfe-web/src/main/java/ru/runa/af/web/tag/ListRelationPairsFormTag.java index 79a91e8d99..c648379218 100644 --- a/wfe-web/src/main/java/ru/runa/af/web/tag/ListRelationPairsFormTag.java +++ b/wfe-web/src/main/java/ru/runa/af/web/tag/ListRelationPairsFormTag.java @@ -28,6 +28,7 @@ import ru.runa.common.WebResources; import ru.runa.common.web.MessagesCommon; import ru.runa.common.web.form.IdForm; +import ru.runa.common.web.html.BaseTdBuilder; import ru.runa.common.web.html.CheckboxTdBuilder; import ru.runa.common.web.html.HeaderBuilder; import ru.runa.common.web.html.ReflectionRowBuilder; @@ -46,6 +47,16 @@ @org.tldgen.annotations.Tag(bodyContent = BodyContent.JSP, name = "listRelationPairsForm") public class ListRelationPairsFormTag extends BatchReturningTitledFormTag { + @Override + protected boolean isSubmitButtonEnabled() { + return Delegates.getAuthorizationService().isAllowedForAny(getUser(), Permission.DELETE, SecuredObjectType.RELATION); + } + + @Override + protected boolean isSubmitButtonVisible() { + return Delegates.getAuthorizationService().isAllowedForAny(getUser(), Permission.DELETE, SecuredObjectType.RELATION); + } + private static final long serialVersionUID = 1L; private Long relationId; @@ -78,6 +89,11 @@ protected boolean isEnabled(Object object, Env env) { } }; TdBuilder[] builders = BatchPresentationUtils.getBuilders(new TdBuilder[] { checkboxBuilder }, batchPresentation, null); + for (TdBuilder td: builders) { + if (td instanceof BaseTdBuilder) { + ((BaseTdBuilder) td).setPermission(Permission.READ); + } + } RowBuilder rowBuilder = new ReflectionRowBuilder(relationPairs, batchPresentation, pageContext, WebResources.ACTION_MAPPING_UPDATE_EXECUTOR, getReturnAction(), IdForm.ID_INPUT_NAME, builders); HeaderBuilder headerBuilder = new SortingHeaderBuilder(batchPresentation, 1, 0, getReturnAction(), pageContext); diff --git a/wfe-web/src/main/java/ru/runa/af/web/tag/ListRelationsFormTag.java b/wfe-web/src/main/java/ru/runa/af/web/tag/ListRelationsFormTag.java index 8f9513c066..054729d8e0 100644 --- a/wfe-web/src/main/java/ru/runa/af/web/tag/ListRelationsFormTag.java +++ b/wfe-web/src/main/java/ru/runa/af/web/tag/ListRelationsFormTag.java @@ -18,6 +18,9 @@ package ru.runa.af.web.tag; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + import org.apache.ecs.html.TD; import org.tldgen.annotations.BodyContent; import ru.runa.af.web.BatchPresentationUtils; @@ -27,29 +30,48 @@ import ru.runa.common.WebResources; import ru.runa.common.web.Commons; import ru.runa.common.web.MessagesCommon; +import ru.runa.common.web.html.BaseTdBuilder; import ru.runa.common.web.html.CheckboxTdBuilder; import ru.runa.common.web.html.HeaderBuilder; import ru.runa.common.web.html.ItemUrlStrategy; +import ru.runa.common.web.html.PropertyTdBuilder; import ru.runa.common.web.html.ReflectionRowBuilder; import ru.runa.common.web.html.RowBuilder; import ru.runa.common.web.html.SortingHeaderBuilder; import ru.runa.common.web.html.TdBuilder; +import ru.runa.common.web.html.TdBuilder.Env; import ru.runa.common.web.html.TableBuilder; import ru.runa.common.web.tag.BatchReturningTitledFormTag; import ru.runa.wfe.commons.web.PortletUrlType; +import ru.runa.wfe.presentation.BatchPresentation; import ru.runa.wfe.relation.Relation; import ru.runa.wfe.security.Permission; +import ru.runa.wfe.security.SecuredObjectType; import ru.runa.wfe.security.SecuredSingleton; import ru.runa.wfe.service.delegate.Delegates; @org.tldgen.annotations.Tag(bodyContent = BodyContent.JSP, name = "listRelationsForm") public class ListRelationsFormTag extends BatchReturningTitledFormTag { + + @Override + protected boolean isSubmitButtonEnabled() { + return Delegates.getAuthorizationService().isAllowedForAny(getUser(), Permission.DELETE, SecuredObjectType.RELATION); + } + + @Override + protected boolean isSubmitButtonVisible() { + return Delegates.getAuthorizationService().isAllowedForAny(getUser(), Permission.DELETE, SecuredObjectType.RELATION); + } + private static final long serialVersionUID = 1L; @Override protected void fillFormElement(TD tdFormElement) { Delegates.getAuthorizationService().checkAllowed(getUser(), Permission.READ, SecuredSingleton.RELATIONS); List relations = Delegates.getRelationService().getRelations(getUser(), getBatchPresentation()); + Set allowedIds = Delegates.getAuthorizationService().filterAllowedIds(getUser().getActor(), Permission.READ, SecuredObjectType.RELATION, relations.stream().map( (r)-> r.getId() ).collect(Collectors.toList())); + relations.removeIf( (r) -> !allowedIds.contains(r.getId())); + TableBuilder tableBuilder = new TableBuilder(); TdBuilder checkboxBuilder = new CheckboxTdBuilder(null, null) { @@ -63,10 +85,16 @@ protected boolean isEnabled(Object object, Env env) { return true; } }; - TdBuilder[] builders = BatchPresentationUtils.getBuilders(new TdBuilder[] { checkboxBuilder }, getBatchPresentation(), null); - RowBuilder rowBuilder = new ReflectionRowBuilder(relations, getBatchPresentation(), pageContext, WebResources.ACTION_MAPPING_MANAGE_RELATION, + BatchPresentation batchPresentation = getBatchPresentation(); + TdBuilder[] builders = BatchPresentationUtils.getBuilders(new TdBuilder[] { checkboxBuilder }, batchPresentation, null); + for (TdBuilder td: builders) { + if (td instanceof BaseTdBuilder) { + ((BaseTdBuilder) td).setPermission(Permission.READ); + } + } + RowBuilder rowBuilder = new ReflectionRowBuilder(relations, batchPresentation, pageContext, WebResources.ACTION_MAPPING_MANAGE_RELATION, getReturnAction(), new RelationURLStrategy(), builders); - HeaderBuilder headerBuilder = new SortingHeaderBuilder(getBatchPresentation(), 1, 0, getReturnAction(), pageContext); + HeaderBuilder headerBuilder = new SortingHeaderBuilder(batchPresentation, 1, 0, getReturnAction(), pageContext); tdFormElement.addElement(tableBuilder.build(headerBuilder, rowBuilder)); } diff --git a/wfe-web/src/main/java/ru/runa/common/WebResources.java b/wfe-web/src/main/java/ru/runa/common/WebResources.java index 5c1682475b..f90e5de0f5 100644 --- a/wfe-web/src/main/java/ru/runa/common/WebResources.java +++ b/wfe-web/src/main/java/ru/runa/common/WebResources.java @@ -26,6 +26,7 @@ import ru.runa.wfe.commons.ClassLoaderUtil; import ru.runa.wfe.commons.PropertyResources; import ru.runa.wfe.commons.SystemProperties; +import ru.runa.wfe.service.delegate.Delegates; /** * Created on 30.09.2004 @@ -85,7 +86,7 @@ public static boolean useImagesForValidationErrors() { * Used from JSP page */ public static boolean isTaskDelegationEnabled() { - return RESOURCES.getBooleanProperty("task.delegation.enabled", true); + return Delegates.getTaskService().isTaskDelegationEnabled(); } /** diff --git a/wfe-web/src/main/java/ru/runa/common/web/MessagesCommon.java b/wfe-web/src/main/java/ru/runa/common/web/MessagesCommon.java index 56490d48d3..2cd4639a1f 100644 --- a/wfe-web/src/main/java/ru/runa/common/web/MessagesCommon.java +++ b/wfe-web/src/main/java/ru/runa/common/web/MessagesCommon.java @@ -27,10 +27,9 @@ public final class MessagesCommon { public static final StrutsMessage MAIN_MENU_ITEM_SETTINGS = new StrutsMessage("manage_settings"); // Forward menu (left main menu items) -> Logs. public static final StrutsMessage MAIN_MENU_ITEM_LOGS = new StrutsMessage("view_logs"); - + // Forward menu (left main menu items) -> Internal storage. + public static final StrutsMessage MAIN_MENU_ITEM_INTERNAL_STORAGE = new StrutsMessage("view_internal_storage"); public static final StrutsMessage MAIN_MENU_ITEM_CHATS = new StrutsMessage("swich_chats"); - - // Common buttons diff --git a/wfe-web/src/main/java/ru/runa/common/web/action/ViewInternalStorageAction.java b/wfe-web/src/main/java/ru/runa/common/web/action/ViewInternalStorageAction.java new file mode 100644 index 0000000000..daaa5ed751 --- /dev/null +++ b/wfe-web/src/main/java/ru/runa/common/web/action/ViewInternalStorageAction.java @@ -0,0 +1,142 @@ +package ru.runa.common.web.action; + +import com.google.common.base.Strings; +import com.google.common.io.Files; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.commons.io.FilenameUtils; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import ru.runa.common.web.HTMLUtils; +import ru.runa.common.web.Resources; +import ru.runa.common.web.form.ViewInternalStorageForm; +import ru.runa.wfe.datasource.DataSource; +import ru.runa.wfe.datasource.DataSourceStorage; +import ru.runa.wfe.datasource.DataSourceStuff; +import ru.runa.wfe.datasource.ExcelDataSource; + +/** + * @struts:action path="/viewInternalStorage" name="viewInternalStorageForm" validate="false" + * @struts.action-forward name="success" path="/displayInternalStorage.do" redirect = "false" + */ +public class ViewInternalStorageAction extends ActionBase { + + public static final String ACTION_PATH = "/viewInternalStorage"; + + @Override + public ActionForward execute(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) { + try { + ViewInternalStorageForm form = (ViewInternalStorageForm) actionForm; + String workbookPath = null; + DataSource ds = DataSourceStorage.getDataSource(DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME); + if (ds instanceof ExcelDataSource) { + ExcelDataSource eds = (ExcelDataSource) ds; + workbookPath = eds.getFilePath(); + request.setAttribute("workbookPath", workbookPath); + if (form.getMode() == ViewInternalStorageForm.MODE_DOWNLOAD) { + String encodedFileName = HTMLUtils.encodeFileName(request, form.getWorkbookName()); + response.setHeader("Content-disposition", "attachment; filename=\"" + encodedFileName + "\""); + OutputStream os = response.getOutputStream(); + Files.copy(new File(form.getWorkbookPath() + "/" + form.getWorkbookName()), os); + os.flush(); + return null; + } + } + form.setWorkbookPath(workbookPath); + String workbookName = form.getWorkbookName(); + if (!Strings.isNullOrEmpty(workbookPath) && !Strings.isNullOrEmpty(workbookName)) { + try (InputStream is = new FileInputStream(workbookPath + "/" + workbookName)) { + Workbook wb; + if (workbookName.endsWith(".xls")) { + wb = new HSSFWorkbook(is); + } else if (workbookName.endsWith(".xlsx")) { + wb = new XSSFWorkbook(is); + } else { + throw new IllegalArgumentException("excel file extension is incorrect"); + } + Sheet sheet = wb.getSheet(FilenameUtils.removeExtension(workbookName)); + List> data = new ArrayList<>(); + int columnNumber = getSheetContent(sheet, data); + StringBuffer sheetContent = new StringBuffer(); + if (columnNumber > 0 && data.size() > 0) { + sheetContent.append(""); + for (List row : data) { + sheetContent.append(""); + for (Cell cell : row) { + sheetContent.append(""); + } + sheetContent.append(""); + } + sheetContent.append("
"); + sheetContent.append(cellValue(cell)); + sheetContent.append("
"); + } + request.setAttribute("workbookContent", sheetContent.toString()); + wb.close(); + } + } + return mapping.findForward(Resources.FORWARD_SUCCESS); + } catch (Exception e) { + addError(request, e); + return mapping.findForward(Resources.FORWARD_FAILURE); + } + } + + private Object cellValue(Cell cell) { + Object value; + switch (cell.getCellTypeEnum()) { + case STRING: + value = cell.getRichStringCellValue().getString(); + break; + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + value = cell.getDateCellValue(); + } else { + value = cell.getNumericCellValue(); + } + break; + case BOOLEAN: + value = cell.getBooleanCellValue(); + break; + case FORMULA: + value = cell.getCellFormula(); + break; + default: + value = cell.getStringCellValue(); + } + return value; + } + + private int getSheetContent(Sheet sheet, List> data) { + int columnNumber = 0; + for (int r = 0; r <= sheet.getLastRowNum(); r++) { + List cells = new ArrayList<>(); + Row row = sheet.getRow(r); + if (row == null) { + break; + } else { + for (int c = 0; c < row.getLastCellNum(); c++) { + cells.add(row.getCell(c)); + } + } + data.add(cells); + columnNumber = Math.max(columnNumber, cells.size()); + } + return columnNumber; + } + +} diff --git a/wfe-web/src/main/java/ru/runa/common/web/form/ViewInternalStorageForm.java b/wfe-web/src/main/java/ru/runa/common/web/form/ViewInternalStorageForm.java new file mode 100644 index 0000000000..6eb722e2da --- /dev/null +++ b/wfe-web/src/main/java/ru/runa/common/web/form/ViewInternalStorageForm.java @@ -0,0 +1,41 @@ +package ru.runa.common.web.form; + +import org.apache.struts.action.ActionForm; + +/** + * @struts:form name = "viewInternalStorageForm" + */ +public class ViewInternalStorageForm extends ActionForm { + private static final long serialVersionUID = 1L; + + public static final int MODE_DOWNLOAD = 5; + + private int mode; + private String workbookPath; + private String workbookName; + + public String getWorkbookPath() { + return workbookPath; + } + + public void setWorkbookPath(String workbookPath) { + this.workbookPath = workbookPath; + } + + public String getWorkbookName() { + return workbookName; + } + + public void setWorkbookName(String workbookName) { + this.workbookName = workbookName; + } + + public int getMode() { + return mode; + } + + public void setMode(int mode) { + this.mode = mode; + } + +} diff --git a/wfe-web/src/main/java/ru/runa/common/web/html/BaseTdBuilder.java b/wfe-web/src/main/java/ru/runa/common/web/html/BaseTdBuilder.java index 621fc979f2..8a46f19e0a 100644 --- a/wfe-web/src/main/java/ru/runa/common/web/html/BaseTdBuilder.java +++ b/wfe-web/src/main/java/ru/runa/common/web/html/BaseTdBuilder.java @@ -30,7 +30,7 @@ * @author Vitaliy S aka Yilativs */ public abstract class BaseTdBuilder implements TdBuilder { - private final Permission permission; + private Permission permission; private SecuredObjectExtractor securedObjectExtractor; public BaseTdBuilder(Permission permission) { @@ -47,13 +47,17 @@ public void setSecuredObjectExtractor(SecuredObjectExtractor securedObjectExtrac } protected boolean isEnabled(Object object, Env env) { - if (permission == null) { + return isEnabledFor(object, env, permission); + } + + protected boolean isEnabledFor(Object object, Env env, Permission perm) { + if (perm == null) { return false; } - if (permission == Permission.START_PROCESS) { + if (perm == Permission.START_PROCESS) { return ((WfDefinition) object).isCanBeStarted(); } - return env.isAllowed(permission, securedObjectExtractor); + return env.isAllowed(perm, securedObjectExtractor); } protected String readProperty(Object object, String propertyName, boolean isExceptionOnAbsent) { @@ -82,4 +86,13 @@ public String[] getSeparatedValues(Object object, Env env) { public int getSeparatedValuesCount(Object object, Env env) { return 1; } + + public Permission getPermission() { + return permission; + } + + public void setPermission(Permission permission) { + this.permission = permission; + } + } diff --git a/wfe-web/src/main/java/ru/runa/common/web/tag/ManagePermissionsLinkTag.java b/wfe-web/src/main/java/ru/runa/common/web/tag/ManagePermissionsLinkTag.java index 3e981e5f0a..b3d539f0bd 100644 --- a/wfe-web/src/main/java/ru/runa/common/web/tag/ManagePermissionsLinkTag.java +++ b/wfe-web/src/main/java/ru/runa/common/web/tag/ManagePermissionsLinkTag.java @@ -13,6 +13,7 @@ @org.tldgen.annotations.Tag(bodyContent = BodyContent.EMPTY, name = "managePermissionsLink") public class ManagePermissionsLinkTag extends BaseLinkTag { + private static final long serialVersionUID = 1L; private SecuredObjectType securedObjectType; @@ -43,6 +44,11 @@ protected boolean isLinkEnabled() { getUser(), Permission.READ_PERMISSIONS, securedObjectType, identifiableId != null ? identifiableId : 0 ); } + + @Override + protected boolean isVisible() { + return isLinkEnabled(); + } @Override protected String getLinkText() { diff --git a/wfe-web/src/main/java/ru/runa/common/web/tag/TabHeaderTag.java b/wfe-web/src/main/java/ru/runa/common/web/tag/TabHeaderTag.java index afecf82876..30b13c9f85 100644 --- a/wfe-web/src/main/java/ru/runa/common/web/tag/TabHeaderTag.java +++ b/wfe-web/src/main/java/ru/runa/common/web/tag/TabHeaderTag.java @@ -34,6 +34,9 @@ import ru.runa.common.web.StrutsMessage; import ru.runa.common.web.TabHttpSessionHelper; import ru.runa.wfe.commons.web.PortletUrlType; +import ru.runa.wfe.datasource.DataSourceStorage; +import ru.runa.wfe.datasource.DataSourceStuff; +import ru.runa.wfe.datasource.ExcelDataSource; import ru.runa.wfe.security.Permission; import ru.runa.wfe.security.SecuredObject; import ru.runa.wfe.security.SecuredObjectType; @@ -62,7 +65,8 @@ public class TabHeaderTag extends TagSupport { FORWARDS.add(new MenuForward(MessagesCommon.MAIN_MENU_ITEM_REPORTS, SecuredSingleton.REPORTS)); FORWARDS.add(new MenuForward(MessagesCommon.MAIN_MENU_ITEM_RELATIONS, SecuredSingleton.RELATIONS)); FORWARDS.add(new MenuForward(MessagesCommon.MAIN_MENU_ITEM_BOT_STATION, SecuredSingleton.BOTSTATIONS)); - FORWARDS.add(new MenuForward(MessagesCommon.MAIN_MENU_ITEM_DATA_SOURCES, null, true)); + FORWARDS.add(new MenuForward(MessagesCommon.MAIN_MENU_ITEM_DATA_SOURCES, SecuredSingleton.DATASOURCES)); + FORWARDS.add(new MenuForward(MessagesCommon.MAIN_MENU_ITEM_INTERNAL_STORAGE, null, true)); FORWARDS.add(new MenuForward(MessagesCommon.MAIN_MENU_ITEM_SYSTEM, SecuredSingleton.SYSTEM)); FORWARDS.add(new MenuForward(MessagesCommon.MAIN_MENU_ITEM_SETTINGS, null, true)); FORWARDS.add(new MenuForward(MessagesCommon.MAIN_MENU_ITEM_LOGS)); @@ -135,6 +139,13 @@ private User getUser() { private boolean isMenuForwardVisible(MenuForward menuForward) { try { if (menuForward.forAdministratorOnly) { + if (menuForward.menuMessage.getKey().equals(MessagesCommon.MAIN_MENU_ITEM_INTERNAL_STORAGE.getKey())) { + if (DataSourceStorage.getNames().contains(DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME)) { + if (!(DataSourceStorage.getDataSource(DataSourceStuff.INTERNAL_STORAGE_DATA_SOURCE_NAME) instanceof ExcelDataSource)) { + return false; + } + } + } return Delegates.getExecutorService().isAdministrator(getUser()); } if (menuForward.menuMessage.getKey().equals("swich_chats")) { diff --git a/wfe-web/src/main/java/ru/runa/common/web/tag/ViewWorkbooksTag.java b/wfe-web/src/main/java/ru/runa/common/web/tag/ViewWorkbooksTag.java new file mode 100644 index 0000000000..2976b89a17 --- /dev/null +++ b/wfe-web/src/main/java/ru/runa/common/web/tag/ViewWorkbooksTag.java @@ -0,0 +1,65 @@ +package ru.runa.common.web.tag; + +import com.google.common.base.Throwables; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.jsp.tagext.Tag; +import javax.servlet.jsp.tagext.TagSupport; +import org.apache.commons.io.FilenameUtils; +import org.tldgen.annotations.Attribute; +import org.tldgen.annotations.BodyContent; +import ru.runa.common.web.Commons; +import ru.runa.common.web.action.ViewInternalStorageAction; +import ru.runa.wfe.commons.web.PortletUrlType; +import ru.runa.wfe.security.AuthorizationException; +import ru.runa.wfe.service.delegate.Delegates; +import ru.runa.wfe.user.User; + +@org.tldgen.annotations.Tag(bodyContent = BodyContent.EMPTY, name = "viewWorkbooks") +public class ViewWorkbooksTag extends TagSupport { + private static final long serialVersionUID = 1L; + private String workbookPath; + + public String getworkbookPath() { + return workbookPath; + } + + @Attribute(required = true) + public void setworkbookPath(String workbookPath) { + this.workbookPath = workbookPath; + } + + @Override + public int doStartTag() { + if (!Delegates.getExecutorService().isAdministrator(getUser())) { + throw new AuthorizationException("No permission on this page"); + } + try { + StringBuilder html = new StringBuilder(); + File internalStorage = new File(workbookPath); + if (internalStorage.exists() && internalStorage.isDirectory()) { + String[] workbookNameList = internalStorage.list((dir, name) -> { + return name.endsWith(".xls") || name.endsWith(".xlsx"); + }); + for (int i = 0; i < workbookNameList.length; i++) { + Map params = new HashMap<>(); + params.put("workbookName", workbookNameList[i]); + String href = Commons.getActionUrl(ViewInternalStorageAction.ACTION_PATH, params, pageContext, PortletUrlType.Action); + html.append("").append(FilenameUtils.removeExtension(workbookNameList[i])) + .append("   "); + } + } + pageContext.getOut().write(html.toString()); + return Tag.SKIP_BODY; + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + private User getUser() { + return Commons.getUser(pageContext.getSession()); + } + +} diff --git a/wfe-web/src/main/java/ru/runa/report/web/html/ReportPropertiesTdBuilder.java b/wfe-web/src/main/java/ru/runa/report/web/html/ReportPropertiesTdBuilder.java index f4dcbacbe6..598604f5ff 100644 --- a/wfe-web/src/main/java/ru/runa/report/web/html/ReportPropertiesTdBuilder.java +++ b/wfe-web/src/main/java/ru/runa/report/web/html/ReportPropertiesTdBuilder.java @@ -21,7 +21,6 @@ import org.apache.ecs.StringElement; import org.apache.ecs.html.A; import org.apache.ecs.html.TD; - import ru.runa.common.WebResources; import ru.runa.common.web.Commons; import ru.runa.common.web.MessagesCommon; @@ -45,7 +44,7 @@ public TD build(Object object, Env env) { WfReport report = (WfReport) object; ConcreteElement startLink; - if (isEnabled(object, env)) { + if (isEnabledFor(object, env, Permission.UPDATE)) { String url = Commons.getActionUrl(WebResources.ACTION_MAPPING_MANAGE_REPORT, IdForm.ID_INPUT_NAME, report.getId(), env.getPageContext(), PortletUrlType.Render); startLink = new A(url, MessagesCommon.LABEL_PROPERTIES.message(env.getPageContext())); diff --git a/wfe-web/src/main/java/ru/runa/wf/web/tag/ProcessInfoFormTag.java b/wfe-web/src/main/java/ru/runa/wf/web/tag/ProcessInfoFormTag.java index 76ba069b70..e1570c06b6 100644 --- a/wfe-web/src/main/java/ru/runa/wf/web/tag/ProcessInfoFormTag.java +++ b/wfe-web/src/main/java/ru/runa/wf/web/tag/ProcessInfoFormTag.java @@ -59,6 +59,7 @@ import ru.runa.wfe.execution.dto.WfProcess; import ru.runa.wfe.security.Permission; import ru.runa.wfe.security.SecuredObject; +import ru.runa.wfe.security.SecuredObjectType; import ru.runa.wfe.service.delegate.Delegates; @org.tldgen.annotations.Tag(bodyContent = BodyContent.JSP, name = "processInfoForm") @@ -246,6 +247,9 @@ private Element addUpgradeLinkIfRequired(WfProcess process, Element versionEleme if (!SystemProperties.isUpgradeProcessToDefinitionVersionEnabled()) { return versionElement; } + if (! Delegates.getAuthorizationService().isAllowed(this.getUser(), Permission.UPDATE, SecuredObjectType.PROCESS, process.getId() )) { + return versionElement; + } Div div = new Div(); div.addElement(versionElement); div.addElement(Entities.NBSP); diff --git a/wfe-web/src/main/java/ru/runa/wf/web/tag/TaskFormDelegationTag.java b/wfe-web/src/main/java/ru/runa/wf/web/tag/TaskFormDelegationTag.java index 806794ebf6..4bbf970f20 100644 --- a/wfe-web/src/main/java/ru/runa/wf/web/tag/TaskFormDelegationTag.java +++ b/wfe-web/src/main/java/ru/runa/wf/web/tag/TaskFormDelegationTag.java @@ -14,6 +14,8 @@ import ru.runa.common.web.Commons; import ru.runa.common.web.tag.VisibleTag; import ru.runa.wf.web.MessagesProcesses; +import ru.runa.wfe.security.Permission; +import ru.runa.wfe.security.SecuredObjectType; import ru.runa.wfe.service.ExecutorService; import ru.runa.wfe.service.delegate.Delegates; import ru.runa.wfe.service.delegate.ExecutorServiceDelegate; @@ -25,6 +27,11 @@ */ @org.tldgen.annotations.Tag(bodyContent = BodyContent.EMPTY, name = "taskFormDelegationButton") public class TaskFormDelegationTag extends VisibleTag { + @Override + protected boolean isVisible() { + return Delegates.getAuthorizationService().isAllowedForAny(getUser(), Permission.DELEGATE_TASKS, SecuredObjectType.EXECUTOR); + } + private static final long serialVersionUID = 1L; private Long taskId; diff --git a/wfe-web/src/main/resources/settingsList.xml b/wfe-web/src/main/resources/settingsList.xml index f0ffb9ed67..0477a2df0e 100644 --- a/wfe-web/src/main/resources/settingsList.xml +++ b/wfe-web/src/main/resources/settingsList.xml @@ -9,6 +9,10 @@ + + true + false + @@ -176,11 +180,7 @@ true false - - - true - false - + true false @@ -268,4 +268,47 @@ + + + + true + false + + + true + false + + + true + false + + + true + false + + + true + false + + + true + false + + + true + false + + + true + false + + + true + false + + + true + false + + diff --git a/wfe-web/src/main/resources/web.properties b/wfe-web/src/main/resources/web.properties index ab1a003407..ff154cb58a 100644 --- a/wfe-web/src/main/resources/web.properties +++ b/wfe-web/src/main/resources/web.properties @@ -10,7 +10,7 @@ task.form.builder.ftl=ru.runa.wf.web.ftl.FtlFormBuilder task.form.builder.html=ru.runa.wf.web.customtag.HtmlFormBuilder task.form.builder.quick=ru.runa.wf.web.quick.QuickFormBuilder task.form.ajaxFileInputEnabled=true -task.delegation.enabled=true + # Settings for log viewer view.logs.limit.lines.count=10000 view.logs.timeout.autoreload.seconds=15 diff --git a/wfe-web/src/main/webapp/WEB-INF/classes/settingsDescriptions.properties b/wfe-web/src/main/webapp/WEB-INF/classes/settingsDescriptions.properties index 5c8a535b92..afff7f8798 100644 --- a/wfe-web/src/main/webapp/WEB-INF/classes/settingsDescriptions.properties +++ b/wfe-web/src/main/webapp/WEB-INF/classes/settingsDescriptions.properties @@ -6,6 +6,7 @@ system.properties_escalation.default.hierarchy.loader = Organization function or system.properties_escalation.default.orgFunction = system.properties_task.default.deadline = If task deadline is not set in process definition (in Developer Studio) then this value is used system.properties_task.almostDeadlinePercents = For task highlighting tasks in tasklist only +system.properties_task.delegation.enabled = Task delegation enabled system.properties_authentication.domain.name = system.properties_date.format.pattern = system.properties_scriptingServiceAPI.executeGroovyScript.enabled = Whether execution of ru.runa.wfe.service.ScriptingService.executeGroovyScript(User, String) enabled @@ -54,7 +55,6 @@ web.properties_confirmation.execute.task = web.properties_confirmation.start.process = web.properties_confirmation.start.process.noform = web.properties_confirmation.use.default.properties = Require confirmation to load default settings -web.properties_task.delegation.enabled = Task delegation enabled web.properties_process.swimlane.assignment.enabled = Allow swimlanes update web.properties_process.variable.assignment.enabled = Allow variables update web.properties_process.task.filters.enabled = Started processes view contains task filters @@ -110,3 +110,15 @@ botstation.properties_botstations.autostart.enabled = start all bot stations on botstation.properties_botstation.invocation.handler.timeout.milliseconds = delay before task creation and bot station invocation botstation.properties_botstation.failedExecutionInitialDelaySeconds = initial value of delay after failed execution of bot's task (next will be 2*n) (in seconds) botstation.properties_botstation.failedExecutionMaxDelaySeconds = limit of delay after failed execution of bot's task (in seconds) + +securitycheck.properties = Permission check settings +securitycheck.properties_permission.check.required.EXECUTOR = Check actors +securitycheck.properties_permission.check.required.DEFINITION = Check process definitions +securitycheck.properties_permission.check.required.PROCESS = Check process instances +securitycheck.properties_permission.check.required.REPORTS = Check reports +securitycheck.properties_permission.check.required.REPORT = Check report +securitycheck.properties_permission.check.required.RELATIONS = Check relations +securitycheck.properties_permission.check.required.RELATION = Check relation +securitycheck.properties_permission.check.required.BOTSTATIONS = Check bot stations +securitycheck.properties_permission.check.required.SYSTEM = Check system +securitycheck.properties_permission.check.required.DATASOURCES = Check datasources \ No newline at end of file diff --git a/wfe-web/src/main/webapp/WEB-INF/classes/settingsDescriptions_ru.properties b/wfe-web/src/main/webapp/WEB-INF/classes/settingsDescriptions_ru.properties index fe4f2b9b6d..5ece6def3a 100644 --- a/wfe-web/src/main/webapp/WEB-INF/classes/settingsDescriptions_ru.properties +++ b/wfe-web/src/main/webapp/WEB-INF/classes/settingsDescriptions_ru.properties @@ -6,6 +6,7 @@ system.properties_escalation.default.hierarchy.loader = \u041e\u0440\u0433. \u04 system.properties_escalation.default.orgFunction = system.properties_task.default.deadline = \u0412\u0440\u0435\u043c\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e (\u0435\u0441\u043b\u0438 \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u044f\u0432\u043d\u043e \u0432 \u0421\u0440\u0435\u0434\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438) system.properties_task.almostDeadlinePercents = \u041f\u0440\u043e\u0446\u0435\u043d\u0442 \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0446\u0432\u0435\u0442 \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u043d\u044b\u0439 +system.properties_task.delegation.enabled = \u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 system.properties_authentication.domain.name = \u0418\u043c\u044f \u0434\u043e\u043c\u0435\u043d\u0430 system.properties_date.format.pattern = \u0424\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u0442\u044b \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 (\u0442\u0430\u043a\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u0430\u0442\u044b \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c) system.properties_scriptingServiceAPI.executeGroovyScript.enabled = \u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 ru.runa.wfe.service.ScriptingService.executeGroovyScript(User, String @@ -54,7 +55,6 @@ web.properties_confirmation.execute.task = \u0417\u0430\u043f\u0440\u0430\u0448\ web.properties_confirmation.start.process = \u0417\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 web.properties_confirmation.start.process.noform = \u0417\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0431\u0435\u0437 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u0444\u043e\u0440\u043c\u044b web.properties_confirmation.use.default.properties = \u0417\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u0441\u0431\u0440\u043e\u0441\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e -web.properties_task.delegation.enabled = \u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 web.properties_process.swimlane.assignment.enabled = \u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044f \u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 web.properties_process.variable.assignment.enabled = \u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 web.properties_process.task.filters.enabled = \u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u043f\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c \u0437\u0430\u0434\u0430\u0447 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432 @@ -110,3 +110,16 @@ botstation.properties_botstations.autostart.enabled = \u0430\u0432\u0442\u043e\u botstation.properties_botstation.invocation.handler.timeout.milliseconds = \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0431\u043e\u0442-\u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0437\u0430\u0434\u0430\u043d\u0438\u044f, \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0435\u043c\u043e\u0433\u043e \u0431\u043e\u0442\u0443, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0441\u043e\u0437\u0434\u0430\u0432\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 botstation.properties_botstation.failedExecutionInitialDelaySeconds = \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 \u0431\u043e\u0442\u0430 (\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u0443\u0434\u0432\u043e\u0438\u0442\u0441\u044f) (\u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0430\u0445) botstation.properties_botstation.failedExecutionMaxDelaySeconds = \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 \u0431\u043e\u0442\u0430 (\u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0430\u0445) + +securitycheck.properties=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u043F\u0440\u0430\u0432 \u0434\u043E\u0441\u0442\u0443\u043F\u0430 + +securitycheck.properties_permission.check.required.EXECUTOR=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A \u0438\u0441\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044F\u043C +securitycheck.properties_permission.check.required.DEFINITION=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u044F\u043C \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0430 +securitycheck.properties_permission.check.required.PROCESS=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A \u044D\u043A\u0437\u0435\u043C\u043F\u043B\u044F\u0440\u0430\u043C \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0430 +securitycheck.properties_permission.check.required.REPORT=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A \u043E\u0442\u0447\u0451\u0442\u0443 +securitycheck.properties_permission.check.required.REPORTS=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A \u043E\u0442\u0447\u0451\u0442\u0430\u043C +securitycheck.properties_permission.check.required.RELATIONS=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u044F\u043C +securitycheck.properties_permission.check.required.RELATION=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u044E +securitycheck.properties_permission.check.required.BOTSTATIONS=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A \u0431\u043E\u0442-\u0441\u0442\u0430\u043D\u0446\u0438\u044F\u043C +securitycheck.properties_permission.check.required.SYSTEM=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u043A \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F\u043C \u0441 \u0441\u0438\u0441\u0442\u0435\u043C\u043E\u0439 +securitycheck.properties_permission.check.required.DATASOURCES=\u041F\u0440\u0438\u043C\u0435\u043D\u044F\u0442\u044C \u0434\u043B\u044F \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u043E\u0432 \u0434\u0430\u043D\u043D\u044B\u0445 \ No newline at end of file diff --git a/wfe-web/src/main/webapp/WEB-INF/classes/struts.properties b/wfe-web/src/main/webapp/WEB-INF/classes/struts.properties index 09c839a0f5..2c1c0b8b7b 100644 --- a/wfe-web/src/main/webapp/WEB-INF/classes/struts.properties +++ b/wfe-web/src/main/webapp/WEB-INF/classes/struts.properties @@ -468,6 +468,7 @@ permission.UPDATE = Update permission.UPDATE_ACTOR_STATUS = Update status permission.UPDATE_PERMISSIONS = Update permissions permission.VIEW_TASKS = View tasks +permission.DELEGATE_TASKS = Delegate tasks process.canceled = Process has been stopped process.does.not.exist.error = Process "{0}" does not exist @@ -705,4 +706,6 @@ label.routing_parameter_name = Route parameter name label.routing_parameter_value = Route parameter value label.payload_parameter_name = Payload parameter name label.payload_parameter_value = Payload parameter value -signal.message_is_sent = Signal has been sent \ No newline at end of file +signal.message_is_sent = Signal has been sent + +view_internal_storage = Internal storage diff --git a/wfe-web/src/main/webapp/WEB-INF/classes/struts_ru.properties b/wfe-web/src/main/webapp/WEB-INF/classes/struts_ru.properties index 0a2dabda8e..727dfe76a2 100644 --- a/wfe-web/src/main/webapp/WEB-INF/classes/struts_ru.properties +++ b/wfe-web/src/main/webapp/WEB-INF/classes/struts_ru.properties @@ -466,6 +466,7 @@ permission.UPDATE = \u0418\u0437\u043c\u0435\u043d\u044f\u0442\u044c permission.UPDATE_ACTOR_STATUS = \u0418\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441 permission.UPDATE_PERMISSIONS = \u0418\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u043c\u043e\u0447\u0438\u044f permission.VIEW_TASKS = \u0412\u0438\u0434\u0435\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 +permission.DELEGATE_TASKS = \u0414\u0435\u043B\u0435\u0433\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438 process.canceled = \u042d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d process.does.not.exist.error = \u042d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 "{0}" \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 @@ -702,3 +703,5 @@ label.routing_parameter_value = \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 label.payload_parameter_name = \u0418\u043c\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 label.payload_parameter_value = \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 signal.message_is_sent = \u0421\u0438\u0433\u043d\u0430\u043b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d + +view_internal_storage = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 diff --git a/wfe-web/src/main/webapp/WEB-INF/common/internal_storage.jsp b/wfe-web/src/main/webapp/WEB-INF/common/internal_storage.jsp new file mode 100644 index 0000000000..1e3a6e5c44 --- /dev/null +++ b/wfe-web/src/main/webapp/WEB-INF/common/internal_storage.jsp @@ -0,0 +1,56 @@ +<%@ page language="java" pageEncoding="UTF-8" %> +<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles"%> +<%@ taglib uri="/WEB-INF/wf.tld" prefix="wf" %> +<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%> +<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%> + + + +<% + String workbookPath = (String) request.getAttribute("workbookPath"); + String workbookName = (String) request.getAttribute("workbookName"); + String workbookContent = (String) request.getAttribute("workbookContent"); +%> + + + + + + + <%= workbookPath %>
+ + <% if (workbookContent != null) { %> + + + + +
+ +
+
+ <%= workbookContent %> + <% } %> +
+ + + +
diff --git a/wfe-web/src/main/webapp/WEB-INF/struts-config.xml b/wfe-web/src/main/webapp/WEB-INF/struts-config.xml index 93e248b995..0b75f258e7 100644 --- a/wfe-web/src/main/webapp/WEB-INF/struts-config.xml +++ b/wfe-web/src/main/webapp/WEB-INF/struts-config.xml @@ -46,6 +46,7 @@ + @@ -95,6 +96,7 @@ + @@ -370,6 +372,11 @@ + + + + @@ -800,6 +807,9 @@ + + - - + + +