From 28ea689652eb66338823e514c27a9fdb9fc3ba4c Mon Sep 17 00:00:00 2001 From: Serge Rider Date: Wed, 9 Sep 2020 11:51:08 +0300 Subject: [PATCH] CB-253 Check connection permissions --- .../schema/service.core.graphqls | 3 + .../cloudbeaver/model/session/WebSession.java | 89 ++++++++++++++----- .../service/WebServiceBindingBase.java | 8 +- .../service/core/DBWServiceCore.java | 3 + .../service/core/WebServiceBindingCore.java | 1 + .../service/core/impl/WebServiceCore.java | 23 +++-- 6 files changed, 93 insertions(+), 34 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls index 039ebb7ff2..d79a6d4dd7 100644 --- a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls +++ b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls @@ -303,6 +303,9 @@ extend type Mutation { # Refreshes session on server and returns its state touchSession: Boolean + # Refresh session connection list + refreshSessionConnections: Boolean + # Refreshes session on server and returns its state changeSessionLanguage(locale: String): Boolean diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/session/WebSession.java index 014b37311d..0f6a7560a4 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/session/WebSession.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/session/WebSession.java @@ -16,6 +16,8 @@ */ package io.cloudbeaver.model.session; +import io.cloudbeaver.DBWConnectionGrant; +import io.cloudbeaver.DBWConstants; import io.cloudbeaver.DBWSecurityController; import io.cloudbeaver.DBWebException; import io.cloudbeaver.model.WebAsyncTaskInfo; @@ -52,6 +54,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; +import java.util.stream.Collectors; /** * Web session. @@ -153,7 +156,11 @@ public class WebSession implements DBASession { return user; } - public synchronized Set getSessionPermissions() throws DBCException { + public synchronized boolean hasPermission(String perm) { + return getSessionPermissions().contains(perm); + } + + public synchronized Set getSessionPermissions() { if (sessionPermissions == null) { refreshSessionAuth(); } @@ -172,11 +179,7 @@ public class WebSession implements DBASession { } catch (DBCException e) { log.error(e); } - try { - refreshSessionAuth(); - } catch (DBCException e) { - log.error(e); - } + refreshSessionAuth(); } private void initNavigatorModel() { @@ -189,17 +192,59 @@ public class WebSession implements DBASession { this.databases = projectNode.getDatabases(); this.locale = Locale.getDefault().getLanguage(); + try { + this.refreshConnections(); + } catch (Exception e) { + log.error("Error getting connection list", e); + } + } + + public void refreshConnections() { + + // Add all provided datasources to the session + List connList = new ArrayList<>(); + for (DBPDataSourceContainer ds : databases.getDataSourceRegistry().getDataSources()) { + if (ds.isProvided()) { + WebConnectionInfo connectionInfo = new WebConnectionInfo(this, ds); + connList.add(connectionInfo); + } + } + filterAccessibleConnections(connList); + // Add all provided datasources to the session synchronized (connections) { - for (DBPDataSourceContainer ds : databases.getDataSourceRegistry().getDataSources()) { - if (ds.isProvided()) { - WebConnectionInfo connectionInfo = new WebConnectionInfo(this, ds); - connections.put(connectionInfo.getId(), connectionInfo); - } + connections.clear(); + for (WebConnectionInfo connectionInfo : connList) { + connections.put(connectionInfo.getId(), connectionInfo); } } } + public void filterAccessibleConnections(List connections) { + if (this.hasPermission(DBWConstants.PERMISSION_ADMIN)) { + // All connections are accessible + return; + } + Set allowedConnections = getAccessibleConnectionIds(); + connections.removeIf(c -> !allowedConnections.contains(c.getId())); + } + + @NotNull + public Set getAccessibleConnectionIds() { + CBApplication application = CBApplication.getInstance(); + String subjectId = user == null ? + application.getAppConfiguration().getAnonymousUserRole() : user.getUserId(); + + try { + return Arrays.stream(application.getSecurityController() + .getSubjectConnectionAccess(new String[]{subjectId})) + .map(DBWConnectionGrant::getConnectionId).collect(Collectors.toSet()); + } catch (DBCException e) { + log.error("Error reading connection grants", e); + return Collections.emptySet(); + } + } + private void resetSessionCache() throws DBCException { // Clear attributes synchronized (attributes) { @@ -230,17 +275,21 @@ public class WebSession implements DBASession { this.databases = null; } - private void refreshSessionAuth() throws DBCException { - CBApplication application = CBPlatform.getInstance().getApplication(); - if (this.user == null) { - if (application.getAppConfiguration().isAnonymousAccessEnabled()) { - sessionPermissions = application.getSecurityController().getSubjectPermissions( - application.getAppConfiguration().getAnonymousUserRole()); + private void refreshSessionAuth() { + try { + CBApplication application = CBPlatform.getInstance().getApplication(); + if (this.user == null) { + if (application.getAppConfiguration().isAnonymousAccessEnabled()) { + sessionPermissions = application.getSecurityController().getSubjectPermissions( + application.getAppConfiguration().getAnonymousUserRole()); + } else { + sessionPermissions = Collections.emptySet(); + } } else { - sessionPermissions = Collections.emptySet(); + sessionPermissions = application.getSecurityController().getUserPermissions(this.user.getUserId()); } - } else { - sessionPermissions = application.getSecurityController().getUserPermissions(this.user.getUserId()); + } catch (Exception e) { + log.error("Error reading session permissions", e); } } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java index 19a262b0c1..1affc3045f 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java @@ -28,7 +28,6 @@ import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.server.CBApplication; import io.cloudbeaver.server.CBPlatform; import io.cloudbeaver.server.graphql.GraphQLEndpoint; -import org.jkiss.dbeaver.model.exec.DBCException; import org.jkiss.utils.CommonUtils; import javax.servlet.http.HttpServletRequest; @@ -147,12 +146,7 @@ public abstract class WebServiceBindingBase impleme } if (!CBApplication.getInstance().isConfigurationMode()) { // Check permissions - Set sessionPermissions; - try { - sessionPermissions = session.getSessionPermissions(); - } catch (DBCException e) { - throw new DBWebExceptionAccessDenied("Can't retrieve session permissions", e); - } + Set sessionPermissions = session.getSessionPermissions(); if (CommonUtils.isEmpty(sessionPermissions)) { throw new DBWebExceptionAccessDenied("Anonymous access restricted"); } 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 f19acfc11c..c399bcd87b 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 @@ -69,6 +69,9 @@ public interface DBWServiceCore extends DBWService { @WebAction(requirePermissions = {}) boolean touchSession(HttpServletRequest request) throws DBWebException; + @WebAction(requirePermissions = {}) + boolean refreshSessionConnections(HttpServletRequest request) throws DBWebException; + @WebAction boolean changeSessionLanguage(WebSession webSession, String locale) throws DBWebException; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java index 87f3f370cd..8a42268630 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java @@ -66,6 +66,7 @@ public class WebServiceBindingCore extends WebServiceBindingBase .dataFetcher("openSession", env -> getService(env).openSession(sessionManager.getWebSession(GraphQLEndpoint.getServletRequest(env), false))) .dataFetcher("closeSession", env -> getService(env).closeSession(GraphQLEndpoint.getServletRequest(env))) .dataFetcher("touchSession", env -> getService(env).touchSession(GraphQLEndpoint.getServletRequest(env))) + .dataFetcher("refreshSessionConnections", env -> getService(env).refreshSessionConnections(GraphQLEndpoint.getServletRequest(env))) .dataFetcher("changeSessionLanguage", env -> getService(env).changeSessionLanguage(getWebSession(env), env.getArgument("locale"))) .dataFetcher("openConnection", env -> getService(env).openConnection(getWebSession(env), getConnectionConfig(env))) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java index 79092f8208..767edbc914 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java @@ -33,7 +33,6 @@ import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry; import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration; import org.jkiss.dbeaver.model.connection.DBPDriver; import org.jkiss.dbeaver.model.data.json.JSONUtils; -import org.jkiss.dbeaver.model.exec.DBCException; import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNative; import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings; import org.jkiss.dbeaver.registry.DataSourceDescriptor; @@ -101,10 +100,13 @@ public class WebServiceCore implements DBWServiceCore { public List getTemplateConnections(WebSession webSession) throws DBWebException { List result = new ArrayList<>(); for (DBPDataSourceContainer ds : WebServiceUtils.getDataSourceRegistry().getDataSources()) { - if (ds.isTemplate() && CBPlatform.getInstance().getApplicableDrivers().contains(ds.getDriver())) { + if (ds.isTemplate() && + CBPlatform.getInstance().getApplicableDrivers().contains(ds.getDriver())) + { result.add(new WebConnectionInfo(webSession, ds)); } } + webSession.filterAccessibleConnections(result); return result; } @@ -117,11 +119,7 @@ public class WebServiceCore implements DBWServiceCore { DBWConstants.PERMISSION_ADMIN }; } - try { - return webSession.getSessionPermissions().toArray(new String[0]); - } catch (DBCException e) { - throw new DBWebException("Error reading session permissions", e); - } + return webSession.getSessionPermissions().toArray(new String[0]); } @Override @@ -149,6 +147,17 @@ public class WebServiceCore implements DBWServiceCore { return CBPlatform.getInstance().getSessionManager().touchSession(request); } + @Override + public boolean refreshSessionConnections(HttpServletRequest request) throws DBWebException { + WebSession session = CBPlatform.getInstance().getSessionManager().getWebSession(request); + if (session == null) { + return false; + } else { + session.refreshConnections(); + return true; + } + } + @Override public boolean changeSessionLanguage(WebSession webSession, String locale) { webSession.setLocale(locale);