Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
* Copyright (C) 2010-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,6 +26,7 @@
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.fs.lock.LockManager;
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
Expand All @@ -45,6 +46,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

public abstract class BaseLocalResourceController implements RMController {
Expand Down Expand Up @@ -160,7 +162,9 @@ protected DataSourceParseResults updateProjectDataSourcesConfig(
@Nullable List<String> dataSourceIds
) throws DBException {
try (var ignoredLock = lockController.lock(LockTarget.of(projectId), LockOptions.of("updateProjectDataSources"))) {
DBPProject project = getWebProject(projectId, false);
RMLocalProject project = getWebProject(projectId, false);
Map<String, DBPConnectionConfiguration> storedDataSourceConfigurations =
captureCurrentDataSourceConfigurations(project, dataSourceIds);
return doFileWriteOperation(
projectId, project.getMetadataFolder(false),
() -> {
Expand All @@ -176,6 +180,16 @@ protected DataSourceParseResults updateProjectDataSourcesConfig(
dataSourceIds == null
);
registry.checkForErrors();
try {
processLoadedDataSourceConfigurationUpdate(
project,
projectId,
dataSourceIds,
storedDataSourceConfigurations
);
} catch (DBException e) {
registry.checkForErrors();
}
log.debug("Save data sources configuration in project '" + projectId + "'");
((DataSourcePersistentRegistry) registry).saveDataSources();
registry.checkForErrors();
Expand All @@ -185,6 +199,22 @@ protected DataSourceParseResults updateProjectDataSourcesConfig(
}
}

@NotNull
protected Map<String, DBPConnectionConfiguration> captureCurrentDataSourceConfigurations(
@NotNull RMLocalProject project,
@Nullable List<String> dataSourceIds
) {
return Map.of();
}

protected void processLoadedDataSourceConfigurationUpdate(
@NotNull RMLocalProject project,
@NotNull String projectId,
@Nullable List<String> dataSourceIds,
@NotNull Map<String, DBPConnectionConfiguration> storedDataSourceConfigurations
) throws DBException {
}

@Override
public void deleteProjectDataSources(
@NotNull String projectId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMCredentials;
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.fs.lock.LockManager;
import org.jkiss.dbeaver.model.fs.lock.LockOptions;
import org.jkiss.dbeaver.model.fs.lock.LockTarget;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
import org.jkiss.dbeaver.model.navigator.DBNLocalFolder;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.rm.*;
import org.jkiss.dbeaver.model.security.SMAdminController;
import org.jkiss.dbeaver.model.security.SMObjectType;
Expand All @@ -52,6 +54,7 @@
import org.jkiss.dbeaver.registry.DataSourceParseResults;
import org.jkiss.dbeaver.registry.ResourceTypeDescriptor;
import org.jkiss.dbeaver.registry.ResourceTypeRegistry;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.IOUtils;
Expand Down Expand Up @@ -411,6 +414,107 @@ public boolean updateProjectDataSources(
return parseResults != null;
}

@Override
@NotNull
protected Map<String, DBPConnectionConfiguration> captureCurrentDataSourceConfigurations(
@NotNull RMLocalProject project,
@Nullable List<String> dataSourceIds
) {
return project.getDataSourceRegistry().getDataSources().stream()
.filter(ds -> dataSourceIds == null || dataSourceIds.contains(ds.getId()))
.collect(Collectors.toMap(
DBPDataSourceContainer::getId,
ds -> new DBPConnectionConfiguration(ds.getConnectionConfiguration())
));
}

@Override
protected void processLoadedDataSourceConfigurationUpdate(
@NotNull RMLocalProject project,
@NotNull String projectId,
@Nullable List<String> dataSourceIds,
@NotNull Map<String, DBPConnectionConfiguration> storedDataSourceConfigurations
) throws DBException {
Set<RMProjectPermission> userProjectPermissions = getProjectPermissions(projectId, project.getProjectType());
Set<String> grantedPermissions = userProjectPermissions.stream()
.flatMap(permission -> permission.getAllPermissions().stream())
.collect(Collectors.toSet());

for (DBPDataSourceContainer dataSource : project.getDataSourceRegistry().getDataSources()) {
if (dataSourceIds != null && !dataSourceIds.contains(dataSource.getId())) {
continue;
}

DBPConnectionConfiguration storedConfiguration = storedDataSourceConfigurations.get(dataSource.getId());
reconcileNetworkHandlers(
storedConfiguration,
dataSource.getConnectionConfiguration(),
grantedPermissions
);
}
}

private void reconcileNetworkHandlers(
@Nullable DBPConnectionConfiguration storedConfiguration,
@NotNull DBPConnectionConfiguration updatedConfiguration,
@NotNull Set<String> grantedPermissions
) throws DBException {

// Getting all handlers ids from both stored and updated configurations to check permissions for all of them
// and to add missing handlers if user has no permissions to add new ones
Set<String> handlerIds = new LinkedHashSet<>();
if (storedConfiguration != null) {
storedConfiguration.getHandlers().stream()
.map(DBWHandlerConfiguration::getId)
.forEach(handlerIds::add);
}
updatedConfiguration.getHandlers().stream()
.map(DBWHandlerConfiguration::getId)
.forEach(handlerIds::add);

for (String handlerId : handlerIds) {
DBWHandlerConfiguration storedHandler = storedConfiguration == null ? null : storedConfiguration.getHandler(handlerId);
DBWHandlerConfiguration updatedHandler = updatedConfiguration.getHandler(handlerId);
DBWHandlerConfiguration descriptorSource = updatedHandler != null ? updatedHandler : storedHandler;
if (descriptorSource == null
|| !(descriptorSource.getHandlerDescriptor() instanceof NetworkHandlerDescriptor descriptor)) {
continue;
}

if (descriptor.getRequiredPermissions().isEmpty()
|| grantedPermissions.containsAll(descriptor.getRequiredPermissions())) {
continue;
}

if (storedHandler == null) {
throw new DBException("No permissions to configure network handler '" + handlerId + "'");
}

// if user doesn't have permissions to add new handler, we should keep old one
if (updatedHandler == null) {
updatedConfiguration.updateHandler(new DBWHandlerConfiguration(storedHandler));
continue;
}

if (!areSameHandlerConfiguration(storedHandler, updatedHandler)) {
throw new DBException("No permissions to modify network handler '" + handlerId + "'");
}
}
}

private boolean areSameHandlerConfiguration(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add compare function to handler itself. Or just compare by ID, why so complicated?

@NotNull DBWHandlerConfiguration storedHandler,
@NotNull DBWHandlerConfiguration updatedHandler
) {
DBWHandlerConfiguration storedHandlerCopy = new DBWHandlerConfiguration(storedHandler);
storedHandlerCopy.setDataSource(null);

DBWHandlerConfiguration updatedHandlerCopy = new DBWHandlerConfiguration(updatedHandler);
updatedHandlerCopy.setDataSource(null);

return storedHandlerCopy.equals(updatedHandlerCopy);
}

@Override
public void deleteProjectDataSources(@NotNull String projectId, @NotNull String[] dataSourceIds) throws DBException {
super.deleteProjectDataSources(projectId, dataSourceIds);
Expand Down
Loading