mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
CB-5574. Added new api for get manager, added flap in server configur… (#3161)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+8
@@ -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);
|
||||
|
||||
+2
@@ -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;
|
||||
}
|
||||
|
||||
+22
-10
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -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!
|
||||
|
||||
|
||||
+14
-2
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
+102
@@ -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);
|
||||
}
|
||||
+540
@@ -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()));
|
||||
}
|
||||
}
|
||||
+28
-315
@@ -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!]
|
||||
|
||||
+6
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
+1
@@ -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(),
|
||||
|
||||
+2
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user