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 4fe539750e3..40cf606df08 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 @@ -72,6 +72,11 @@ public class WebConnectionInfo { private static final String FEATURE_PROVIDED = "provided"; private static final String FEATURE_MANAGEABLE = "manageable"; + private static final String FEATURE_RESTRICT_DATA_EDIT = "restrictDataEdit"; + private static final String FEATURE_RESTRICT_SCRIPT_EXECUTE = "restrictScriptExecute"; + private static final String FEATURE_RESTRICT_DATA_IMPORT = "restrictDataImport"; + private static final String FEATURE_RESTRICT_METADATA_EDIT = "restrictMetadataEdit"; + private static final String TOOL_SESSION_MANAGER = "sessionManager"; private final WebSession session; @@ -275,6 +280,18 @@ public String[] getFeatures() { if (dataSourceContainer.isConnectionReadOnly()) { features.add(FEATURE_READ_ONLY); } + if (!dataSourceContainer.hasModifyPermission(DBPDataSourcePermission.PERMISSION_EDIT_DATA)) { + features.add(FEATURE_RESTRICT_DATA_EDIT); + } + if (!dataSourceContainer.hasModifyPermission(DBPDataSourcePermission.PERMISSION_EXECUTE_SCRIPTS)) { + features.add(FEATURE_RESTRICT_SCRIPT_EXECUTE); + } + if (!dataSourceContainer.hasModifyPermission(DBPDataSourcePermission.PERMISSION_IMPORT_DATA)) { + features.add(FEATURE_RESTRICT_DATA_IMPORT); + } + if (!dataSourceContainer.hasModifyPermission(DBPDataSourcePermission.PERMISSION_EDIT_METADATA)) { + features.add(FEATURE_RESTRICT_METADATA_EDIT); + } if (dataSourceContainer.isProvided()) { features.add(FEATURE_PROVIDED); } 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 a35c46d4e30..10b2c55d801 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 @@ -461,6 +461,7 @@ public String renameNode( return node.getNodeUri(); } if (node instanceof DBNDatabaseNode dbNode) { + checkMetadataEditPermission(dbNode); return renameDatabaseObject( session, dbNode, @@ -546,6 +547,7 @@ public int deleteNodes( } checkProjectEditAccess(node, session); if (node instanceof DBNDatabaseNode) { + checkMetadataEditPermission((DBNDatabaseNode) node); DBSObject object = ((DBNDatabaseNode) node).getObject(); DBEObjectMaker objectDeleter = DBWorkbench.getPlatform().getEditorsRegistry().getObjectManager( object.getClass(), DBEObjectMaker.class); @@ -602,6 +604,12 @@ public int deleteNodes( } } + private void checkMetadataEditPermission(@NotNull DBNDatabaseNode node) throws DBException { + if (!node.getDataSourceContainer().hasModifyPermission(DBPDataSourcePermission.PERMISSION_EDIT_METADATA)) { + throw new DBWebException("Structure edit is restricted for this connection"); + } + } + private void checkProjectEditAccess(@NotNull DBNNode node, @NotNull WebSession session) throws DBException { var project = node.getOwnerProject(); if (!(project instanceof BaseWebProjectImpl bwp) || !hasNodeEditPermission(session, node, bwp.getRMProject())) { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java index 1c0372c6a5f..4f6d6ad50d1 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/impl/WebServiceSQL.java @@ -31,10 +31,7 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; -import org.jkiss.dbeaver.model.DBPDataKind; -import org.jkiss.dbeaver.model.DBPDataSource; -import org.jkiss.dbeaver.model.DBPDataSourceContainer; -import org.jkiss.dbeaver.model.DBUtils; +import org.jkiss.dbeaver.model.*; import org.jkiss.dbeaver.model.data.DBDAttributeBinding; import org.jkiss.dbeaver.model.exec.DBCException; import org.jkiss.dbeaver.model.exec.DBCLogicalOperator; @@ -509,6 +506,7 @@ private WebSQLExecuteInfo updateResultsDataBatch( @Nullable List addedRows, @Nullable WebDataFormat dataFormat ) throws DBException { + checkDataEditPermission(contextInfo); WebSQLExecuteInfo[] result = new WebSQLExecuteInfo[1]; DBExecUtils.tryExecuteRecover( @@ -521,6 +519,13 @@ private WebSQLExecuteInfo updateResultsDataBatch( return result[0]; } + private void checkDataEditPermission(@NotNull WebSQLContextInfo contextInfo) throws DBWebException { + if (!contextInfo.getProcessor().getConnection().getDataSourceContainer() + .hasModifyPermission(DBPDataSourcePermission.PERMISSION_EDIT_DATA)) { + throw new DBWebException("Data edit is restricted for this connection"); + } + } + @FunctionalInterface private interface ThrowableFunction { R apply(T obj) throws DBException; @@ -573,6 +578,7 @@ private String readValue( @Override public String updateResultsDataBatchScript(@NotNull WebSQLContextInfo contextInfo, @NotNull String resultsId, @Nullable List updatedRows, @Nullable List deletedRows, @Nullable List addedRows, WebDataFormat dataFormat) throws DBWebException { + checkDataEditPermission(contextInfo); try { return contextInfo.getProcessor().generateResultsDataUpdateScript( contextInfo.getProcessor().getWebSession().getProgressMonitor(), @@ -599,6 +605,10 @@ public WebAsyncTaskInfo asyncExecuteQuery( if (DBWorkbench.isDistributed() && !webSession.hasPermission(DBWConstants.PERMISSION_SQL_EXECUTE_QUERY)) { throw new DBWebException("Permission denied"); } + if (!contextInfo.getProcessor().getConnection().getDataSourceContainer() + .hasModifyPermission(DBPDataSourcePermission.PERMISSION_EXECUTE_SCRIPTS)) { + throw new DBWebException("Script execution is restricted for this connection"); + } return WebSQLUtils.createAsyncTaskExecuteSqlQuery( webSession, contextInfo, diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebServiceDataTransfer.java b/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebServiceDataTransfer.java index 86a93c4896c..77acb2cbc6a 100644 --- a/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebServiceDataTransfer.java +++ b/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebServiceDataTransfer.java @@ -32,6 +32,7 @@ import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.DBPDataSourcePermission; import org.jkiss.dbeaver.model.data.json.JSONUtils; import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; @@ -245,6 +246,10 @@ public WebAsyncTaskInfo asyncImportDataContainer( if (!validateImportPermission(webSession)) { throw new DBWebException("Permission denied. Data import is not allowed for this user"); } + if (!sqlContext.getProcessor().getConnection().getDataSourceContainer() + .hasModifyPermission(DBPDataSourcePermission.PERMISSION_IMPORT_DATA)) { + throw new DBWebException("Data import is restricted for this connection"); + } DataTransferProcessorDescriptor processor = DataTransferRegistry.getInstance().getProcessor(parameters.getProcessorId()); if (processor == null) { throw new DBWebException("Wrong data processor '" + parameters.getProcessorId() + "'");