CB-5574. Added new api for get manager, added flap in server configur… (#3161)

This commit is contained in:
DenisSinelnikov
2025-01-22 15:12:45 +00:00
committed by GitHub
parent 82753268e6
commit cd7dcb40c8
26 changed files with 789 additions and 333 deletions
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
* 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.
@@ -44,6 +44,12 @@ public class WebPropertyInfo {
private DBPPropertySource propertySource;
private boolean showProtected;
private Object[] validValues;
private String[] supportedConfigurationTypes = new String[0];
private Object defaultValue;
public WebPropertyInfo(WebSession session, DBPPropertyDescriptor property, DBPPropertySource propertySource) {
this.session = session;
this.property = property;
@@ -123,7 +129,7 @@ public class WebPropertyInfo {
@Property
public Object getDefaultValue() throws DBException {
var defaultValue = property.getDefaultValue();
var defaultValue = property.getDefaultValue() == null ? this.defaultValue : property.getDefaultValue();
return defaultValue == null ? getValue() : defaultValue;
}
@@ -154,9 +160,9 @@ public class WebPropertyInfo {
}
return validValues;
}
return null;
return validValues;
}
return null;
return validValues;
}
@Property
@@ -172,7 +178,7 @@ public class WebPropertyInfo {
.map(DBPDriverConfigurationType::toString)
.toArray(String[]::new);
}
return new String[0];
return supportedConfigurationTypes;
}
@Property
@@ -252,4 +258,20 @@ public class WebPropertyInfo {
}
return null;
}
//TODO: delete after refactoring on front-end
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
//TODO: delete after refactoring on front-end
public void setValidValues(Object[] validValues) {
this.validValues = validValues;
}
//TODO: delete after refactoring on front-end
public void setSupportedConfigurationTypes(String[] supportedConfigurationTypes) {
this.supportedConfigurationTypes = supportedConfigurationTypes;
}
}
@@ -31,6 +31,7 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration
protected final Map<String, Object> plugins;
protected String defaultUserTeam = DEFAULT_APP_ANONYMOUS_TEAM_NAME;
protected boolean resourceManagerEnabled;
protected boolean secretManagerEnabled;
protected boolean showReadOnlyConnectionInfo;
protected String[] enabledFeatures;
protected String[] disabledBetaFeatures;
@@ -42,6 +43,7 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration
this.enabledFeatures = null;
this.disabledBetaFeatures = new String[0];
this.showReadOnlyConnectionInfo = false;
this.secretManagerEnabled = false;
}
public BaseWebAppConfiguration(BaseWebAppConfiguration src) {
@@ -51,6 +53,7 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration
this.enabledFeatures = src.enabledFeatures;
this.disabledBetaFeatures = src.disabledBetaFeatures;
this.showReadOnlyConnectionInfo = src.showReadOnlyConnectionInfo;
this.secretManagerEnabled = src.secretManagerEnabled;
}
@Override
@@ -84,6 +87,11 @@ public abstract class BaseWebAppConfiguration implements ServletAppConfiguration
return resourceManagerEnabled;
}
@Override
public boolean isSecretManagerEnabled() {
return secretManagerEnabled;
}
@Override
public boolean isFeatureEnabled(String id) {
return ArrayUtils.contains(getEnabledFeatures(), id);
@@ -40,6 +40,8 @@ public interface ServletAppConfiguration {
boolean isResourceManagerEnabled();
boolean isSecretManagerEnabled();
boolean isFeaturesEnabled(String[] requiredFeatures);
boolean isFeatureEnabled(String id);
@@ -134,6 +134,10 @@ public class CBAppConfig extends BaseWebAppConfiguration implements ServletAuthC
this.resourceManagerEnabled = resourceManagerEnabled;
}
public void setSecretManagerEnabled(boolean secretManagerEnabled) {
this.secretManagerEnabled = secretManagerEnabled;
}
public boolean isSupportsCustomConnections() {
return supportsCustomConnections;
}
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
* 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.
@@ -114,13 +114,22 @@ public class LocalResourceController extends BaseLocalResourceController {
if (project == null || refresh) {
SessionContextImpl sessionContext = new SessionContextImpl(null);
RMProject rmProject = makeProjectFromId(projectId, false);
project = new InternalWebProjectImpl(sessionContext, rmProject, getProjectPath(projectId));
project = createWebProjectImpl(projectId, sessionContext, rmProject);
projectRegistries.put(projectId, project);
}
return project;
}
}
@NotNull
protected InternalWebProjectImpl createWebProjectImpl(
String projectId,
SessionContextImpl sessionContext,
RMProject rmProject
) throws DBException {
return new InternalWebProjectImpl(sessionContext, rmProject, getProjectPath(projectId));
}
@NotNull
@Override
public RMProject[] listAccessibleProjects() throws DBException {
@@ -946,16 +955,19 @@ public class LocalResourceController extends BaseLocalResourceController {
return "pong (RM)";
}
public static final class Builder {
private final SMCredentialsProvider credentialsProvider;
private final Supplier<SMController> smController;
private final DBPWorkspace workspace;
public static class Builder {
protected final SMCredentialsProvider credentialsProvider;
protected final Supplier<SMController> smController;
protected final DBPWorkspace workspace;
private Path rootPath;
private Path userProjectsPath;
private Path sharedProjectsPath;
protected Path rootPath;
protected Path userProjectsPath;
protected Path sharedProjectsPath;
private Builder(DBPWorkspace workspace, SMCredentialsProvider credentialsProvider, Supplier<SMController> smControllerSupplier) {
protected Builder(
DBPWorkspace workspace, SMCredentialsProvider credentialsProvider,
Supplier<SMController> smControllerSupplier
) {
this.workspace = workspace;
this.credentialsProvider = credentialsProvider;
this.smController = smControllerSupplier;
@@ -46,6 +46,7 @@ public class CBConstants {
public static final String PARAM_STATIC_CONTENT = "staticContent";
public static final String PARAM_RESOURCE_QUOTAS = "resourceQuotas";
public static final String PARAM_RESOURCE_MANAGER_ENABLED = "resourceManagerEnabled";
public static final String PARAM_SECRET_MANAGER_ENABLED = "secretManagerEnabled";
public static final String PARAM_SHOW_READ_ONLY_CONN_INFO = "showReadOnlyConnectionInfo";
public static final String PARAM_CONN_GRANT_ANON_ACCESS = "grantConnectionsAccessToAnonymousTeam";
public static final String PARAM_AUTH_PROVIDERS = "authConfiguration";
@@ -15,6 +15,7 @@ Export-Package: io.cloudbeaver,
io.cloudbeaver.model.config,
io.cloudbeaver.server,
io.cloudbeaver.service,
io.cloudbeaver.service.core,
io.cloudbeaver.service.session
Import-Package: org.slf4j
Automatic-Module-Name: io.cloudbeaver.server.ce
@@ -29,6 +29,8 @@ import io.cloudbeaver.model.config.SMControllerConfiguration;
import io.cloudbeaver.registry.WebDriverRegistry;
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;
@@ -773,4 +775,9 @@ public abstract class CBApplication<T extends CBServerConfig> extends
public WebServerConfig getWebServerConfig() {
return new CBWebServerConfig(this);
}
@Override
public ConnectionController getConnectionController() {
return new ConnectionControllerCE();
}
}
@@ -436,6 +436,11 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
appConfigProperties,
CBConstants.PARAM_RESOURCE_MANAGER_ENABLED,
appConfig.isResourceManagerEnabled());
copyConfigValue(
oldAppConfig,
appConfigProperties,
CBConstants.PARAM_SECRET_MANAGER_ENABLED,
appConfig.isSecretManagerEnabled());
copyConfigValue(
oldAppConfig,
appConfigProperties,
@@ -130,6 +130,8 @@ type ServerConfig {
supportsCustomConnections: Boolean!
resourceManagerEnabled: Boolean!
secretManagerEnabled: Boolean! @since(version: "24.3.2")
publicCredentialsSaveEnabled: Boolean!
adminCredentialsSaveEnabled: Boolean!
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
* 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.
@@ -39,6 +39,8 @@ import org.jkiss.utils.CommonUtils;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
/**
* Web driver configuration
@@ -255,9 +257,19 @@ public class WebDatabaseDriverInfo {
@Property
public WebPropertyInfo[] getProviderProperties() {
return Arrays.stream(driver.getProviderPropertyDescriptors())
WebPropertyInfo[] additionalWebProperty = Optional.of(WebAppUtils.getWebApplication())
.filter(app -> app.getAppConfiguration().isSecretManagerEnabled())
.map(app -> app.getConnectionController().getExternalInfo(webSession))
.orElse(new WebPropertyInfo[0]);
WebPropertyInfo[] providerProperties = Arrays.stream(driver.getProviderPropertyDescriptors())
.map(p -> new WebPropertyInfo(webSession, p, null))
.toArray(WebPropertyInfo[]::new);
return Stream.concat(
Arrays.stream(additionalWebProperty),
Arrays.stream(providerProperties)
).toArray(WebPropertyInfo[]::new);
}
@Property
@@ -110,6 +110,11 @@ public class WebServerConfig {
return application.getAppConfiguration().isResourceManagerEnabled();
}
@Property
public boolean isSecretManagerEnabled() {
return application.getAppConfiguration().isSecretManagerEnabled();
}
@Property
public String[] getEnabledFeatures() {
return application.getAppConfiguration().getEnabledFeatures();
@@ -21,6 +21,7 @@ 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;
@@ -52,4 +53,6 @@ public interface WebApplication extends ServletApplication {
WebServerConfig getWebServerConfig();
ConnectionController getConnectionController();
}
@@ -0,0 +1,102 @@
/*
* 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.WebPropertyInfo;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
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;
WebPropertyInfo[] getExternalInfo(WebSession webSession);
}
@@ -0,0 +1,540 @@
/*
* 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.WebPropertyInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import io.cloudbeaver.utils.WebEventUtils;
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.model.websocket.WSConstants;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceConnectEvent;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
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();
// we don't need to save credentials for templates
if (connectionConfig.isTemplate()) {
connectionConfig.setSaveCredentials(false);
}
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));
WebEventUtils.addDataSourceUpdatedEvent(
webSession.getProjectById(projectId),
webSession,
connectionInfo.getId(),
WSConstants.EventAction.CREATE,
WSDataSourceProperty.CONFIGURATION
);
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());
}
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());
boolean sendEvent = !((DataSourceDescriptor) dataSource).equalSettings(getOldDataSource(dataSource));
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()
);
}
WSDataSourceProperty property = getDatasourceEventProperty(getOldDataSource(dataSource), dataSource);
try {
sessionRegistry.updateDataSource(dataSource);
sessionRegistry.checkForErrors();
} catch (DBException e) {
throw new DBWebException("Failed to update connection", e);
}
if (sendEvent) {
WebEventUtils.addDataSourceUpdatedEvent(
webSession.getProjectById(projectId),
webSession,
connectionInfo.getId(),
WSConstants.EventAction.UPDATE,
property
);
}
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);
WebEventUtils.addDataSourceUpdatedEvent(
webSession.getProjectById(projectId),
webSession,
connectionId,
WSConstants.EventAction.DELETE,
WSDataSourceProperty.CONFIGURATION
);
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;
}
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;
}
@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);
if (connect) {
webSession.addSessionEvent(
new WSDataSourceConnectEvent(
projectId,
connectionId,
webSession.getSessionId(),
webSession.getUserId()
)
);
}
} catch (Exception e) {
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 {
}
public WebPropertyInfo[] getExternalInfo(WebSession session) {
return null;
}
private void validateDriverLibrariesPresence(@NotNull DBPDataSourceContainer container) throws DBWebException {
if (!DBWorkbench.isDistributed() && container.getDriver().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()));
}
}
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
* 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.
@@ -51,7 +51,6 @@ 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.secret.DBSSecretController;
import org.jkiss.dbeaver.model.secret.DBSSecretValue;
@@ -328,7 +327,7 @@ public class WebServiceCore implements DBWServiceCore {
@Nullable String projectId,
@NotNull String connectionId
) throws DBWebException {
return WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
return WebAppUtils.getWebApplication().getConnectionController().getConnectionState(webSession, projectId, connectionId);
}
@@ -343,109 +342,8 @@ public class WebServiceCore implements DBWServiceCore {
boolean sharedCredentials,
@Nullable String selectedSecretId
) throws DBWebException {
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
connectionInfo.setSavedCredentials(authProperties, networkCredentials);
var dataSourceContainer = (DataSourceDescriptor) 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);
if (connect) {
webSession.addSessionEvent(
new WSDataSourceConnectEvent(
projectId,
connectionId,
webSession.getSessionId(),
webSession.getUserId()
)
);
}
} catch (Exception e) {
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;
return WebAppUtils.getWebApplication().getConnectionController().initConnection(webSession, projectId,
connectionId, authProperties, networkCredentials, saveCredentials, sharedCredentials, selectedSecretId);
}
@Override
@@ -454,47 +352,14 @@ public class WebServiceCore implements DBWServiceCore {
@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();
// we don't need to save credentials for templates
if (connectionConfig.isTemplate()) {
connectionConfig.setSaveCredentials(false);
}
DBPDataSourceContainer newDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig,
sessionRegistry);
if (CommonUtils.isEmpty(newDataSource.getName())) {
newDataSource.setName(CommonUtils.notNull(connectionConfig.getName(), "NewConnection"));
}
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));
WebEventUtils.addDataSourceUpdatedEvent(
webSession.getProjectById(projectId),
DBPDataSourceContainer dataSourceContainer =
WebAppUtils.getWebApplication().getConnectionController().createDataSourceContainer(webSession, projectId, connectionConfig);
return WebAppUtils.getWebApplication().getConnectionController().createConnection(
webSession,
connectionInfo.getId(),
WSConstants.EventAction.CREATE,
WSDataSourceProperty.CONFIGURATION
projectId,
dataSourceContainer.getRegistry(),
dataSourceContainer
);
return connectionInfo;
}
@Override
@@ -503,82 +368,15 @@ public class WebServiceCore implements DBWServiceCore {
@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));
DataSourceDescriptor oldDataSource;
oldDataSource = dataSource.getRegistry().createDataSource(dataSource);
oldDataSource.setId(dataSource.getId());
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());
}
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 = dataSource.isSharedCredentials() || !dataSource.getProject()
.isUseSecretStorage() && dataSource.isSavePassword();
if (sharedCredentials) {
//we must notify about the shared password change
WebServiceUtils.saveAuthProperties(
dataSource,
dataSource.getConnectionConfiguration(),
config.getCredentials(),
config.isSaveCredentials(),
config.isSharedCredentials()
);
}
boolean sendEvent = !((DataSourceDescriptor) dataSource).equalSettings(oldDataSource);
if (!sharedCredentials) {
// secret controller is responsible for notification, password changes applied after checks
WebServiceUtils.saveAuthProperties(
dataSource,
dataSource.getConnectionConfiguration(),
config.getCredentials(),
config.isSaveCredentials(),
config.isSharedCredentials()
);
}
connectionInfo.setCredentialsSavedInSession(null);
WSDataSourceProperty property = getDatasourceEventProperty(oldDataSource, dataSource);
try {
sessionRegistry.updateDataSource(dataSource);
sessionRegistry.checkForErrors();
} catch (DBException e) {
throw new DBWebException("Failed to update connection", e);
}
if (sendEvent) {
WebEventUtils.addDataSourceUpdatedEvent(
webSession.getProjectById(projectId),
webSession,
connectionInfo.getId(),
WSConstants.EventAction.UPDATE,
property
);
}
return connectionInfo;
DBPDataSourceContainer dataSourceContainer =
WebAppUtils.getWebApplication().getConnectionController().getDatasourceConnection(webSession, projectId, config);
return WebAppUtils.getWebApplication().getConnectionController().updateConnection(
webSession,
projectId,
config,
dataSourceContainer,
dataSourceContainer.getRegistry()
);
}
private WSDataSourceProperty getDatasourceEventProperty(
@@ -602,21 +400,8 @@ public class WebServiceCore implements DBWServiceCore {
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);
WebEventUtils.addDataSourceUpdatedEvent(
webSession.getProjectById(projectId),
webSession,
connectionId,
WSConstants.EventAction.DELETE,
WSDataSourceProperty.CONFIGURATION
);
return true;
return WebAppUtils.getWebApplication().getConnectionController().deleteConnection(webSession, projectId, connectionId);
}
@Override
@@ -713,86 +498,14 @@ public class WebServiceCore implements DBWServiceCore {
@Override
public WebConnectionInfo testConnection(
@NotNull WebSession webSession, @Nullable String projectId, @NotNull WebConnectionConfig connectionConfig
@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);
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);
}
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);
}
DataSourceDescriptor dataSourceDescriptor = WebAppUtils.getWebApplication().getConnectionController()
.prepareTestConnection(webSession, projectId, connectionConfig);
return WebAppUtils.getWebApplication().getConnectionController()
.testConnection(webSession, projectId, connectionConfig, dataSourceDescriptor);
}
@Override
@@ -114,6 +114,7 @@ input ServerConfigInput {
publicCredentialsSaveEnabled: Boolean
adminCredentialsSaveEnabled: Boolean
resourceManagerEnabled: Boolean
secretManagerEnabled: Boolean @since(version: "24.3.2")
enabledFeatures: [ID!]
enabledAuthProviders: [ID!]
@@ -37,6 +37,7 @@ public class AdminServerConfig {
private final boolean anonymousAccessEnabled;
private final boolean resourceManagerEnabled;
private final boolean secretManagerEnabled;
private final boolean customConnectionsEnabled;
private final boolean publicCredentialsSaveEnabled;
private final boolean adminCredentialsSaveEnabled;
@@ -59,6 +60,7 @@ public class AdminServerConfig {
this.publicCredentialsSaveEnabled = JSONUtils.getBoolean(params, "publicCredentialsSaveEnabled", appConfig.isPublicCredentialsSaveEnabled());
this.adminCredentialsSaveEnabled = JSONUtils.getBoolean(params, "adminCredentialsSaveEnabled", appConfig.isAdminCredentialsSaveEnabled());
this.resourceManagerEnabled = JSONUtils.getBoolean(params, "resourceManagerEnabled", appConfig.isResourceManagerEnabled());
this.secretManagerEnabled = JSONUtils.getBoolean(params, "secretManagerEnabled", appConfig.isSecretManagerEnabled());
if (params.containsKey("enabledFeatures")) {
this.enabledFeatures = JSONUtils.getStringList(params, "enabledFeatures");
@@ -162,4 +164,8 @@ public class AdminServerConfig {
public boolean isResourceManagerEnabled() {
return resourceManagerEnabled;
}
public boolean isSecretManagerEnabled() {
return secretManagerEnabled;
}
}
@@ -564,6 +564,7 @@ public class WebServiceAdmin implements DBWServiceAdmin {
// custom logic for enabling embedded drivers
updateDisabledDriversConfig(appConfig, config.getDisabledDrivers());
appConfig.setResourceManagerEnabled(config.isResourceManagerEnabled());
appConfig.setSecretManagerEnabled(config.isSecretManagerEnabled());
if (CommonUtils.isEmpty(config.getEnabledAuthProviders())) {
// All of them
@@ -100,6 +100,10 @@ export class ServerConfigResource extends CachedDataResource<ServerConfig | null
return this.data?.resourceManagerEnabled ?? false;
}
get secretManagerEnabled() {
return this.data?.secretManagerEnabled ?? false;
}
isBetaFeatureDisabled(feature: string): boolean {
return this.data?.disabledBetaFeatures?.includes(feature) || false;
}
@@ -28,6 +28,7 @@ export const defaultServerConfig: (productConfiguration?: Record<string, any>) =
anonymousAccessEnabled: true,
adminCredentialsSaveEnabled: true,
publicCredentialsSaveEnabled: true,
secretManagerEnabled: true,
resourceManagerEnabled: true,
licenseRequired: false,
licenseValid: false,
@@ -17,6 +17,7 @@ fragment ServerConfig on ServerConfig {
publicCredentialsSaveEnabled
resourceManagerEnabled
secretManagerEnabled
configurationMode
developmentMode
@@ -19,6 +19,7 @@ const ServerConfigurationFormPartStateConfigSchema = schema.object({
enabledFeatures: schema.array(schema.string()).optional(),
publicCredentialsSaveEnabled: schema.boolean().optional(),
resourceManagerEnabled: schema.boolean().optional(),
secretManagerEnabled: schema.boolean().optional(),
serverName: schema.string().optional(),
serverURL: schema.string().optional(),
sessionExpireTime: schema.number().optional(),
@@ -29,6 +29,7 @@ function DEFAULT_STATE_GETTER(): IServerConfigurationFormPartState {
enabledFeatures: [],
publicCredentialsSaveEnabled: false,
resourceManagerEnabled: false,
secretManagerEnabled: false,
serverName: '',
serverURL: '',
sessionExpireTime: MIN_SESSION_EXPIRE_TIME * 1000 * 60,
@@ -147,6 +148,7 @@ export class ServerConfigurationFormPart extends FormPart<IServerConfigurationFo
anonymousAccessEnabled: config?.anonymousAccessEnabled ?? false,
enabledFeatures: config?.enabledFeatures ? [...config.enabledFeatures] : [],
resourceManagerEnabled: config?.resourceManagerEnabled ?? false,
secretManagerEnabled: config?.secretManagerEnabled ?? false,
},
navigatorConfig: { ...this.state.navigatorConfig, ...defaultNavigatorSettings },
});
@@ -40,7 +40,7 @@ export class ProductInfoService extends Dependency {
onActivate: async () => {
await this.serverLicenseStatusResource.load();
},
order: 12,
order: 13,
});
}