From 04efef80ae5873b241f38d13ed12409bc9cd80c4 Mon Sep 17 00:00:00 2001 From: Aleksandr Skoblikov Date: Mon, 12 Sep 2022 17:58:14 +0300 Subject: [PATCH] CB-2406 rm project permissions api --- .../io.cloudbeaver.model/META-INF/MANIFEST.MF | 1 + .../cloudbeaver/model/WebConnectionInfo.java | 2 +- .../io/cloudbeaver/model/WebProjectInfo.java | 24 +++++-- .../src/io/cloudbeaver/model/rm/RMUtils.java | 2 +- .../rm/local/LocalResourceController.java | 11 ++-- .../cloudbeaver/model/session/WebSession.java | 2 +- .../service/admin/AdminPermissionInfo.java | 0 .../cloudbeaver/service/security/SMUtils.java | 36 +++++++++++ .../schema/service.core.graphqls | 6 +- .../service/core/DBWServiceCore.java | 16 ++--- .../navigator/WebNavigatorNodeInfo.java | 3 +- .../navigator/impl/WebServiceNavigator.java | 2 +- .../schema/service.admin.graphqls | 11 ++++ .../service/admin/impl/WebServiceAdmin.java | 13 +--- .../io.cloudbeaver.service.rm/plugin.xml | 13 ++-- .../schema/service.rm.graphqls | 15 ++++- .../cloudbeaver/service/rm/DBWServiceRM.java | 32 +++++++++- .../service/rm/WebServiceBindingRM.java | 11 ++++ .../service/rm/impl/WebServiceRM.java | 62 ++++++++++++++++++- .../rm/model/RMSubjectProjectPermissions.java | 22 +++++++ 20 files changed, 237 insertions(+), 47 deletions(-) rename server/bundles/{io.cloudbeaver.service.admin => io.cloudbeaver.model}/src/io/cloudbeaver/service/admin/AdminPermissionInfo.java (100%) create mode 100644 server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/security/SMUtils.java create mode 100644 server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/model/RMSubjectProjectPermissions.java diff --git a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF index 9f8a4013cd..50a7b8cb30 100644 --- a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF @@ -29,6 +29,7 @@ Export-Package: io.cloudbeaver, io.cloudbeaver.registry, io.cloudbeaver.server, io.cloudbeaver.service, + io.cloudbeaver.service.security, io.cloudbeaver.service.sql, io.cloudbeaver.utils Automatic-Module-Name: io.cloudbeaver.model diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java index 82e5ca35c2..40e714f34e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java @@ -346,7 +346,7 @@ public class WebConnectionInfo { @Property public boolean isCanEdit() { - return hasProjectPermission(RMProjectPermission.CONNECTIONS_EDIT); + return hasProjectPermission(RMProjectPermission.DATA_SOURCES_EDIT); } @Property diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebProjectInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebProjectInfo.java index 73baf1cf1a..a02ef3149e 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebProjectInfo.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebProjectInfo.java @@ -18,6 +18,7 @@ package io.cloudbeaver.model; import io.cloudbeaver.VirtualProjectImpl; import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.service.security.SMUtils; import org.jkiss.dbeaver.model.app.DBPProject; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.rm.RMProjectPermission; @@ -55,16 +56,27 @@ public class WebProjectInfo { } @Property - public boolean isCanCreateConnections() { - return hasRmPermission(RMProjectPermission.CONNECTIONS_EDIT); + public boolean isCanEditDataSources() { + return hasDatasourcePermission(RMProjectPermission.DATA_SOURCES_EDIT); } @Property - public boolean isCanViewConnections() { - return hasRmPermission(RMProjectPermission.CONNECTIONS_VIEW); + public boolean isCanViewDataSources() { + return hasDatasourcePermission(RMProjectPermission.DATA_SOURCES_VIEW); } - private boolean hasRmPermission(RMProjectPermission permission) { - return project.getRmProject().getProjectPermissions().contains(permission.getPermissionId()); + @Property + public boolean isCanEditResources() { + return hasDatasourcePermission(RMProjectPermission.RESOURCE_EDIT); + } + + @Property + public boolean isCanViewResources() { + return hasDatasourcePermission(RMProjectPermission.RESOURCE_VIEW); + } + + private boolean hasDatasourcePermission(RMProjectPermission permission) { + return SMUtils.isRMAdmin(session) + || project.getRmProject().getProjectPermissions().contains(permission.getPermissionId()); } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/RMUtils.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/RMUtils.java index 8e88f4eeca..4cc972a770 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/RMUtils.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/RMUtils.java @@ -49,7 +49,7 @@ public class RMUtils { RMProject project = new RMProject("anonymous"); project.setId("anonymous"); project.setType(RMProject.Type.USER); - project.setProjectPermissions(RMProjectPermission.CONNECTIONS_EDIT.getAllPermissions()); + project.setProjectPermissions(RMProjectPermission.DATA_SOURCES_EDIT.getAllPermissions()); return project; } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java index 2b8aca87b9..dd512e5371 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/rm/local/LocalResourceController.java @@ -173,8 +173,8 @@ public class LocalResourceController implements RMController { switch (projectType) { case GLOBAL: return credentialsProvider.hasPermission(DBWConstants.PERMISSION_ADMIN) - ? Set.of(RMProjectPermission.RESOURCE_EDIT, RMProjectPermission.CONNECTIONS_EDIT) - : Set.of(RMProjectPermission.RESOURCE_VIEW, RMProjectPermission.CONNECTIONS_VIEW); + ? Set.of(RMProjectPermission.RESOURCE_EDIT, RMProjectPermission.DATA_SOURCES_EDIT) + : Set.of(RMProjectPermission.RESOURCE_VIEW, RMProjectPermission.DATA_SOURCES_VIEW); case SHARED: if(projectId == null) { throw new DBException("Project id required"); @@ -185,7 +185,7 @@ public class LocalResourceController implements RMController { .map(RMProjectPermission::fromPermission) .collect(Collectors.toSet()); case USER: - return Set.of(RMProjectPermission.RESOURCE_EDIT, RMProjectPermission.CONNECTIONS_EDIT); + return Set.of(RMProjectPermission.RESOURCE_EDIT, RMProjectPermission.DATA_SOURCES_EDIT); default: throw new DBException("Unknown project type:" + projectType); } @@ -745,10 +745,9 @@ public class LocalResourceController implements RMController { return new RMProjectName(prefix, name); } - public static boolean isShared(String projectId) { + public static boolean isGlobalProject(String projectId) { RMProjectName rmProjectName = parseProjectName(projectId); - return RMProject.Type.SHARED.getPrefix().equals(rmProjectName.getPrefix()) || - RMProject.Type.GLOBAL.getPrefix().equals(rmProjectName.getPrefix()); + return RMProject.Type.GLOBAL.getPrefix().equals(rmProjectName.getPrefix()); } } diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java index f1239c2260..af80ade6ac 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java @@ -335,7 +335,7 @@ public class WebSession extends AbstractSessionPersistent implements SMSession, RMProject[] rmProjects = controller.listAccessibleProjects(); for (RMProject project : rmProjects) { VirtualProjectImpl virtualProject = createVirtualProject(project); - if (!virtualProject.getRmProject().getProjectPermissions().contains(RMProjectPermission.CONNECTIONS_EDIT.getPermissionId())) { + if (!virtualProject.getRmProject().getProjectPermissions().contains(RMProjectPermission.DATA_SOURCES_EDIT.getPermissionId())) { // Projects for which user don't have edit permission can't be saved. So mark the as in memory virtualProject.setInMemory(true); } diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminPermissionInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/admin/AdminPermissionInfo.java similarity index 100% rename from server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/AdminPermissionInfo.java rename to server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/admin/AdminPermissionInfo.java diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/security/SMUtils.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/security/SMUtils.java new file mode 100644 index 0000000000..a613161bac --- /dev/null +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/service/security/SMUtils.java @@ -0,0 +1,36 @@ +package io.cloudbeaver.service.security; + +import io.cloudbeaver.DBWConstants; +import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.registry.WebPermissionDescriptor; +import io.cloudbeaver.registry.WebServiceDescriptor; +import io.cloudbeaver.registry.WebServiceRegistry; +import io.cloudbeaver.service.admin.AdminPermissionInfo; +import org.jkiss.code.NotNull; +import org.jkiss.dbeaver.model.rm.RMConstants; +import org.jkiss.dbeaver.model.security.SMConstants; + +import java.util.ArrayList; +import java.util.List; + +public class SMUtils { + public static boolean isAdmin(WebSession webSession) { + return webSession.hasPermission(DBWConstants.PERMISSION_ADMIN); + } + + public static boolean isRMAdmin(WebSession webSession) { + return isAdmin(webSession) || webSession.hasPermission(RMConstants.PERMISSION_RM_ADMIN); + } + + public static List findPermissions(@NotNull String permissionsScope) { + List permissionInfos = new ArrayList<>(); + for (WebServiceDescriptor wsd : WebServiceRegistry.getInstance().getWebServices()) { + for (WebPermissionDescriptor pd : wsd.getPermissions()) { + if (permissionsScope.equals(pd.getScope())) { + permissionInfos.add(new AdminPermissionInfo(pd)); + } + } + } + return permissionInfos; + } +} diff --git a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls index c097dd45e4..0e8498648b 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls @@ -370,8 +370,10 @@ type ProjectInfo { id: String! name: String! description: String - canCreateConnections: Boolean! - canViewConnections: Boolean! + canEditDataSources: Boolean! + canViewDataSources: Boolean! + canEditResources: Boolean! + canViewResources: Boolean! } type LogEntry { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java index 99bbb2eb79..eee3e05c6a 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java @@ -111,32 +111,32 @@ public interface DBWServiceCore extends DBWService { @Nullable List networkCredentials, @Nullable Boolean saveCredentials) throws DBWebException; - @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_CONNECTIONS_EDIT}) + @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATA_SOURCES_EDIT}) WebConnectionInfo createConnection( @NotNull WebSession webSession, @Nullable @WebObjectId String projectId, @NotNull WebConnectionConfig connectionConfig) throws DBWebException; - @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_CONNECTIONS_EDIT}) + @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATA_SOURCES_EDIT}) WebConnectionInfo updateConnection( @NotNull WebSession webSession, @Nullable @WebObjectId String projectId, @NotNull WebConnectionConfig connectionConfig) throws DBWebException; - @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_CONNECTIONS_EDIT}) + @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATA_SOURCES_EDIT}) boolean deleteConnection( @NotNull WebSession webSession, @Nullable @WebObjectId String projectId, @NotNull String connectionId) throws DBWebException; - @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_CONNECTIONS_EDIT}) + @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATA_SOURCES_EDIT}) WebConnectionInfo createConnectionFromTemplate( @NotNull WebSession webSession, @Nullable @WebObjectId String projectId, @NotNull String templateId, @Nullable String connectionName) throws DBWebException; - @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_CONNECTIONS_EDIT}) + @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATA_SOURCES_EDIT}) WebConnectionInfo copyConnectionFromNode( @NotNull WebSession webSession, @Nullable @WebObjectId String projectId, @@ -162,14 +162,14 @@ public interface DBWServiceCore extends DBWService { /////////////////////////////////////////// // Folders - @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_CONNECTIONS_EDIT}) + @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATA_SOURCES_EDIT}) WebConnectionFolderInfo createConnectionFolder( @NotNull WebSession session, @Nullable @WebObjectId String projectId, @NotNull String parentNodePath, @NotNull String newName) throws DBWebException; - @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_CONNECTIONS_EDIT}) + @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATA_SOURCES_EDIT}) WebConnectionFolderInfo renameConnectionFolder( @NotNull WebSession session, @Nullable @WebObjectId @@ -177,7 +177,7 @@ public interface DBWServiceCore extends DBWService { @NotNull String folderPath, @NotNull String newName) throws DBWebException; - @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_CONNECTIONS_EDIT}) + @WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATA_SOURCES_EDIT}) boolean deleteConnectionFolder( @NotNull WebSession session, @Nullable @WebObjectId String projectId, diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java index bd490aade0..428b341c8c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java @@ -34,7 +34,6 @@ import org.jkiss.dbeaver.model.struct.DBSEntity; import org.jkiss.dbeaver.model.struct.DBSObject; import org.jkiss.dbeaver.model.struct.rdb.DBSProcedure; import org.jkiss.dbeaver.registry.DataSourceFolder; -import org.jkiss.dbeaver.registry.DataSourceRegistry; import org.jkiss.dbeaver.runtime.DBWorkbench; import java.util.ArrayList; @@ -185,7 +184,7 @@ public class WebNavigatorNodeInfo { return features.toArray(new String[0]); } VirtualProjectImpl project = session.getProjectById(node.getOwnerProject().getId()); - if (!project.getRmProject().getProjectPermissions().contains(RMProjectPermission.CONNECTIONS_EDIT.getPermissionId())) { + if (!project.getRmProject().getProjectPermissions().contains(RMProjectPermission.DATA_SOURCES_EDIT.getPermissionId())) { return features.toArray(new String[0]); } if (node instanceof DBNLocalFolder || node instanceof DBNResourceManagerResource) { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java index 5b01f9b60d..2c9ddeced2 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java @@ -442,7 +442,7 @@ public class WebServiceNavigator implements DBWServiceNavigator { private boolean hasNodeEditPermission(DBNNode node, RMProject rmProject) { var projectPermissions = rmProject.getProjectPermissions(); if (node instanceof DBNDataSource || node instanceof DBNLocalFolder) { - return projectPermissions.contains(RMProjectPermission.CONNECTIONS_EDIT.getPermissionId()); + return projectPermissions.contains(RMProjectPermission.DATA_SOURCES_EDIT.getPermissionId()); } else if (node instanceof DBNAbstractResourceManagerNode) { return projectPermissions.contains(RMProjectPermission.RESOURCE_EDIT.getPermissionId()); } diff --git a/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls b/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls index efdbdbf132..96405de015 100644 --- a/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls +++ b/server/bundles/io.cloudbeaver.service.admin/schema/service.admin.graphqls @@ -11,6 +11,17 @@ type AdminConnectionGrantInfo { subjectType: AdminSubjectType! } +type AdminObjectPermissions { + objectId: ID! + permissions: [String!]! +} + +type AdminObjectGrantInfo { + subjectId: ID! + subjectType: AdminSubjectType! + objectPermissions: AdminObjectPermissions! +} + type AdminConnectionSearchInfo { displayName: String! host: String! diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java index b087a8fda2..c5a12d3994 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java @@ -37,6 +37,7 @@ import io.cloudbeaver.server.CBConstants; import io.cloudbeaver.server.CBPlatform; import io.cloudbeaver.service.DBWServiceServerConfigurator; import io.cloudbeaver.service.admin.*; +import io.cloudbeaver.service.security.SMUtils; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; @@ -118,17 +119,9 @@ public class WebServiceAdmin implements DBWServiceAdmin { @Override public List listPermissions(@NotNull WebSession webSession) throws DBWebException { try { - List permissionInfos = new ArrayList<>(); - for (WebServiceDescriptor wsd : WebServiceRegistry.getInstance().getWebServices()) { - for (WebPermissionDescriptor pd : wsd.getPermissions()) { - if(SMConstants.SUBJECT_PERMISSION_SCOPE.equals(pd.getScope())) { - permissionInfos.add(new AdminPermissionInfo(pd)); - } - } - } - return permissionInfos; + return SMUtils.findPermissions(SMConstants.SUBJECT_PERMISSION_SCOPE); } catch (Exception e) { - throw new DBWebException("Error reading users", e); + throw new DBWebException("Error reading permissions", e); } } diff --git a/server/bundles/io.cloudbeaver.service.rm/plugin.xml b/server/bundles/io.cloudbeaver.service.rm/plugin.xml index ca3ff4442b..0134c563ec 100644 --- a/server/bundles/io.cloudbeaver.service.rm/plugin.xml +++ b/server/bundles/io.cloudbeaver.service.rm/plugin.xml @@ -6,14 +6,15 @@ + category="resources" scope="project"/> + category="resources" scope="project"/> - - + + diff --git a/server/bundles/io.cloudbeaver.service.rm/schema/service.rm.graphqls b/server/bundles/io.cloudbeaver.service.rm/schema/service.rm.graphqls index 3d3e6f8050..eb1f4d0758 100644 --- a/server/bundles/io.cloudbeaver.service.rm/schema/service.rm.graphqls +++ b/server/bundles/io.cloudbeaver.service.rm/schema/service.rm.graphqls @@ -17,6 +17,11 @@ type RMResource { length: Int! } +input RMProjectPermissions { + subjectId: String! + permissions: [String!]! +} + extend type Query { # List accessible projects @@ -26,7 +31,12 @@ extend type Query { rmProject(projectId: String!): RMProject! - # List accessible projects + rmListProjectPermissions: AdminPermissionInfo + + rmListProjectGrantedPermissions(projectId: String!): [AdminObjectGrantInfo!]! + rmListSubjectProjectsPermissionGrants(subjectId: String!): [AdminObjectGrantInfo!]! + + rmListResources( projectId: String!, folder: String, @@ -70,4 +80,7 @@ extend type Mutation { description: String): RMProject! rmDeleteProject(projectId: ID!): Boolean! + + rmSetProjectPermissions(projectId: String!, permissions: [RMProjectPermissions!]!): Boolean! + } \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/DBWServiceRM.java b/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/DBWServiceRM.java index 15471ca396..863b79fa6e 100644 --- a/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/DBWServiceRM.java +++ b/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/DBWServiceRM.java @@ -17,15 +17,19 @@ package io.cloudbeaver.service.rm; import io.cloudbeaver.*; -import io.cloudbeaver.model.WebProjectInfo; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.service.DBWService; +import io.cloudbeaver.service.admin.AdminPermissionInfo; +import io.cloudbeaver.service.rm.model.RMSubjectProjectPermissions; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.model.rm.RMConstants; import org.jkiss.dbeaver.model.rm.RMProject; import org.jkiss.dbeaver.model.rm.RMResource; +import org.jkiss.dbeaver.model.security.SMObjectPermissionsGrant; + +import java.util.List; /** * Web service API @@ -99,4 +103,30 @@ public interface DBWServiceRM extends DBWService { boolean deleteProject( @NotNull WebSession session, @NotNull @WebObjectId String projectId) throws DBWebException; + + @WebAction(requirePermissions = {RMConstants.PERMISSION_RM_ADMIN}) + List listProjectPermissions() throws DBWebException; + + @WebProjectAction( + requireProjectPermissions = RMConstants.PERMISSION_PROJECT_ADMIN + ) + boolean setProjectPermissions( + @NotNull WebSession webSession, + @NotNull @WebObjectId String projectId, + @NotNull RMSubjectProjectPermissions projectPermissions + ) throws DBWebException; + + @WebProjectAction( + requireProjectPermissions = RMConstants.PERMISSION_PROJECT_ADMIN + ) + List listProjectGrantedPermissions( + @NotNull WebSession webSession, + @NotNull @WebObjectId String projectId + ) throws DBWebException; + + @WebAction(requirePermissions = {RMConstants.PERMISSION_RM_ADMIN}) + List listSubjectProjectsPermissionGrants( + @NotNull WebSession webSession, + @NotNull String subjectId + ) throws DBWebException; } diff --git a/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/WebServiceBindingRM.java b/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/WebServiceBindingRM.java index 687a1a8e4a..1701319c39 100644 --- a/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/WebServiceBindingRM.java +++ b/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/WebServiceBindingRM.java @@ -20,6 +20,7 @@ import io.cloudbeaver.DBWebException; import io.cloudbeaver.service.DBWBindingContext; import io.cloudbeaver.service.WebServiceBindingBase; import io.cloudbeaver.service.rm.impl.WebServiceRM; +import io.cloudbeaver.service.rm.model.RMSubjectProjectPermissions; import org.jkiss.utils.CommonUtils; /** @@ -53,6 +54,16 @@ public class WebServiceBindingRM extends WebServiceBindingBase { env -> getService(env).readResourceAsString(getWebSession(env), env.getArgument("projectId"), env.getArgument("resourcePath"))) + .dataFetcher("rmListProjectPermissions", env -> getService(env).listProjectPermissions()) + .dataFetcher("rmSetProjectPermissions", env -> getService(env).setProjectPermissions( + getWebSession(env), + env.getArgument("projectId"), + new RMSubjectProjectPermissions(env.getArgument("permissions")) + )) + .dataFetcher("rmListProjectGrantedPermissions", env -> getService(env).listProjectGrantedPermissions( + getWebSession(env), + env.getArgument("subjectId") + )) ; model.getMutationType() .dataFetcher("rmCreateResource", diff --git a/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/impl/WebServiceRM.java b/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/impl/WebServiceRM.java index ed3403c1f0..ff36cc553e 100644 --- a/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/impl/WebServiceRM.java +++ b/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/impl/WebServiceRM.java @@ -17,9 +17,11 @@ package io.cloudbeaver.service.rm.impl; import io.cloudbeaver.DBWebException; -import io.cloudbeaver.model.WebProjectInfo; import io.cloudbeaver.model.session.WebSession; +import io.cloudbeaver.service.admin.AdminPermissionInfo; import io.cloudbeaver.service.rm.DBWServiceRM; +import io.cloudbeaver.service.rm.model.RMSubjectProjectPermissions; +import io.cloudbeaver.service.security.SMUtils; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; @@ -27,8 +29,12 @@ import org.jkiss.dbeaver.model.app.DBPProject; import org.jkiss.dbeaver.model.rm.RMController; import org.jkiss.dbeaver.model.rm.RMProject; import org.jkiss.dbeaver.model.rm.RMResource; +import org.jkiss.dbeaver.model.security.*; import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * Web service implementation @@ -148,6 +154,60 @@ public class WebServiceRM implements DBWServiceRM { } } + @Override + public List listProjectPermissions() throws DBWebException { + try { + return SMUtils.findPermissions(SMConstants.PROJECT_PERMISSION_SCOPE); + } catch (Exception e) { + throw new DBWebException("Error reading project permissions", e); + } + } + + @Override + public boolean setProjectPermissions(@NotNull WebSession webSession, + @NotNull String projectId, + @NotNull RMSubjectProjectPermissions projectPermissions + ) throws DBWebException { + try { + SMController sm = webSession.getSecurityController(); + //TODO one 'setObjectPermissions' call + for (Map.Entry> entry : projectPermissions.getSubjectPermissions().entrySet()) { + String subjectId = entry.getKey(); + Set permissions = entry.getValue(); + sm.setObjectPermissions( + Set.of(projectId), + SMObjects.PROJECT, + Set.of(subjectId), + permissions, + webSession.getUserId() + ); + } + return true; + } catch (Exception e) { + throw new DBWebException("Error granting project permissions", e); + } + } + + @Override + public List listProjectGrantedPermissions(@NotNull WebSession webSession, @NotNull String projectId) throws DBWebException { + SMController sm = webSession.getSecurityController(); + try { + return sm.getObjectPermissionGrants(projectId, SMObjects.PROJECT); + } catch (DBException e) { + throw new DBWebException("Error reading project permission grants", e); + } + } + + @Override + public List listSubjectProjectsPermissionGrants(@NotNull WebSession webSession, @NotNull String subjectId) throws DBWebException { + try { + SMAdminController sm = webSession.getAdminSecurityController(); + return sm.getSubjectObjectPermissionGrants(subjectId, SMObjects.PROJECT); + } catch (DBException e) { + throw new DBWebException("Error reading project permission grants", e); + } + } + private RMController getResourceController(WebSession webSession) { return webSession.getRmController(); } diff --git a/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/model/RMSubjectProjectPermissions.java b/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/model/RMSubjectProjectPermissions.java new file mode 100644 index 0000000000..e31680874f --- /dev/null +++ b/server/bundles/io.cloudbeaver.service.rm/src/io/cloudbeaver/service/rm/model/RMSubjectProjectPermissions.java @@ -0,0 +1,22 @@ +package io.cloudbeaver.service.rm.model; + +import org.jkiss.dbeaver.model.data.json.JSONUtils; + +import java.util.*; + +public class RMSubjectProjectPermissions { + private final Map> subjectPermissions = new HashMap<>(); + + public RMSubjectProjectPermissions(Map params) { + for (Map.Entry entry : params.entrySet()) { + String subjectId = entry.getKey(); + Map subjectParams = JSONUtils.getObject(params, subjectId); + Set permissions = new HashSet<>(JSONUtils.getStringList(subjectParams, "permissions")); + this.subjectPermissions.put(subjectId, permissions); + } + } + + public Map> getSubjectPermissions() { + return subjectPermissions; + } +}