dbeaver/pro#6656 create web connection info objects in a session project (#3751)

* dbeaver/pro#6656 create web connection info objects in a session project

* dbeaver/pro#6656 fix data source connection test

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
This commit is contained in:
Ainur
2025-09-26 10:09:48 +02:00
committed by GitHub
co-authored by mr-anton-t
parent 25247321b8
commit 4f7c7ba808
14 changed files with 690 additions and 988 deletions
@@ -0,0 +1,109 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.app.WebAppConfiguration;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
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.registry.DataSourceDescriptor;
import org.jkiss.utils.CommonUtils;
public class WebConnectionConfigInputHandler<T extends WebConnectionConfig, C extends DataSourceDescriptor> {
private static final Log log = Log.getLog(WebConnectionConfigInputHandler.class);
protected final T input;
protected final DBPDataSourceRegistry registry;
public WebConnectionConfigInputHandler(@NotNull DBPDataSourceRegistry registry, T configInput) {
this.registry = registry;
this.input = configInput;
}
public C createDataSourceContainer() throws DBWebException {
String driverId = input.getDriverId();
if (CommonUtils.isEmpty(driverId)) {
throw new DBWebException("Driver must be specified");
}
DBPDriver driver = WebDataSourceUtils.getDriverById(driverId);
C newDataSource = createDataSourceContainerFromInput(driver);
if (ServletAppUtils.getServletApplication().getAppConfiguration() instanceof WebAppConfiguration webAppConfiguration) {
newDataSource.setNavigatorSettings(webAppConfiguration.getDefaultNavigatorSettings());
}
WebDataSourceUtils.saveAuthProperties(
newDataSource,
newDataSource.getConnectionConfiguration(),
input.getCredentials(),
input.isSaveCredentials(),
input.isSharedCredentials()
);
return newDataSource;
}
public void updateDataSource(@NotNull C dataSource) throws DBWebException {
dataSource.setId(dataSource.getId());
if (!CommonUtils.isEmpty(input.getName())) {
dataSource.setName(input.getName());
}
if (input.getDescription() != null) {
dataSource.setDescription(input.getDescription());
}
dataSource.setFolder(input.getFolder() != null ? registry.getFolder(input.getFolder()) : null);
if (input.isDefaultAutoCommit() != null) {
dataSource.setDefaultAutoCommit(input.isDefaultAutoCommit());
}
WebDataSourceUtils.setConnectionConfiguration(
dataSource.getDriver(),
dataSource.getConnectionConfiguration(),
input
);
WebDataSourceUtils.saveAuthProperties(
dataSource,
dataSource.getConnectionConfiguration(),
input.getCredentials(),
input.isSaveCredentials(),
input.isSharedCredentials()
);
}
@NotNull
protected C createDataSourceContainerFromInput(@NotNull DBPDriver driver) {
DBPConnectionConfiguration dsConfig = new DBPConnectionConfiguration();
WebDataSourceUtils.setConnectionConfiguration(driver, dsConfig, input);
C newDataSource = registry.createDataSource(driver, dsConfig);
newDataSource.setSavePassword(true);
newDataSource.setName(CommonUtils.notNull(input.getName(), "NewConnection"));
newDataSource.setDescription(input.getDescription());
newDataSource.setConnectionReadOnly(input.isReadOnly());
if (input.getFolder() != null) {
newDataSource.setFolder(registry.getFolder(input.getFolder()));
}
return newDataSource;
}
}
@@ -16,11 +16,13 @@
*/
package io.cloudbeaver;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
@@ -33,6 +35,7 @@ import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceRegistry;
import org.jkiss.dbeaver.runtime.jobs.DisconnectJob;
import org.jkiss.utils.CommonUtils;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -159,7 +162,7 @@ public class WebSessionProjectImpl extends WebProjectImpl {
*/
@NotNull
public synchronized WebConnectionInfo addConnection(@NotNull DBPDataSourceContainer dataSourceContainer) {
WebConnectionInfo connection = new WebConnectionInfo(webSession, dataSourceContainer);
WebConnectionInfo connection = createConnectionInfo(dataSourceContainer);
synchronized (connections) {
connections.put(dataSourceContainer.getId(), connection);
}
@@ -237,4 +240,110 @@ public class WebSessionProjectImpl extends WebProjectImpl {
}
return sendDataSourceUpdatedEvent;
}
@NotNull
public WebConnectionInfo createConnectionInfo(@NotNull DBPDataSourceContainer dataSourceDescriptor) {
return new WebConnectionInfo(webSession, dataSourceDescriptor);
}
@NotNull
public WebConnectionInfo createConnection(@NotNull Map<String, Object> configMap) throws DBWebException {
if (CommonUtils.isEmpty(configMap)) {
throw new DBWebException("Connection configuration parameters are missing");
}
DBPDataSourceContainer newDataSource = getDataSourceContainerFromInput(configMap);
return addDataSourceToProject(newDataSource);
}
@NotNull
public WebConnectionInfo addDataSourceToProject(@NotNull DBPDataSourceContainer newDataSource) throws DBWebException {
DBPDataSourceRegistry registry = getDataSourceRegistry();
try {
registry.addDataSource(newDataSource);
registry.checkForErrors();
} catch (DBException e) {
registry.removeDataSource(newDataSource);
throw new DBWebException("Failed to create connection", e);
}
WebConnectionInfo connectionInfo = addConnection(newDataSource);
webSession.addInfoMessage("New connection was created - " + WebDataSourceUtils.getConnectionContainerInfo(
newDataSource));
log.info(String.format(
"New connection was created: [info=%s, user=%s]",
WebDataSourceUtils.getConnectionContainerInfo(newDataSource),
webSession.getUserId()
));
return connectionInfo;
}
@NotNull
public WebConnectionInfo updateConnection(@Nullable Map<String, Object> configMap) throws DBWebException {
WebConnectionConfig config = getConnectionConfigInput(configMap);
WebConnectionInfo connectionInfo = getWebConnectionInfo(config.getConnectionId());
DataSourceDescriptor dataSource = (DataSourceDescriptor) connectionInfo.getDataSourceContainer();
webSession.addInfoMessage("Update connection - " + WebDataSourceUtils.getConnectionContainerInfo(dataSource));
DBPDataSourceRegistry registry = getDataSourceRegistry();
getInputConfigHandler(configMap).updateDataSource(dataSource);
connectionInfo.setCredentialsSavedInSession(null);
try {
registry.updateDataSource(dataSource);
registry.checkForErrors();
} catch (DBException e) {
throw new DBWebException("Failed to update connection", e);
}
return connectionInfo;
}
public boolean deleteConnection(@NotNull String connectionId) throws DBWebException {
WebConnectionInfo connectionInfo = getWebConnectionInfo(connectionId);
webSession.addInfoMessage("Delete connection - " +
WebDataSourceUtils.getConnectionContainerInfo(connectionInfo.getDataSourceContainer()));
closeAndDeleteConnection(connectionInfo);
log.info(String.format(
"Connection deleted: [info=%s, userId=%s]",
WebDataSourceUtils.getConnectionContainerInfo(connectionInfo.getDataSourceContainer()),
webSession.getUserId()
));
return true;
}
@NotNull
private WebConnectionInfo closeAndDeleteConnection(@NotNull WebConnectionInfo connectionInfo) throws DBWebException {
DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer();
boolean disconnected = WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer);
DBPDataSourceRegistry registry = getDataSourceRegistry();
registry.removeDataSource(dataSourceContainer);
try {
registry.checkForErrors();
} catch (DBException e) {
try {
registry.addDataSource(dataSourceContainer);
} catch (DBException ex) {
log.error("Error re-adding after delete attempt", e);
}
throw new DBWebException("Failed to delete connection", e);
}
removeConnection(dataSourceContainer);
return connectionInfo;
}
@NotNull
public DataSourceDescriptor getDataSourceContainerFromInput(@NotNull Map<String, Object> configMap) throws DBWebException {
return getInputConfigHandler(configMap).createDataSourceContainer();
}
@NotNull
public WebConnectionConfig getConnectionConfigInput(@Nullable Map<String, Object> configMap) {
return new WebConnectionConfig(configMap == null ? Map.of() : configMap);
}
@NotNull
protected WebConnectionConfigInputHandler getInputConfigHandler(@NotNull Map<String, Object> configMap) {
return new WebConnectionConfigInputHandler<>(getDataSourceRegistry(), getConnectionConfigInput(configMap));
}
}
@@ -16,11 +16,11 @@
*/
package io.cloudbeaver.model;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.connection.DBPDriverConfigurationType;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.utils.CommonUtils;
import java.util.ArrayList;
import java.util.List;
@@ -58,7 +58,6 @@ public class WebConnectionConfig {
private Map<String, Object> mainPropertyValues;
private Map<String, Object> expertSettingsValues;
private Map<String, Object> providerProperties;
private Map<String, Object> externalParameters;
private List<WebNetworkHandlerConfigInput> networkHandlersConfig;
private DBPDriverConfigurationType configurationType;
private String selectedSecretId;
@@ -69,54 +68,52 @@ public class WebConnectionConfig {
public WebConnectionConfig() {
}
public WebConnectionConfig(Map<String, Object> params) {
if (!CommonUtils.isEmpty(params)) {
connectionId = JSONUtils.getString(params, "connectionId");
driverId = JSONUtils.getString(params, "driverId");
public WebConnectionConfig(@NotNull Map<String, Object> params) {
connectionId = JSONUtils.getString(params, "connectionId");
driverId = JSONUtils.getString(params, "driverId");
host = JSONUtils.getString(params, "host");
port = JSONUtils.getString(params, "port");
serverName = JSONUtils.getString(params, "serverName");
databaseName = JSONUtils.getString(params, "databaseName");
url = JSONUtils.getString(params, "url");
host = JSONUtils.getString(params, "host");
port = JSONUtils.getString(params, "port");
serverName = JSONUtils.getString(params, "serverName");
databaseName = JSONUtils.getString(params, "databaseName");
url = JSONUtils.getString(params, "url");
name = JSONUtils.getString(params, "name");
description = JSONUtils.getString(params, "description");
folder = JSONUtils.getString(params, "folder");
name = JSONUtils.getString(params, "name");
description = JSONUtils.getString(params, "description");
folder = JSONUtils.getString(params, "folder");
properties = JSONUtils.getObjectOrNull(params, "properties");
userName = JSONUtils.getString(params, "userName");
userPassword = JSONUtils.getString(params, "userPassword");
selectedSecretId = JSONUtils.getString(params, "selectedSecretId");
properties = JSONUtils.getObjectOrNull(params, "properties");
userName = JSONUtils.getString(params, "userName");
userPassword = JSONUtils.getString(params, "userPassword");
selectedSecretId = JSONUtils.getString(params, "selectedSecretId");
authModelId = JSONUtils.getString(params, "authModelId");
credentials = JSONUtils.getObjectOrNull(params, "credentials");
saveCredentials = JSONUtils.getBoolean(params, "saveCredentials");
sharedCredentials = JSONUtils.getBoolean(params, "sharedCredentials");
authModelId = JSONUtils.getString(params, "authModelId");
credentials = JSONUtils.getObjectOrNull(params, "credentials");
saveCredentials = JSONUtils.getBoolean(params, "saveCredentials");
sharedCredentials = JSONUtils.getBoolean(params, "sharedCredentials");
mainPropertyValues = JSONUtils.getObjectOrNull(params, "mainPropertyValues");
providerProperties = JSONUtils.getObjectOrNull(params, "providerProperties");
mainPropertyValues = JSONUtils.getObjectOrNull(params, "mainPropertyValues");
providerProperties = JSONUtils.getObjectOrNull(params, "providerProperties");
expertSettingsValues = JSONUtils.getObjectOrNull(params, "expertSettingsValues");
keepAliveInterval = JSONUtils.getInteger(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_KEEP_ALIVE_INTERVAL, -1);
readOnly = JSONUtils.getBoolean(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_READ_ONLY);
defaultAutoCommit = JSONUtils.getBoolean(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_AUTO_COMMIT, true);
defaultCatalogName = JSONUtils.getString(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_DEFAULT_CATALOG);
defaultSchemaName = JSONUtils.getString(
expertSettingsValues != null ? expertSettingsValues : params,
WebExpertSettingsProperties.PROP_DEFAULT_SCHEMA
);
expertSettingsValues = JSONUtils.getObjectOrNull(params, "expertSettingsValues");
keepAliveInterval = JSONUtils.getInteger(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_KEEP_ALIVE_INTERVAL, -1);
readOnly = JSONUtils.getBoolean(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_READ_ONLY);
defaultAutoCommit = JSONUtils.getBoolean(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_AUTO_COMMIT, true);
defaultCatalogName = JSONUtils.getString(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_DEFAULT_CATALOG);
defaultSchemaName = JSONUtils.getString(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_DEFAULT_SCHEMA);
String configType = JSONUtils.getString(params, "configurationType");
configurationType = configType == null ? null : DBPDriverConfigurationType.valueOf(configType);
String configType = JSONUtils.getString(params, "configurationType");
configurationType = configType == null ? null : DBPDriverConfigurationType.valueOf(configType);
externalParameters = JSONUtils.getObjectOrNull(params, "externalParameters");
networkHandlersConfig = new ArrayList<>();
for (Map<String, Object> nhc : JSONUtils.getObjectList(params, "networkHandlersConfig")) {
networkHandlersConfig.add(new WebNetworkHandlerConfigInput(nhc));
}
networkHandlersConfig = new ArrayList<>();
for (Map<String, Object> nhc : JSONUtils.getObjectList(params, "networkHandlersConfig")) {
networkHandlersConfig.add(new WebNetworkHandlerConfigInput(nhc));
}
}
@@ -262,8 +259,4 @@ public class WebConnectionConfig {
public String getDefaultSchemaName() {
return defaultSchemaName;
}
public Map<String, Object> getExternalParameters() {
return externalParameters;
}
}
@@ -16,6 +16,7 @@
*/
package io.cloudbeaver.model;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.model.app.BaseWebAppConfiguration;
import io.cloudbeaver.model.session.WebSession;
@@ -319,6 +320,10 @@ public class WebConnectionInfo {
!dataSourceContainer.getDriver().isAnonymousAccess();
}
public void validateConnection() throws DBWebException {
}
// we don't show non-secured properties in FE when connecting to DB without saved credentials
private boolean isAuthPropertiesEmpty() {
return Arrays.stream(getAuthProperties()).allMatch(f -> f.hasFeature(DBConstants.PROP_FEATURE_NON_SECURED));
@@ -23,6 +23,7 @@ import com.google.gson.Strictness;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebSessionProjectImpl;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.session.WebSession;
@@ -30,21 +31,25 @@ import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.access.DBAAuthCredentials;
import org.jkiss.dbeaver.model.access.DBAAuthCredentialsWithComplexProperties;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDataSourceProviderDescriptor;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNativeCredentials;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.ssh.SSHConstants;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceDisconnectEvent;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.CommonUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;
public class WebDataSourceUtils {
@@ -219,4 +224,181 @@ public class WebDataSourceUtils {
}
credGson.fromJson(credGson.toJsonTree(properties), credentials.getClass());
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials
) {
saveAuthProperties(dataSourceContainer, configuration, authProperties, saveCredentials, sharedCredentials, false);
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials,
boolean isTest
) {
dataSourceContainer.setSavePassword(saveCredentials);
dataSourceContainer.setSharedCredentials(sharedCredentials);
if (!saveCredentials) {
// Reset credentials
if (authProperties == null) {
authProperties = new LinkedHashMap<>();
}
authProperties.replace(AuthModelDatabaseNativeCredentials.PROP_USER_PASSWORD, null);
dataSourceContainer.resetPassword();
} else {
if (authProperties == null) {
// No changes
return;
}
}
{
// Read save credentials
DBAAuthCredentials credentials = configuration.getAuthModel().loadCredentials(dataSourceContainer, configuration);
if (isTest) {
var currentAuthProps = new HashMap<String, String>();
for (Map.Entry<String, Object> stringObjectEntry : authProperties.entrySet()) {
var value = stringObjectEntry.getValue() == null ? null : stringObjectEntry.getValue().toString();
currentAuthProps.put(stringObjectEntry.getKey(), value);
}
configuration.setAuthProperties(currentAuthProps);
}
if (!authProperties.isEmpty()) {
updateCredentialsFromProperties(credentials, authProperties);
}
configuration.getAuthModel().saveCredentials(dataSourceContainer, configuration, credentials);
}
}
public static void setConnectionConfiguration(
@NotNull DBPDriver driver,
@NotNull DBPConnectionConfiguration dsConfig,
@NotNull WebConnectionConfig config
) {
setMainProperties(dsConfig, config);
if (config.getProperties() != null) {
Map<String, String> newProps = new LinkedHashMap<>();
for (Map.Entry<String, Object> pe : config.getProperties().entrySet()) {
newProps.put(pe.getKey(), CommonUtils.toString(pe.getValue()));
}
dsConfig.setProperties(newProps);
}
if (config.getUserName() != null) {
dsConfig.setUserName(config.getUserName());
}
if (config.getUserPassword() != null) {
dsConfig.setUserPassword(config.getUserPassword());
}
if (config.getAuthModelId() != null) {
dsConfig.setAuthModelId(config.getAuthModelId());
}
if (config.getKeepAliveInterval() >= 0) {
dsConfig.setKeepAliveInterval(config.getKeepAliveInterval());
}
if (config.isDefaultAutoCommit() != null) {
dsConfig.getBootstrap().setDefaultAutoCommit(config.isDefaultAutoCommit());
}
dsConfig.getBootstrap().setDefaultCatalogName(config.getDefaultCatalogName());
dsConfig.getBootstrap().setDefaultSchemaName(config.getDefaultSchemaName());
// Save provider props
if (config.getProviderProperties() != null) {
dsConfig.setProviderProperties(new LinkedHashMap<>());
for (Map.Entry<String, Object> e : config.getProviderProperties().entrySet()) {
dsConfig.setProviderProperty(e.getKey(), CommonUtils.toString(e.getValue()));
}
}
if (config.getConfigurationType() != null) {
dsConfig.setConfigurationType(config.getConfigurationType());
}
if (CommonUtils.isEmpty(config.getUrl())) {
dsConfig.setUrl(driver.getConnectionURL(dsConfig));
}
// Save network handlers
if (config.getNetworkHandlersConfig() != null) {
for (WebNetworkHandlerConfigInput nhc : config.getNetworkHandlersConfig()) {
DBWHandlerConfiguration handlerConfig = dsConfig.getHandler(nhc.getId());
if (handlerConfig == null) {
NetworkHandlerDescriptor handlerDescriptor = NetworkHandlerRegistry.getInstance().getDescriptor(nhc.getId());
if (handlerDescriptor == null) {
log.warn("Can't find network handler '" + nhc.getId() + "'");
continue;
} else {
handlerConfig = new DBWHandlerConfiguration(handlerDescriptor, null);
WebDataSourceUtils.updateHandlerConfig(handlerConfig, nhc);
}
} else {
WebDataSourceUtils.updateHandlerConfig(handlerConfig, nhc);
}
dsConfig.updateHandler(handlerConfig);
}
}
}
public static void setMainProperties(@NotNull DBPConnectionConfiguration dsConfig, @NotNull WebConnectionConfig config) {
if (CommonUtils.isNotEmpty(config.getUrl())) {
dsConfig.setUrl(config.getUrl());
return;
}
if (config.getMainPropertyValues() != null) {
for (Map.Entry<String, Object> e : config.getMainPropertyValues().entrySet()) {
if (e.getValue() == null) {
continue;
}
switch (e.getKey()) {
case DBConstants.PROP_HOST -> dsConfig.setHostName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_PORT -> dsConfig.setHostPort(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_DATABASE -> dsConfig.setDatabaseName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_SERVER -> dsConfig.setServerName(CommonUtils.toString(e.getValue()));
default -> throw new IllegalStateException("Unexpected value: " + e.getKey());
}
}
return;
}
if (config.getHost() != null) {
dsConfig.setHostName(config.getHost());
}
if (config.getPort() != null) {
dsConfig.setHostPort(config.getPort());
}
if (config.getDatabaseName() != null) {
dsConfig.setDatabaseName(config.getDatabaseName());
}
if (config.getServerName() != null) {
dsConfig.setServerName(config.getServerName());
}
}
@NotNull
public static DBPDriver getDriverById(String id) throws DBWebException {
int divPos = id.indexOf(':');
if (divPos < 0) {
throw new DBWebException("Bad driver id [" + id + "]");
}
String dsId = id.substring(0, divPos);
String driverId = id.substring(divPos + 1);
DBPDataSourceProviderDescriptor dsProvider = DBWorkbench.getPlatform().getDataSourceProviderRegistry().getDataSourceProvider(dsId);
if (dsProvider == null) {
throw new DBWebException("Data source provider '" + dsId + "' not found");
}
DBPDriver driver = dsProvider.getDriver(driverId);
if (driver == null) {
throw new DBWebException("Driver '" + driverId + "' not found in provider '" + dsId + "'");
}
return driver;
}
public static String getConnectionContainerInfo(@Nullable DBPDataSourceContainer container) {
if (container == null) {
return null;
}
return container.getName() + " [" + container.getId() + "]";
}
}
@@ -30,8 +30,6 @@ import io.cloudbeaver.registry.WebDriverRegistry;
import io.cloudbeaver.registry.WebFeatureRegistry;
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.server.jetty.CBJettyServer;
import io.cloudbeaver.service.ConnectionController;
import io.cloudbeaver.service.ConnectionControllerCE;
import io.cloudbeaver.service.DBWServiceInitializer;
import io.cloudbeaver.service.DBWServiceServerConfigurator;
import io.cloudbeaver.service.session.CBSessionManager;
@@ -785,11 +783,6 @@ public abstract class CBApplication<T extends CBServerConfig>
return new CBWebServerConfig(this);
}
@Override
public ConnectionController getConnectionController() {
return new ConnectionControllerCE();
}
@NotNull
@Override
public ServletSystemInformationCollector<?> getSystemInformationCollector() {
@@ -18,10 +18,7 @@ package io.cloudbeaver;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.WebPropertyInfo;
import io.cloudbeaver.model.app.ServletApplication;
import io.cloudbeaver.model.app.WebAppConfiguration;
import io.cloudbeaver.model.rm.DBNResourceManagerResource;
import io.cloudbeaver.model.session.WebActionParameters;
@@ -30,7 +27,6 @@ import io.cloudbeaver.model.utils.ConfigurationUtils;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebAuthProviderRegistry;
import io.cloudbeaver.server.WebAppUtils;
import io.cloudbeaver.server.WebApplication;
import io.cloudbeaver.service.navigator.WebPropertyFilter;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebCommonUtils;
@@ -39,25 +35,14 @@ import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.access.DBAAuthCredentials;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNativeCredentials;
import org.jkiss.dbeaver.model.navigator.*;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
import org.jkiss.dbeaver.registry.DataSourceProviderDescriptor;
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
import org.jkiss.dbeaver.registry.driver.DriverDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.runtime.properties.PropertyCollector;
import org.jkiss.utils.CommonUtils;
@@ -74,25 +59,6 @@ public class WebServiceUtils extends WebCommonUtils {
private static final Gson gson = new GsonBuilder().create();
@NotNull
public static DBPDriver getDriverById(String id) throws DBWebException {
int divPos = id.indexOf(':');
if (divPos < 0) {
throw new DBWebException("Bad driver id [" + id + "]");
}
String dsId = id.substring(0, divPos);
String driverId = id.substring(divPos + 1);
DataSourceProviderDescriptor dsProvider = DataSourceProviderRegistry.getInstance().getDataSourceProvider(dsId);
if (dsProvider == null) {
throw new DBWebException("Data source provider '" + dsId + "' not found");
}
DriverDescriptor driver = dsProvider.getDriver(driverId);
if (driver == null) {
throw new DBWebException("Driver '" + driverId + "' not found in provider '" + dsId + "'");
}
return driver;
}
@NotNull
public static DBPDataSourceRegistry getGlobalDataSourceRegistry() throws DBWebException {
return WebDataSourceUtils.getGlobalDataSourceRegistry();
@@ -102,198 +68,6 @@ public class WebServiceUtils extends WebCommonUtils {
return WebServiceUtils.class.getClassLoader().getResourceAsStream(path);
}
@NotNull
public static DBPDataSourceContainer createConnectionFromConfig(WebConnectionConfig config, DBPDataSourceRegistry registry) throws DBWebException {
DBPDataSourceContainer newDataSource;
if (!CommonUtils.isEmpty(config.getDriverId())) {
String driverId = config.getDriverId();
if (CommonUtils.isEmpty(driverId)) {
throw new DBWebException("Driver not specified");
}
DBPDriver driver = getDriverById(driverId);
DBPConnectionConfiguration dsConfig = new DBPConnectionConfiguration();
setConnectionConfiguration(driver, dsConfig, config);
newDataSource = registry.createDataSource(driver, dsConfig);
} else {
throw new DBWebException("Template connection or driver must be specified");
}
newDataSource.setSavePassword(true);
newDataSource.setName(config.getName());
newDataSource.setDescription(config.getDescription());
newDataSource.setConnectionReadOnly(config.isReadOnly());
if (config.getFolder() != null) {
newDataSource.setFolder(registry.getFolder(config.getFolder()));
}
ServletApplication app = ServletAppUtils.getServletApplication();
if (app instanceof WebApplication webApplication) {
((DataSourceDescriptor) newDataSource).setNavigatorSettings(
webApplication.getAppConfiguration().getDefaultNavigatorSettings());
}
saveAuthProperties(
newDataSource,
newDataSource.getConnectionConfiguration(),
config.getCredentials(),
config.isSaveCredentials(),
config.isSharedCredentials()
);
return newDataSource;
}
public static void setConnectionConfiguration(DBPDriver driver, DBPConnectionConfiguration dsConfig, WebConnectionConfig config) {
setMainProperties(dsConfig, config);
if (config.getProperties() != null) {
Map<String, String> newProps = new LinkedHashMap<>();
for (Map.Entry<String, Object> pe : config.getProperties().entrySet()) {
newProps.put(pe.getKey(), CommonUtils.toString(pe.getValue()));
}
dsConfig.setProperties(newProps);
}
if (config.getUserName() != null) {
dsConfig.setUserName(config.getUserName());
}
if (config.getUserPassword() != null) {
dsConfig.setUserPassword(config.getUserPassword());
}
if (config.getAuthModelId() != null) {
dsConfig.setAuthModelId(config.getAuthModelId());
}
if (config.getKeepAliveInterval() >= 0) {
dsConfig.setKeepAliveInterval(config.getKeepAliveInterval());
}
if (config.isDefaultAutoCommit() != null) {
dsConfig.getBootstrap().setDefaultAutoCommit(config.isDefaultAutoCommit());
}
dsConfig.getBootstrap().setDefaultCatalogName(config.getDefaultCatalogName());
dsConfig.getBootstrap().setDefaultSchemaName(config.getDefaultSchemaName());
// Save provider props
if (config.getProviderProperties() != null) {
dsConfig.setProviderProperties(new LinkedHashMap<>());
for (Map.Entry<String, Object> e : config.getProviderProperties().entrySet()) {
dsConfig.setProviderProperty(e.getKey(), CommonUtils.toString(e.getValue()));
}
}
if (config.getConfigurationType() != null) {
dsConfig.setConfigurationType(config.getConfigurationType());
}
if (CommonUtils.isEmpty(config.getUrl())) {
dsConfig.setUrl(driver.getConnectionURL(dsConfig));
}
// Save network handlers
if (config.getNetworkHandlersConfig() != null) {
for (WebNetworkHandlerConfigInput nhc : config.getNetworkHandlersConfig()) {
DBWHandlerConfiguration handlerConfig = dsConfig.getHandler(nhc.getId());
if (handlerConfig == null) {
NetworkHandlerDescriptor handlerDescriptor = NetworkHandlerRegistry.getInstance().getDescriptor(nhc.getId());
if (handlerDescriptor == null) {
log.warn("Can't find network handler '" + nhc.getId() + "'");
continue;
} else {
handlerConfig = new DBWHandlerConfiguration(handlerDescriptor, null);
WebDataSourceUtils.updateHandlerConfig(handlerConfig, nhc);
}
} else {
WebDataSourceUtils.updateHandlerConfig(handlerConfig, nhc);
}
dsConfig.updateHandler(handlerConfig);
}
}
}
private static void setMainProperties(DBPConnectionConfiguration dsConfig, WebConnectionConfig config) {
if (CommonUtils.isNotEmpty(config.getUrl())) {
dsConfig.setUrl(config.getUrl());
return;
}
if (config.getMainPropertyValues() != null) {
for (Map.Entry<String, Object> e : config.getMainPropertyValues().entrySet()) {
if (e.getValue() == null) {
continue;
}
switch (e.getKey()) {
case DBConstants.PROP_HOST -> dsConfig.setHostName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_PORT -> dsConfig.setHostPort(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_DATABASE -> dsConfig.setDatabaseName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_SERVER -> dsConfig.setServerName(CommonUtils.toString(e.getValue()));
default -> throw new IllegalStateException("Unexpected value: " + e.getKey());
}
}
return;
}
if (config.getHost() != null) {
dsConfig.setHostName(config.getHost());
}
if (config.getPort() != null) {
dsConfig.setHostPort(config.getPort());
}
if (config.getDatabaseName() != null) {
dsConfig.setDatabaseName(config.getDatabaseName());
}
if (config.getServerName() != null) {
dsConfig.setServerName(config.getServerName());
}
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials
) {
saveAuthProperties(dataSourceContainer, configuration, authProperties, saveCredentials, sharedCredentials, false);
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials,
boolean isTest
) {
dataSourceContainer.setSavePassword(saveCredentials);
dataSourceContainer.setSharedCredentials(sharedCredentials);
if (!saveCredentials) {
// Reset credentials
if (authProperties == null) {
authProperties = new LinkedHashMap<>();
}
authProperties.replace(AuthModelDatabaseNativeCredentials.PROP_USER_PASSWORD, null);
dataSourceContainer.resetPassword();
} else {
if (authProperties == null) {
// No changes
return;
}
}
{
// Read save credentials
DBAAuthCredentials credentials = configuration.getAuthModel().loadCredentials(dataSourceContainer, configuration);
if (isTest) {
var currentAuthProps = new HashMap<String, String>();
for (Map.Entry<String, Object> stringObjectEntry : authProperties.entrySet()) {
var value = stringObjectEntry.getValue() == null ? null : stringObjectEntry.getValue().toString();
currentAuthProps.put(stringObjectEntry.getKey(), value);
}
configuration.setAuthProperties(currentAuthProps);
}
if (!authProperties.isEmpty()) {
WebDataSourceUtils.updateCredentialsFromProperties(credentials, authProperties);
}
configuration.getAuthModel().saveCredentials(dataSourceContainer, configuration, credentials);
}
}
public static DBNBrowseSettings parseNavigatorSettings(Map<String, Object> settingsMap) {
return gson.fromJson(
gson.toJsonTree(settingsMap), DataSourceNavigatorSettings.class);
@@ -310,13 +84,6 @@ public class WebServiceUtils extends WebCommonUtils {
WebActionParameters.saveToSession(webSession, actionParameters);
}
public static String getConnectionContainerInfo(DBPDataSourceContainer container) {
if (container == null) {
return null;
}
return container.getName() + " [" + container.getId() + "]";
}
public static void refreshDatabases(WebSession session, String projectId) throws DBWebException {
DBNProject projectNode = session.getNavigatorModelOrThrow().getRoot().getProjectNode(session.getProjectById(projectId));
if (projectNode != null) {
@@ -21,7 +21,6 @@ import io.cloudbeaver.model.app.ServletApplication;
import io.cloudbeaver.model.app.WebAppConfiguration;
import io.cloudbeaver.model.app.WebServerConfiguration;
import io.cloudbeaver.registry.WebDriverRegistry;
import io.cloudbeaver.service.ConnectionController;
import org.jkiss.code.NotNull;
import java.net.InetAddress;
@@ -53,6 +52,4 @@ public interface WebApplication extends ServletApplication {
WebServerConfig getWebServerConfig();
ConnectionController getConnectionController();
}
@@ -1,99 +0,0 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.service;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebObjectId;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import java.util.List;
import java.util.Map;
public interface ConnectionController {
DBPDataSourceContainer createDataSourceContainer(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull WebConnectionConfig connectionConfig
) throws DBWebException;
WebConnectionInfo createConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
DBPDataSourceRegistry sessionRegistry,
DBPDataSourceContainer newDataSource
) throws DBWebException;
DBPDataSourceContainer getDatasourceConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull WebConnectionConfig connectionConfig) throws DBWebException;
WebConnectionInfo updateConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig config,
DBPDataSourceContainer dataSource,
DBPDataSourceRegistry sessionRegistry
) throws DBWebException;
boolean deleteConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull String connectionId) throws DBWebException;
DataSourceDescriptor prepareTestConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig) throws DBWebException;
WebConnectionInfo testConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig,
DataSourceDescriptor dataSource
) throws DBWebException;
WebConnectionInfo getConnectionState(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId
) throws DBWebException;
WebConnectionInfo initConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId,
@NotNull Map<String, Object> authProperties,
@Nullable List<WebNetworkHandlerConfigInput> networkCredentials,
boolean saveCredentials,
boolean sharedCredentials,
@Nullable String selectedSecretId
) throws DBWebException;
void validateConnection(DBPDataSourceContainer dataSourceContainer) throws DBWebException;
}
@@ -1,496 +0,0 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.service;
import io.cloudbeaver.*;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.exec.DBCConnectException;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.DBWHandlerType;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.secret.DBSSecretValue;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.dbeaver.runtime.jobs.ConnectionTestJob;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;
import java.util.List;
import java.util.Map;
public class ConnectionControllerCE implements ConnectionController {
private static final Log log = Log.getLog(ConnectionController.class);
@Override
public DBPDataSourceContainer createDataSourceContainer(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig
) throws DBWebException {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
var rmProject = project.getRMProject();
if (rmProject.getType() == RMProjectType.USER
&& !webSession.hasPermission(DBWConstants.PERMISSION_ADMIN)
&& !ServletAppUtils.getServletApplication().getAppConfiguration().isSupportsCustomConnections()
) {
throw new DBWebException("New connection create is restricted by server configuration");
}
webSession.addInfoMessage("Create new connection");
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
DBPDataSourceContainer newDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig,
sessionRegistry);
if (CommonUtils.isEmpty(newDataSource.getName())) {
newDataSource.setName(CommonUtils.notNull(connectionConfig.getName(), "NewConnection"));
}
return newDataSource;
}
@Override
@NotNull
public WebConnectionInfo createConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
DBPDataSourceRegistry sessionRegistry,
DBPDataSourceContainer newDataSource
) throws DBWebException {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
try {
sessionRegistry.addDataSource(newDataSource);
sessionRegistry.checkForErrors();
} catch (DBException e) {
sessionRegistry.removeDataSource(newDataSource);
throw new DBWebException("Failed to create connection", e);
}
WebConnectionInfo connectionInfo = project.addConnection(newDataSource);
webSession.addInfoMessage("New connection was created - " + WebServiceUtils.getConnectionContainerInfo(
newDataSource));
log.info(String.format(
"New connection was created: [info=%s, user=%s]",
WebServiceUtils.getConnectionContainerInfo(newDataSource),
webSession.getUserId()
));
return connectionInfo;
}
@Override
public DBPDataSourceContainer getDatasourceConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig config
) throws DBWebException {
// Do not check for custom connection option. Already created connections can be edited.
// Also template connections can be edited
// if (!CBApplication.getInstance().getAppConfiguration().isSupportsCustomConnections()) {
// throw new DBWebException("Connection edit is restricted by server configuration");
// }
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, config.getConnectionId());
DBPDataSourceContainer dataSource = connectionInfo.getDataSourceContainer();
webSession.addInfoMessage("Update connection - " + WebServiceUtils.getConnectionContainerInfo(dataSource));
getOldDataSource(dataSource);
if (!CommonUtils.isEmpty(config.getName())) {
dataSource.setName(config.getName());
}
if (config.getDescription() != null) {
dataSource.setDescription(config.getDescription());
}
WebSessionProjectImpl project = getProjectById(webSession, projectId);
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
dataSource.setFolder(config.getFolder() != null ? sessionRegistry.getFolder(config.getFolder()) : null);
if (config.isDefaultAutoCommit() != null) {
dataSource.setDefaultAutoCommit(config.isDefaultAutoCommit());
}
dataSource.setConnectionReadOnly(config.isReadOnly());
WebServiceUtils.setConnectionConfiguration(dataSource.getDriver(),
dataSource.getConnectionConfiguration(),
config);
// we should check that the config has changed but not check for password changes
dataSource.setSharedCredentials(config.isSharedCredentials());
dataSource.setSavePassword(config.isSaveCredentials());
boolean sharedCredentials = isSharedCredentials(dataSource);
if (sharedCredentials) {
//we must notify about the shared password change
WebServiceUtils.saveAuthProperties(
dataSource,
dataSource.getConnectionConfiguration(),
config.getCredentials(),
config.isSaveCredentials(),
config.isSharedCredentials()
);
}
connectionInfo.setCredentialsSavedInSession(null);
// same here
return dataSource;
}
private static boolean isSharedCredentials(DBPDataSourceContainer dataSource) {
return dataSource.isSharedCredentials() || !dataSource.getProject()
.isUseSecretStorage() && dataSource.isSavePassword();
}
private static DataSourceDescriptor getOldDataSource(DBPDataSourceContainer dataSource) {
DataSourceDescriptor oldDataSource;
oldDataSource = dataSource.getRegistry().createDataSource(dataSource);
oldDataSource.setId(dataSource.getId());
return oldDataSource;
}
@Override
public WebConnectionInfo updateConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig config,
DBPDataSourceContainer dataSource,
DBPDataSourceRegistry sessionRegistry
) throws DBWebException {
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, config.getConnectionId());
if (!isSharedCredentials(dataSource)) {
// secret controller is responsible for notification, password changes applied after checks
WebServiceUtils.saveAuthProperties(
dataSource,
dataSource.getConnectionConfiguration(),
config.getCredentials(),
config.isSaveCredentials(),
config.isSharedCredentials()
);
}
try {
sessionRegistry.updateDataSource(dataSource);
sessionRegistry.checkForErrors();
} catch (DBException e) {
throw new DBWebException("Failed to update connection", e);
}
log.info(String.format(
"Connection updated: [info=%s, userId=%s]",
WebServiceUtils.getConnectionContainerInfo(dataSource),
webSession.getUser()
));
return connectionInfo;
}
@Override
public boolean deleteConnection(
@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId
) throws DBWebException {
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
if (connectionInfo.getDataSourceContainer().getProject() != getProjectById(webSession, projectId)) {
throw new DBWebException("Global connection '" + connectionInfo.getName() + "' configuration cannot be deleted");
}
webSession.addInfoMessage("Delete connection - " +
WebServiceUtils.getConnectionContainerInfo(connectionInfo.getDataSourceContainer()));
closeAndDeleteConnection(webSession, projectId, connectionId, true);
log.info(String.format(
"Connection deleted: [info=%s, userId=%s]",
WebServiceUtils.getConnectionContainerInfo(connectionInfo.getDataSourceContainer()),
webSession.getUserId()
));
return true;
}
@Override
public DataSourceDescriptor prepareTestConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig
) throws DBWebException {
String connectionId = connectionConfig.getConnectionId();
connectionConfig.setSaveCredentials(true); // It is used in createConnectionFromConfig
DataSourceDescriptor dataSource = (DataSourceDescriptor) WebDataSourceUtils.getLocalOrGlobalDataSource(
webSession, projectId, connectionId);
validateConnection(dataSource);
WebProjectImpl project = getProjectById(webSession, projectId);
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
DataSourceDescriptor testDataSource;
if (dataSource != null) {
try {
// Check that creds are saved to trigger secrets resolve
dataSource.isCredentialsSaved();
} catch (DBException e) {
throw new DBWebException("Can't determine whether datasource credentials are saved", e);
}
testDataSource = (DataSourceDescriptor) dataSource.createCopy(dataSource.getRegistry());
WebServiceUtils.setConnectionConfiguration(
testDataSource.getDriver(),
testDataSource.getConnectionConfiguration(),
connectionConfig
);
if (connectionConfig.getSelectedSecretId() != null) {
try {
dataSource.listSharedCredentials()
.stream()
.filter(secret -> connectionConfig.getSelectedSecretId().equals(secret.getSubjectId()))
.findFirst()
.ifPresent(testDataSource::setSelectedSharedCredentials);
} catch (DBException e) {
throw new DBWebException("Failed to load secret value: " + connectionConfig.getSelectedSecretId());
}
}
WebServiceUtils.saveAuthProperties(
testDataSource,
testDataSource.getConnectionConfiguration(),
connectionConfig.getCredentials(),
true,
false,
true
);
} else {
testDataSource = (DataSourceDescriptor) WebServiceUtils.createConnectionFromConfig(connectionConfig,
sessionRegistry);
}
return testDataSource;
}
@Override
@NotNull
public WebConnectionInfo testConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig,
DataSourceDescriptor testDataSource
) throws DBWebException {
validateDriverLibrariesPresence(testDataSource);
webSession.provideAuthParameters(webSession.getProgressMonitor(),
testDataSource,
testDataSource.getConnectionConfiguration());
testDataSource.setSavePassword(true); // We need for test to avoid password callback
if (DataSourceDescriptor.class.isAssignableFrom(testDataSource.getClass())) {
testDataSource.setAccessCheckRequired(!webSession.hasPermission(DBWConstants.PERMISSION_ADMIN));
}
try {
ConnectionTestJob ct = new ConnectionTestJob(testDataSource, param -> {
});
ct.run(webSession.getProgressMonitor());
if (ct.getConnectError() != null) {
if (ct.getConnectError() instanceof DBCConnectException error) {
Throwable rootCause = CommonUtils.getRootCause(error);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(testDataSource);
}
}
throw new DBWebException("Connection failed", ct.getConnectError());
}
WebConnectionInfo connectionInfo = new WebConnectionInfo(webSession, testDataSource);
connectionInfo.setConnectError(ct.getConnectError());
connectionInfo.setServerVersion(ct.getServerVersion());
connectionInfo.setClientVersion(ct.getClientVersion());
connectionInfo.setConnectTime(RuntimeUtils.formatExecutionTime(ct.getConnectTime()));
return connectionInfo;
} catch (DBException e) {
throw new DBWebException("Error connecting to database", e);
}
}
private WebSessionProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException {
WebSessionProjectImpl project = webSession.getProjectById(projectId);
if (project == null) {
throw new DBWebException("Project '" + projectId + "' not found");
}
return project;
}
@NotNull
private WebConnectionInfo closeAndDeleteConnection(
@NotNull WebSession webSession,
@NotNull String projectId,
@NotNull String connectionId,
boolean forceDelete
) throws DBWebException {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
WebConnectionInfo connectionInfo = project.getWebConnectionInfo(connectionId);
DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer();
boolean disconnected = WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer);
if (forceDelete) {
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
registry.removeDataSource(dataSourceContainer);
try {
registry.checkForErrors();
} catch (DBException e) {
try {
registry.addDataSource(dataSourceContainer);
} catch (DBException ex) {
log.error("Error re-adding after delete attempt", e);
}
throw new DBWebException("Failed to delete connection", e);
}
project.removeConnection(dataSourceContainer);
} else {
// Just reset saved credentials
connectionInfo.clearCache();
}
return connectionInfo;
}
@Override
public WebConnectionInfo getConnectionState(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId
) throws DBWebException {
return WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
}
@Override
public WebConnectionInfo initConnection(@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId, @NotNull Map<String, Object> authProperties, @Nullable List<WebNetworkHandlerConfigInput> networkCredentials, boolean saveCredentials, boolean sharedCredentials, @Nullable String selectedSecretId) throws DBWebException {
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
connectionInfo.setSavedCredentials(authProperties, networkCredentials);
var dataSourceContainer = connectionInfo.getDataSourceContainer();;
validateConnection(dataSourceContainer);
if (dataSourceContainer.isConnected()) {
throw new DBWebException("Datasource '" + dataSourceContainer.getName() + "' is already connected");
}
if (dataSourceContainer.isSharedCredentials() && selectedSecretId != null) {
List<DBSSecretValue> allSecrets;
try {
allSecrets = dataSourceContainer.listSharedCredentials();
} catch (DBException e) {
throw new DBWebException("Error loading connection secret", e);
}
DBSSecretValue selectedSecret =
allSecrets.stream()
.filter(secret -> selectedSecretId.equals(secret.getUniqueId()))
.findFirst().orElse(null);
if (selectedSecret == null) {
throw new DBWebException("Secret not found:" + selectedSecretId);
}
dataSourceContainer.setSelectedSharedCredentials(selectedSecret);
}
boolean oldSavePassword = dataSourceContainer.isSavePassword();
DBRProgressMonitor monitor = webSession.getProgressMonitor();
validateDriverLibrariesPresence(dataSourceContainer);
try {
boolean connect = dataSourceContainer.connect(monitor, true, false);
} catch (Exception e) {
if (e instanceof DBCConnectException) {
Throwable rootCause = CommonUtils.getRootCause(e);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(dataSourceContainer);
}
}
throw new DBWebException("Error connecting to database", e);
} finally {
dataSourceContainer.setSavePassword(oldSavePassword);
connectionInfo.clearCache();
}
// Mark all specified network configs as saved
boolean[] saveConfig = new boolean[1];
if (networkCredentials != null) {
networkCredentials.forEach(c -> {
if (CommonUtils.toBoolean(c.isSavePassword())) {
DBWHandlerConfiguration handlerCfg = dataSourceContainer.getConnectionConfiguration()
.getHandler(c.getId());
if (handlerCfg != null &&
// check username param only for ssh config
!(CommonUtils.isEmpty(c.getUserName()) && CommonUtils.equalObjects(handlerCfg.getType(),
DBWHandlerType.TUNNEL))
) {
WebDataSourceUtils.updateHandlerCredentials(handlerCfg, c);
handlerCfg.setSavePassword(true);
saveConfig[0] = true;
}
}
});
}
if (saveCredentials) {
// Save all passed credentials in the datasource container
WebServiceUtils.saveAuthProperties(
dataSourceContainer,
dataSourceContainer.getConnectionConfiguration(),
authProperties,
true,
sharedCredentials
);
var project = dataSourceContainer.getProject();
if (project.isUseSecretStorage()) {
try {
dataSourceContainer.persistSecrets(
DBSSecretController.getProjectSecretController(dataSourceContainer.getProject())
);
} catch (DBException e) {
throw new DBWebException("Failed to save credentials", e);
}
}
WebDataSourceUtils.saveCredentialsInDataSource(connectionInfo,
dataSourceContainer,
dataSourceContainer.getConnectionConfiguration());
saveConfig[0] = true;
}
if (WebServiceUtils.isGlobalProject(dataSourceContainer.getProject())) {
// Do not flush config for global project (only admin can do it - CB-2415)
if (saveCredentials) {
connectionInfo.setCredentialsSavedInSession(true);
}
saveConfig[0] = false;
}
if (saveConfig[0]) {
dataSourceContainer.persistConfiguration();
}
return connectionInfo;
}
@Override
public void validateConnection(DBPDataSourceContainer dataSourceContainer) throws DBWebException {
}
private void validateDriverLibrariesPresence(@NotNull DBPDataSourceContainer container) throws DBWebException {
if (!DBWorkbench.isDistributed() && container.getDriver().getDriverLoader(container).needsExternalDependencies()) {
throwDriverNotFoundException(container);
}
}
@NotNull
private static String throwDriverNotFoundException(@NotNull DBPDataSourceContainer container) throws DBWebException {
throw new DBWebException("Driver files for %s are not found. Please ask the administrator to download it."
.formatted(container.getDriver().getName()));
}
}
@@ -130,31 +130,37 @@ public interface DBWServiceCore extends DBWService {
WebConnectionInfo createConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull WebConnectionConfig connectionConfig
@NotNull Map<String, Object> connectionConfig
) throws DBWebException;
@WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT})
WebConnectionInfo updateConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull WebConnectionConfig connectionConfig) throws DBWebException;
@NotNull Map<String, Object> connectionConfig
) throws DBWebException;
@WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT})
boolean deleteConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull String connectionId) throws DBWebException;
@NotNull String connectionId
) throws DBWebException;
@WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT})
WebConnectionInfo copyConnectionFromNode(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull String nodePath,
@NotNull WebConnectionConfig config) throws DBWebException;
@NotNull Map<String, Object> connectionConfig
) throws DBWebException;
@WebAction
WebConnectionInfo testConnection(
@NotNull WebSession webSession, @Nullable String projectId, @NotNull WebConnectionConfig connectionConfig) throws DBWebException;
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull Map<String, Object> connectionConfig
) throws DBWebException;
@WebAction
WebNetworkEndpointInfo testNetworkHandler(@NotNull WebSession webSession, @NotNull WebNetworkHandlerConfigInput nhConfig) throws DBWebException;
@@ -17,11 +17,9 @@
package io.cloudbeaver.service.core;
import graphql.TypeResolutionEnvironment;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.idl.TypeRuntimeWiring;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.WebAppSessionManager;
@@ -105,16 +103,20 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
.dataFetcher("changeSessionLanguage", env -> getService(env).changeSessionLanguage(getWebSession(env), env.getArgument("locale")))
.dataFetcher("createConnection", env -> getService(env).createConnection(
getWebSession(env), getProjectReference(env), getConnectionConfig(env)))
getWebSession(env), getProjectReference(env), env.getArgument("config"))
)
.dataFetcher("updateConnection", env -> getService(env).updateConnection(
getWebSession(env), getProjectReference(env), getConnectionConfig(env)))
getWebSession(env), getProjectReference(env), env.getArgument("config"))
)
.dataFetcher("deleteConnection", env -> getService(env).deleteConnection(
getWebSession(env), getProjectReference(env), env.getArgument("id")))
.dataFetcher("copyConnectionFromNode", env -> getService(env).copyConnectionFromNode(
getWebSession(env),
getProjectReference(env),
env.getArgument("nodePath"),
new WebConnectionConfig(env.getArgument("config"))))
env.getArgument("config")
)
)
.dataFetcher("initConnection", env -> {
List<Map<String, Object>> networkCredentials = env.getArgument("networkCredentials");
List<WebNetworkHandlerConfigInput> nhc = null;
@@ -134,7 +136,7 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
}
)
.dataFetcher("testConnection", env -> getService(env).testConnection(
getWebSession(env), getProjectReference(env), getConnectionConfig(env)
getWebSession(env), getProjectReference(env), env.getArgument("config")
))
.dataFetcher("testNetworkHandler", env -> getService(env).testNetworkHandler(
getWebSession(env), new WebNetworkHandlerConfigInput(env.getArgument("config"))
@@ -177,8 +179,4 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
);
}
private WebConnectionConfig getConnectionConfig(DataFetchingEnvironment env) {
return new WebConnectionConfig(env.getArgument("config"));
}
}
@@ -44,23 +44,29 @@ import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.model.exec.DBCConnectException;
import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
import org.jkiss.dbeaver.model.navigator.DBNDataSource;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.DBWHandlerType;
import org.jkiss.dbeaver.model.net.DBWNetworkHandler;
import org.jkiss.dbeaver.model.net.DBWTunnel;
import org.jkiss.dbeaver.model.net.ssh.SSHSession;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.secret.DBSSecretValue;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
import org.jkiss.dbeaver.registry.settings.ProductSettingsRegistry;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.dbeaver.runtime.jobs.ConnectionTestJob;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;
import java.util.*;
@@ -280,7 +286,7 @@ public class WebServiceCore implements DBWServiceCore {
@Nullable String projectId,
@NotNull String connectionId
) throws DBWebException {
return WebAppUtils.getWebApplication().getConnectionController().getConnectionState(webSession, projectId, connectionId);
return WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
}
@@ -295,65 +301,137 @@ public class WebServiceCore implements DBWServiceCore {
boolean sharedCredentials,
@Nullable String selectedSecretId
) throws DBWebException {
return WebAppUtils.getWebApplication().getConnectionController().initConnection(webSession, projectId,
connectionId, authProperties, networkCredentials, saveCredentials, sharedCredentials, selectedSecretId);
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
connectionInfo.validateConnection();
connectionInfo.setSavedCredentials(authProperties, networkCredentials);
var dataSourceContainer = connectionInfo.getDataSourceContainer();
if (dataSourceContainer.isConnected()) {
throw new DBWebException("Datasource '" + dataSourceContainer.getName() + "' is already connected");
}
if (dataSourceContainer.isSharedCredentials() && selectedSecretId != null) {
List<DBSSecretValue> allSecrets;
try {
allSecrets = dataSourceContainer.listSharedCredentials();
} catch (DBException e) {
throw new DBWebException("Error loading connection secret", e);
}
DBSSecretValue selectedSecret =
allSecrets.stream()
.filter(secret -> selectedSecretId.equals(secret.getUniqueId()))
.findFirst().orElse(null);
if (selectedSecret == null) {
throw new DBWebException("Secret not found:" + selectedSecretId);
}
dataSourceContainer.setSelectedSharedCredentials(selectedSecret);
}
boolean oldSavePassword = dataSourceContainer.isSavePassword();
DBRProgressMonitor monitor = webSession.getProgressMonitor();
validateDriverLibrariesPresence(dataSourceContainer);
try {
boolean connect = dataSourceContainer.connect(monitor, true, false);
} catch (Exception e) {
if (e instanceof DBCConnectException) {
Throwable rootCause = CommonUtils.getRootCause(e);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(dataSourceContainer);
}
}
throw new DBWebException("Error connecting to database", e);
} finally {
dataSourceContainer.setSavePassword(oldSavePassword);
connectionInfo.clearCache();
}
// Mark all specified network configs as saved
boolean[] saveConfig = new boolean[1];
if (networkCredentials != null) {
networkCredentials.forEach(c -> {
if (CommonUtils.toBoolean(c.isSavePassword())) {
DBWHandlerConfiguration handlerCfg = dataSourceContainer.getConnectionConfiguration()
.getHandler(c.getId());
if (handlerCfg != null &&
// check username param only for ssh config
!(CommonUtils.isEmpty(c.getUserName()) && CommonUtils.equalObjects(
handlerCfg.getType(),
DBWHandlerType.TUNNEL
))
) {
WebDataSourceUtils.updateHandlerCredentials(handlerCfg, c);
handlerCfg.setSavePassword(true);
saveConfig[0] = true;
}
}
});
}
if (saveCredentials) {
// Save all passed credentials in the datasource container
WebDataSourceUtils.saveAuthProperties(
dataSourceContainer,
dataSourceContainer.getConnectionConfiguration(),
authProperties,
true,
sharedCredentials
);
var project = dataSourceContainer.getProject();
if (project.isUseSecretStorage()) {
try {
dataSourceContainer.persistSecrets(
DBSSecretController.getProjectSecretController(dataSourceContainer.getProject())
);
} catch (DBException e) {
throw new DBWebException("Failed to save credentials", e);
}
}
WebDataSourceUtils.saveCredentialsInDataSource(
connectionInfo,
dataSourceContainer,
dataSourceContainer.getConnectionConfiguration()
);
saveConfig[0] = true;
}
if (WebServiceUtils.isGlobalProject(dataSourceContainer.getProject())) {
// Do not flush config for global project (only admin can do it - CB-2415)
if (saveCredentials) {
connectionInfo.setCredentialsSavedInSession(true);
}
saveConfig[0] = false;
}
if (saveConfig[0]) {
dataSourceContainer.persistConfiguration();
}
return connectionInfo;
}
@Override
public WebConnectionInfo createConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig
@NotNull Map<String, Object> connectionConfig
) throws DBWebException {
DBPDataSourceContainer dataSourceContainer =
WebAppUtils.getWebApplication().getConnectionController().createDataSourceContainer(webSession, projectId, connectionConfig);
return WebAppUtils.getWebApplication().getConnectionController().createConnection(
webSession,
projectId,
dataSourceContainer.getRegistry(),
dataSourceContainer
);
return getProjectById(webSession, projectId).createConnection(connectionConfig);
}
@Override
public WebConnectionInfo updateConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig config
@NotNull Map<String, Object> connectionConfig
) throws DBWebException {
DBPDataSourceContainer dataSourceContainer =
WebAppUtils.getWebApplication().getConnectionController().getDatasourceConnection(webSession, projectId, config);
return WebAppUtils.getWebApplication().getConnectionController().updateConnection(
webSession,
projectId,
config,
dataSourceContainer,
dataSourceContainer.getRegistry()
);
}
private WSDataSourceProperty getDatasourceEventProperty(
DataSourceDescriptor oldDataSource,
DBPDataSourceContainer dataSource
) {
if (!oldDataSource.equalConfiguration((DataSourceDescriptor) dataSource)) {
return WSDataSourceProperty.CONFIGURATION;
}
var nameChanged = !CommonUtils.equalObjects(oldDataSource.getName(), dataSource.getName());
var descriptionChanged = !CommonUtils.equalObjects(oldDataSource.getDescription(), dataSource.getDescription());
if (nameChanged && descriptionChanged) {
return WSDataSourceProperty.CONFIGURATION;
}
return nameChanged ? WSDataSourceProperty.NAME : WSDataSourceProperty.CONFIGURATION;
return getProjectById(webSession, projectId).updateConnection(connectionConfig);
}
@Override
public boolean deleteConnection(
@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId
) throws DBWebException {
return WebAppUtils.getWebApplication().getConnectionController().deleteConnection(webSession, projectId, connectionId);
return getProjectById(webSession, projectId).deleteConnection(connectionId);
}
@@ -362,7 +440,7 @@ public class WebServiceCore implements DBWServiceCore {
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String nodePath,
@NotNull WebConnectionConfig config
@NotNull Map<String, Object> connectionConfig
) throws DBWebException {
try {
DBNModel navigatorModel = webSession.getNavigatorModelOrThrow();
@@ -373,19 +451,20 @@ public class WebServiceCore implements DBWServiceCore {
if (srcNode == null) {
throw new DBException("Node '" + nodePath + "' not found");
}
if (!(srcNode instanceof DBNDataSource)) {
if (!(srcNode instanceof DBNDataSource dbnDataSource)) {
throw new DBException("Node '" + nodePath + "' is not a datasource node");
}
DBPDataSourceContainer dataSourceTemplate = ((DBNDataSource) srcNode).getDataSourceContainer();
DBPDataSourceContainer dataSourceTemplate = dbnDataSource.getDataSourceContainer();
DBPDataSourceContainer newDataSource = dataSourceRegistry.createDataSource(dataSourceTemplate);
DataSourceDescriptor newDataSource = dataSourceRegistry.createDataSource(dataSourceTemplate);
ServletApplication app = ServletAppUtils.getServletApplication();
if (app instanceof WebApplication webApplication) {
((DataSourceDescriptor) newDataSource).setNavigatorSettings(
webApplication.getAppConfiguration().getDefaultNavigatorSettings());
newDataSource.setNavigatorSettings(webApplication.getAppConfiguration().getDefaultNavigatorSettings());
}
WebConnectionConfig config = project.getConnectionConfigInput(connectionConfig);
// Copy props from config
if (!CommonUtils.isEmpty(config.getName())) {
newDataSource.setName(config.getName());
@@ -407,12 +486,84 @@ public class WebServiceCore implements DBWServiceCore {
public WebConnectionInfo testConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig
@NotNull Map<String, Object> connectionConfig
) throws DBWebException {
DataSourceDescriptor dataSourceDescriptor = WebAppUtils.getWebApplication().getConnectionController()
.prepareTestConnection(webSession, projectId, connectionConfig);
return WebAppUtils.getWebApplication().getConnectionController()
.testConnection(webSession, projectId, connectionConfig, dataSourceDescriptor);
WebSessionProjectImpl project = getProjectById(webSession, projectId);
WebConnectionConfig configInput = project.getConnectionConfigInput(connectionConfig);
DataSourceDescriptor dataSource = (DataSourceDescriptor) WebDataSourceUtils.getLocalOrGlobalDataSource(
webSession, projectId, configInput.getConnectionId());
DataSourceDescriptor testDataSource;
if (dataSource != null) {
try {
// Check that creds are saved to trigger secrets resolve
dataSource.isCredentialsSaved();
} catch (DBException e) {
throw new DBWebException("Can't determine whether datasource credentials are saved", e);
}
testDataSource = (DataSourceDescriptor) dataSource.createCopy(dataSource.getRegistry());
WebDataSourceUtils.setConnectionConfiguration(
testDataSource.getDriver(),
testDataSource.getConnectionConfiguration(),
configInput
);
if (configInput.getSelectedSecretId() != null) {
try {
dataSource.listSharedCredentials()
.stream()
.filter(secret -> configInput.getSelectedSecretId().equals(secret.getSubjectId()))
.findFirst()
.ifPresent(testDataSource::setSelectedSharedCredentials);
} catch (DBException e) {
throw new DBWebException("Failed to load secret value: " + configInput.getSelectedSecretId());
}
}
WebDataSourceUtils.saveAuthProperties(
testDataSource,
testDataSource.getConnectionConfiguration(),
configInput.getCredentials(),
true,
false,
true
);
} else {
testDataSource = project.getDataSourceContainerFromInput(connectionConfig);
}
validateDriverLibrariesPresence(testDataSource);
webSession.provideAuthParameters(
webSession.getProgressMonitor(),
testDataSource,
testDataSource.getConnectionConfiguration()
);
testDataSource.setSavePassword(true); // We need for test to avoid password callback
testDataSource.setAccessCheckRequired(!webSession.hasPermission(DBWConstants.PERMISSION_ADMIN));
try {
ConnectionTestJob ct = new ConnectionTestJob(
testDataSource, param -> {
}
);
ct.run(webSession.getProgressMonitor());
if (ct.getConnectError() != null) {
if (ct.getConnectError() instanceof DBCConnectException error) {
Throwable rootCause = CommonUtils.getRootCause(error);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(testDataSource);
}
}
throw new DBWebException("Connection failed", ct.getConnectError());
}
WebConnectionInfo connectionInfo = project.createConnectionInfo(testDataSource);
connectionInfo.setConnectError(ct.getConnectError());
connectionInfo.setServerVersion(ct.getServerVersion());
connectionInfo.setClientVersion(ct.getClientVersion());
connectionInfo.setConnectTime(RuntimeUtils.formatExecutionTime(ct.getConnectTime()));
return connectionInfo;
} catch (DBException e) {
throw new DBWebException("Error connecting to database", e);
}
}
@Override
@@ -471,42 +622,15 @@ public class WebServiceCore implements DBWServiceCore {
@Override
public WebConnectionInfo closeConnection(
@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId
) throws DBWebException {
return closeAndDeleteConnection(webSession, projectId, connectionId, false);
}
@NotNull
private WebConnectionInfo closeAndDeleteConnection(
@NotNull WebSession webSession,
@NotNull String projectId,
@NotNull String connectionId,
boolean forceDelete
@Nullable String projectId,
@NotNull String connectionId
) throws DBWebException {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
WebConnectionInfo connectionInfo = project.getWebConnectionInfo(connectionId);
DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer();
boolean disconnected = WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer);
if (forceDelete) {
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
registry.removeDataSource(dataSourceContainer);
try {
registry.checkForErrors();
} catch (DBException e) {
try {
registry.addDataSource(dataSourceContainer);
} catch (DBException ex) {
log.error("Error re-adding after delete attempt", e);
}
throw new DBWebException("Failed to delete connection", e);
}
project.removeConnection(dataSourceContainer);
} else {
// Just reset saved credentials
connectionInfo.clearCache();
}
return connectionInfo;
}
@@ -611,11 +735,24 @@ public class WebServiceCore implements DBWServiceCore {
return new WebGroupPropertiesInfo<>(webSession, ProductSettingsRegistry.getInstance().getSettings());
}
private WebSessionProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException {
@NotNull
private WebSessionProjectImpl getProjectById(@NotNull WebSession webSession, @Nullable String projectId) throws DBWebException {
WebSessionProjectImpl project = webSession.getProjectById(projectId);
if (project == null) {
throw new DBWebException("Project '" + projectId + "' not found");
}
return project;
}
private void validateDriverLibrariesPresence(@NotNull DBPDataSourceContainer container) throws DBWebException {
if (!DBWorkbench.isDistributed() && container.getDriver().getDriverLoader(container).needsExternalDependencies()) {
throwDriverNotFoundException(container);
}
}
@NotNull
private static String throwDriverNotFoundException(@NotNull DBPDataSourceContainer container) throws DBWebException {
throw new DBWebException("Driver files for %s are not found. Please ask the administrator to download it."
.formatted(container.getDriver().getName()));
}
}
@@ -35,6 +35,7 @@ import io.cloudbeaver.service.DBWServiceServerConfigurator;
import io.cloudbeaver.service.admin.*;
import io.cloudbeaver.service.security.SMUtils;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
@@ -701,7 +702,7 @@ public class WebServiceAdmin implements DBWServiceAdmin {
// driver is removed from disabled list
// we need to enable if it is embedded
try {
DBPDriver driver = WebServiceUtils.getDriverById(driverId);
DBPDriver driver = WebDataSourceUtils.getDriverById(driverId);
if (driver.isEmbedded()) {
enabledIds.add(driverId);
}