Compare commits

..
1 Commits
Author SHA1 Message Date
Alexey Potsetsuev 9d71a77a48 dbeaver/pro#7111 fix: doubled hot keys handler (#3810) 2025-10-08 10:09:50 +02:00
698 changed files with 9197 additions and 7132 deletions
+1 -1
View File
@@ -48,7 +48,7 @@
"-Declipse.pde.launch=true",
"-XstartOnFirstThread",
"-Dfile.encoding=UTF-8",
"--add-modules=ALL-DEFAULT",
"--add-modules=ALL-SYSTEM",
"--add-opens=java.base/java.io=ALL-UNNAMED",
"--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
+2 -11
View File
@@ -92,10 +92,10 @@
"label": "Run Backend CE",
"type": "shell",
"windows": {
"command": "./run-cloudbeaver-server.bat"
"command": "./run-server.bat"
},
"osx": {
"command": "./run-cloudbeaver-server.sh"
"command": "./run-server.sh"
},
"options": {
"cwd": "${workspaceFolder}/deploy/cloudbeaver"
@@ -136,15 +136,6 @@
"cwd": "${workspaceFolder}/webapp/common-react/@dbeaver/ui-kit"
},
"args": ["docs"]
},
{
"label": "Run Storybook",
"type": "shell",
"command": "yarn",
"options": {
"cwd": "${workspaceFolder}/webapp/packages/storybook"
},
"args": ["storybook"]
}
],
"inputs": [
-5
View File
@@ -25,11 +25,6 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
## Changelog
### 25.2.1 2025-09-22
- Autocomplete values in SQL Editor are ordered alphabetically to simplify object search.
- "Show all databases" setting was added on the connection page for MySQL and MariaDB.
- Different bug fixes and enhancements have been made.
### 25.2.0 2025-09-01
### Changes since 25.1.0:
- Administration:
+1 -1
View File
@@ -28,4 +28,4 @@ echo "Copy static content"
cp -rp ../webapp/packages/product-default/lib/* cloudbeaver/web
echo "Cloudbeaver is ready. Run run-cloudbeaver-server.sh in cloudbeaver folder to start the server."
echo "Cloudbeaver is ready. Run run-server.sh in cloudbeaver folder to start the server."
+1 -1
View File
@@ -72,6 +72,6 @@ echo "Copy static content"
xcopy /E /Q ..\webapp\packages\product-default\lib cloudbeaver\web >NUL
echo "Cloudbeaver is ready. Run run-cloudbeaver-server.bat in cloudbeaver folder to start the server."
echo "Cloudbeaver is ready. Run run-server.bat in cloudbeaver folder to start the server."
pause
+1 -1
View File
@@ -16,6 +16,6 @@ EXPOSE 8978
RUN find /opt/cloudbeaver -type d -exec chmod 775 {} \;
WORKDIR /opt/cloudbeaver/
RUN chmod +x "run-cloudbeaver-server.sh" "/opt/cloudbeaver/launch-product.sh"
RUN chmod +x "run-server.sh" "/opt/cloudbeaver/launch-product.sh"
ENTRYPOINT ["./launch-product.sh"]
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
set -Eeo pipefail
if [[ $# -eq 0 ]] ;
then
set -- "$@" -help
fi
set -- "$@" -cli-mode
source run-cloudbeaver-server.sh "$@"
+3 -3
View File
@@ -12,8 +12,8 @@ if [ "$(id -u)" -eq 0 ]; then
TARGET_GID=${TARGET_GID:-$DBEAVER_GID}
chown -R $DBEAVER_UID:$DBEAVER_GID $PWD/workspace
# Execute run-cloudbeaver-server.sh as the dbeaver user with the JAVA_HOME and PATH environment variables
exec su "$TARGET_USER" -c "JAVA_HOME=$JAVA_HOME PATH=$PATH ./run-cloudbeaver-server.sh"
# Execute run-server.sh as the dbeaver user with the JAVA_HOME and PATH environment variables
exec su "$TARGET_USER" -c "JAVA_HOME=$JAVA_HOME PATH=$PATH ./run-server.sh"
else
exec ./run-cloudbeaver-server.sh
exec ./run-server.sh
fi
@@ -17,7 +17,7 @@ If Not Defined JAVA_OPTS (
java %JAVA_OPTS% ^
-Dfile.encoding=UTF-8 ^
--add-modules=ALL-DEFAULT ^
--add-modules=ALL-SYSTEM ^
--add-opens=java.base/java.io=ALL-UNNAMED ^
--add-opens=java.base/java.lang=ALL-UNNAMED ^
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED ^
@@ -11,7 +11,7 @@ echo "Starting Cloudbeaver Server"
exec java ${JAVA_OPTS} \
-Dfile.encoding=UTF-8 \
--add-modules=ALL-DEFAULT \
--add-modules=ALL-SYSTEM \
--add-opens=java.base/java.io=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
@@ -36,6 +36,6 @@ exec java ${JAVA_OPTS} \
-jar ${launcherJar} \
-product io.cloudbeaver.product.ce.product \
-web-config conf/cloudbeaver.conf \
"$@" \
${CLI_OPTS} \
-nl en \
-registryMultiLanguage
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
set -Eeo pipefail
CLI_OPTS="$@"
if [[ $# -eq 0 ]] ;
then
CLI_OPTS='-help'
fi
source run-server.sh
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Model
Bundle-SymbolicName: io.cloudbeaver.model;singleton:=true
Bundle-Version: 1.0.86.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.85.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
+1 -1
View File
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.model</artifactId>
<version>1.0.86-SNAPSHOT</version>
<version>1.0.85-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -17,14 +17,18 @@
package io.cloudbeaver;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.rm.*;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMControllerProvider;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.Pair;
import java.nio.file.Path;
import java.util.Collection;
public abstract class BaseWebProjectImpl extends BaseProjectImpl implements RMControllerProvider {
@@ -77,12 +81,6 @@ public abstract class BaseWebProjectImpl extends BaseProjectImpl implements RMCo
return project.getId();
}
@NotNull
@Override
public String getDisplayName() {
return getName();
}
@NotNull
@Override
public Path getAbsolutePath() {
@@ -104,25 +102,52 @@ public abstract class BaseWebProjectImpl extends BaseProjectImpl implements RMCo
return false;
}
/**
* Method for Bulk Update of resources properties paths
*
* @param oldToNewPaths collection of OldPath to NewPath pairs
*/
public void moveResourcePropertiesBatch(@NotNull Collection<Pair<String, String>> oldToNewPaths) {
loadMetadata();
synchronized (metadataSync) {
for (var pathsPair : oldToNewPaths) {
final var oldResourcePath = CommonUtils.normalizeResourcePath(pathsPair.getFirst());
final var newResourcePath = CommonUtils.normalizeResourcePath(pathsPair.getSecond());
final var resProps = resourceProperties.remove(oldResourcePath);
if (resProps != null) {
resourceProperties.put(newResourcePath, resProps);
}
}
}
flushMetadata();
}
/**
* Method for Bulk Remove of resources properties
*/
public boolean resetResourcesPropertiesBatch(@NotNull Collection<String> resourcesPaths) {
loadMetadata();
boolean propertiesChanged = false;
synchronized (metadataSync) {
for (var resourcePath : resourcesPaths) {
var removedProperties = resourceProperties.remove(CommonUtils.normalizeResourcePath(resourcePath));
if (removedProperties != null) {
propertiesChanged = true;
}
}
}
if (propertiesChanged) {
flushMetadata();
}
return propertiesChanged;
}
public Path getMetadataFilePath() {
return getMetadataPath().resolve(METADATA_STORAGE_FILE);
}
@Override
public boolean isPrivateProject() {
return RMProjectType.USER.equals(getRMProject().getType());
}
@Override
public void updateProject(@Nullable String newName, @Nullable String description) throws DBException {
RMProject rmProject = getResourceController().updateProject(this.getId(), new RMProjectInfo(newName, description));
updateProjectInfo(rmProject.getName(), rmProject.getDescription());
}
public void updateProjectInfo(@Nullable String newName, @Nullable String description) {
this.project.setName(newName);
this.project.setDescription(description);
RMEventManager.fireEvent(
new RMEvent(
RMEvent.Action.PROJECT_UPDATE,
project
)
);
}
}
@@ -1,110 +0,0 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.app.WebAppConfiguration;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.utils.CommonUtils;
public class WebConnectionConfigInputHandler<T extends WebConnectionConfig, C extends DataSourceDescriptor> {
private static final Log log = Log.getLog(WebConnectionConfigInputHandler.class);
protected final T input;
protected final DBPDataSourceRegistry registry;
public WebConnectionConfigInputHandler(@NotNull DBPDataSourceRegistry registry, T configInput) {
this.registry = registry;
this.input = configInput;
}
public C createDataSourceContainer() throws DBWebException {
String driverId = input.getDriverId();
if (CommonUtils.isEmpty(driverId)) {
throw new DBWebException("Driver must be specified");
}
DBPDriver driver = WebDataSourceUtils.getDriverById(driverId);
C newDataSource = createDataSourceContainerFromInput(driver);
if (ServletAppUtils.getServletApplication().getAppConfiguration() instanceof WebAppConfiguration webAppConfiguration) {
newDataSource.setNavigatorSettings(webAppConfiguration.getDefaultNavigatorSettings());
}
WebDataSourceUtils.saveAuthProperties(
newDataSource,
newDataSource.getConnectionConfiguration(),
input.getCredentials(),
input.isSaveCredentials(),
input.isSharedCredentials()
);
return newDataSource;
}
public void updateDataSource(@NotNull C dataSource) throws DBWebException {
dataSource.setId(dataSource.getId());
if (!CommonUtils.isEmpty(input.getName())) {
dataSource.setName(input.getName());
}
if (input.getDescription() != null) {
dataSource.setDescription(input.getDescription());
}
dataSource.setFolder(input.getFolder() != null ? registry.getFolder(input.getFolder()) : null);
if (input.isDefaultAutoCommit() != null) {
dataSource.setDefaultAutoCommit(input.isDefaultAutoCommit());
}
WebDataSourceUtils.setConnectionConfiguration(
dataSource.getDriver(),
dataSource.getConnectionConfiguration(),
input
);
WebDataSourceUtils.saveAuthProperties(
dataSource,
dataSource.getConnectionConfiguration(),
input.getCredentials(),
input.isSaveCredentials(),
input.isSharedCredentials()
);
dataSource.setConnectionReadOnly(input.isReadOnly());
}
@NotNull
protected C createDataSourceContainerFromInput(@NotNull DBPDriver driver) {
DBPConnectionConfiguration dsConfig = new DBPConnectionConfiguration();
WebDataSourceUtils.setConnectionConfiguration(driver, dsConfig, input);
C newDataSource = registry.createDataSource(driver, dsConfig);
newDataSource.setSavePassword(true);
newDataSource.setName(CommonUtils.notNull(input.getName(), "NewConnection"));
newDataSource.setDescription(input.getDescription());
newDataSource.setConnectionReadOnly(input.isReadOnly());
if (input.getFolder() != null) {
newDataSource.setFolder(registry.getFolder(input.getFolder()));
}
return newDataSource;
}
}
@@ -16,13 +16,11 @@
*/
package io.cloudbeaver;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
@@ -30,26 +28,22 @@ import org.jkiss.dbeaver.model.app.DBPDataSourceRegistryCache;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMUtils;
import org.jkiss.dbeaver.model.security.SMObjectType;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceEvent;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceRegistry;
import org.jkiss.dbeaver.runtime.jobs.DisconnectJob;
import org.jkiss.utils.CommonUtils;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class WebSessionProjectImpl extends WebProjectImpl {
private static final Log log = Log.getLog(WebSessionProjectImpl.class);
protected final WebSession webSession;
private final Map<String, WebConnectionInfo> connections = new HashMap<>();
private final Map<String, Object> projectSettings = new ConcurrentHashMap<>();
private boolean registryIsLoaded = false;
public WebSessionProjectImpl(
@@ -165,7 +159,7 @@ public class WebSessionProjectImpl extends WebProjectImpl {
*/
@NotNull
public synchronized WebConnectionInfo addConnection(@NotNull DBPDataSourceContainer dataSourceContainer) {
WebConnectionInfo connection = createConnectionInfo(dataSourceContainer);
WebConnectionInfo connection = new WebConnectionInfo(webSession, dataSourceContainer);
synchronized (connections) {
connections.put(dataSourceContainer.getId(), connection);
}
@@ -243,124 +237,4 @@ public class WebSessionProjectImpl extends WebProjectImpl {
}
return sendDataSourceUpdatedEvent;
}
public void refreshProjectSettings() throws DBException {
if (webSession.getUser() == null) {
projectSettings.clear();
return;
}
Map<String, Object> loadedSettings = webSession.getSecurityController().getObjectSettings(
getId(),
SMObjectType.project,
null
);
projectSettings.clear();
projectSettings.putAll(loadedSettings);
}
@NotNull
public WebConnectionInfo createConnectionInfo(@NotNull DBPDataSourceContainer dataSourceDescriptor) {
return new WebConnectionInfo(webSession, dataSourceDescriptor);
}
@NotNull
public WebConnectionInfo createConnection(@NotNull Map<String, Object> configMap) throws DBWebException {
if (CommonUtils.isEmpty(configMap)) {
throw new DBWebException("Connection configuration parameters are missing");
}
DBPDataSourceContainer newDataSource = getDataSourceContainerFromInput(configMap);
return addDataSourceToProject(newDataSource);
}
@NotNull
public WebConnectionInfo addDataSourceToProject(@NotNull DBPDataSourceContainer newDataSource) throws DBWebException {
DBPDataSourceRegistry registry = getDataSourceRegistry();
try {
registry.addDataSource(newDataSource);
registry.checkForErrors();
} catch (DBException e) {
registry.removeDataSource(newDataSource);
throw new DBWebException("Failed to create connection", e);
}
WebConnectionInfo connectionInfo = addConnection(newDataSource);
webSession.addInfoMessage("New connection was created - " + WebDataSourceUtils.getConnectionContainerInfo(
newDataSource));
log.info(String.format(
"New connection was created: [info=%s, user=%s]",
WebDataSourceUtils.getConnectionContainerInfo(newDataSource),
webSession.getUserId()
));
return connectionInfo;
}
@NotNull
public WebConnectionInfo updateConnection(@Nullable Map<String, Object> configMap) throws DBWebException {
WebConnectionConfig config = getConnectionConfigInput(configMap);
WebConnectionInfo connectionInfo = getWebConnectionInfo(config.getConnectionId());
DataSourceDescriptor dataSource = (DataSourceDescriptor) connectionInfo.getDataSourceContainer();
webSession.addInfoMessage("Update connection - " + WebDataSourceUtils.getConnectionContainerInfo(dataSource));
DBPDataSourceRegistry registry = getDataSourceRegistry();
getInputConfigHandler(configMap).updateDataSource(dataSource);
connectionInfo.setCredentialsSavedInSession(null);
try {
registry.updateDataSource(dataSource);
registry.checkForErrors();
} catch (DBException e) {
throw new DBWebException("Failed to update connection", e);
}
return connectionInfo;
}
public boolean deleteConnection(@NotNull String connectionId) throws DBWebException {
WebConnectionInfo connectionInfo = getWebConnectionInfo(connectionId);
webSession.addInfoMessage("Delete connection - " +
WebDataSourceUtils.getConnectionContainerInfo(connectionInfo.getDataSourceContainer()));
closeAndDeleteConnection(connectionInfo);
log.info(String.format(
"Connection deleted: [info=%s, userId=%s]",
WebDataSourceUtils.getConnectionContainerInfo(connectionInfo.getDataSourceContainer()),
webSession.getUserId()
));
return true;
}
@NotNull
private WebConnectionInfo closeAndDeleteConnection(@NotNull WebConnectionInfo connectionInfo) throws DBWebException {
DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer();
boolean disconnected = WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer);
DBPDataSourceRegistry registry = getDataSourceRegistry();
registry.removeDataSource(dataSourceContainer);
try {
registry.checkForErrors();
} catch (DBException e) {
try {
registry.addDataSource(dataSourceContainer);
} catch (DBException ex) {
log.error("Error re-adding after delete attempt", e);
}
throw new DBWebException("Failed to delete connection", e);
}
removeConnection(dataSourceContainer);
return connectionInfo;
}
@NotNull
public DataSourceDescriptor getDataSourceContainerFromInput(@NotNull Map<String, Object> configMap) throws DBWebException {
return getInputConfigHandler(configMap).createDataSourceContainer();
}
@NotNull
public WebConnectionConfig getConnectionConfigInput(@Nullable Map<String, Object> configMap) {
return new WebConnectionConfig(configMap == null ? Map.of() : configMap);
}
@NotNull
protected WebConnectionConfigInputHandler getInputConfigHandler(@NotNull Map<String, Object> configMap) {
return new WebConnectionConfigInputHandler<>(getDataSourceRegistry(), getConnectionConfigInput(configMap));
}
}
@@ -16,11 +16,11 @@
*/
package io.cloudbeaver.model;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.connection.DBPDriverConfigurationType;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.utils.CommonUtils;
import java.util.ArrayList;
import java.util.List;
@@ -58,6 +58,7 @@ public class WebConnectionConfig {
private Map<String, Object> mainPropertyValues;
private Map<String, Object> expertSettingsValues;
private Map<String, Object> providerProperties;
private Map<String, Object> externalParameters;
private List<WebNetworkHandlerConfigInput> networkHandlersConfig;
private DBPDriverConfigurationType configurationType;
private String selectedSecretId;
@@ -68,52 +69,54 @@ public class WebConnectionConfig {
public WebConnectionConfig() {
}
public WebConnectionConfig(@NotNull Map<String, Object> params) {
connectionId = JSONUtils.getString(params, "connectionId");
driverId = JSONUtils.getString(params, "driverId");
public WebConnectionConfig(Map<String, Object> params) {
if (!CommonUtils.isEmpty(params)) {
connectionId = JSONUtils.getString(params, "connectionId");
driverId = JSONUtils.getString(params, "driverId");
host = JSONUtils.getString(params, "host");
port = JSONUtils.getString(params, "port");
serverName = JSONUtils.getString(params, "serverName");
databaseName = JSONUtils.getString(params, "databaseName");
url = JSONUtils.getString(params, "url");
host = JSONUtils.getString(params, "host");
port = JSONUtils.getString(params, "port");
serverName = JSONUtils.getString(params, "serverName");
databaseName = JSONUtils.getString(params, "databaseName");
url = JSONUtils.getString(params, "url");
name = JSONUtils.getString(params, "name");
description = JSONUtils.getString(params, "description");
folder = JSONUtils.getString(params, "folder");
name = JSONUtils.getString(params, "name");
description = JSONUtils.getString(params, "description");
folder = JSONUtils.getString(params, "folder");
properties = JSONUtils.getObjectOrNull(params, "properties");
userName = JSONUtils.getString(params, "userName");
userPassword = JSONUtils.getString(params, "userPassword");
selectedSecretId = JSONUtils.getString(params, "selectedSecretId");
properties = JSONUtils.getObjectOrNull(params, "properties");
userName = JSONUtils.getString(params, "userName");
userPassword = JSONUtils.getString(params, "userPassword");
selectedSecretId = JSONUtils.getString(params, "selectedSecretId");
authModelId = JSONUtils.getString(params, "authModelId");
credentials = JSONUtils.getObjectOrNull(params, "credentials");
saveCredentials = JSONUtils.getBoolean(params, "saveCredentials");
sharedCredentials = JSONUtils.getBoolean(params, "sharedCredentials");
authModelId = JSONUtils.getString(params, "authModelId");
credentials = JSONUtils.getObjectOrNull(params, "credentials");
saveCredentials = JSONUtils.getBoolean(params, "saveCredentials");
sharedCredentials = JSONUtils.getBoolean(params, "sharedCredentials");
mainPropertyValues = JSONUtils.getObjectOrNull(params, "mainPropertyValues");
providerProperties = JSONUtils.getObjectOrNull(params, "providerProperties");
expertSettingsValues = JSONUtils.getObjectOrNull(params, "expertSettingsValues");
keepAliveInterval = JSONUtils.getInteger(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_KEEP_ALIVE_INTERVAL, -1);
readOnly = JSONUtils.getBoolean(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_READ_ONLY);
defaultAutoCommit = JSONUtils.getBoolean(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_AUTO_COMMIT, true);
defaultCatalogName = JSONUtils.getString(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_DEFAULT_CATALOG);
defaultSchemaName = JSONUtils.getString(
expertSettingsValues != null ? expertSettingsValues : params,
WebExpertSettingsProperties.PROP_DEFAULT_SCHEMA
);
mainPropertyValues = JSONUtils.getObjectOrNull(params, "mainPropertyValues");
providerProperties = JSONUtils.getObjectOrNull(params, "providerProperties");
String configType = JSONUtils.getString(params, "configurationType");
configurationType = configType == null ? null : DBPDriverConfigurationType.valueOf(configType);
expertSettingsValues = JSONUtils.getObjectOrNull(params, "expertSettingsValues");
keepAliveInterval = JSONUtils.getInteger(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_KEEP_ALIVE_INTERVAL, -1);
readOnly = JSONUtils.getBoolean(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_READ_ONLY);
defaultAutoCommit = JSONUtils.getBoolean(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_AUTO_COMMIT, true);
defaultCatalogName = JSONUtils.getString(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_DEFAULT_CATALOG);
defaultSchemaName = JSONUtils.getString(
expertSettingsValues != null ? expertSettingsValues : params, WebExpertSettingsProperties.PROP_DEFAULT_SCHEMA);
networkHandlersConfig = new ArrayList<>();
for (Map<String, Object> nhc : JSONUtils.getObjectList(params, "networkHandlersConfig")) {
networkHandlersConfig.add(new WebNetworkHandlerConfigInput(nhc));
String configType = JSONUtils.getString(params, "configurationType");
configurationType = configType == null ? null : DBPDriverConfigurationType.valueOf(configType);
externalParameters = JSONUtils.getObjectOrNull(params, "externalParameters");
networkHandlersConfig = new ArrayList<>();
for (Map<String, Object> nhc : JSONUtils.getObjectList(params, "networkHandlersConfig")) {
networkHandlersConfig.add(new WebNetworkHandlerConfigInput(nhc));
}
}
}
@@ -259,4 +262,8 @@ public class WebConnectionConfig {
public String getDefaultSchemaName() {
return defaultSchemaName;
}
public Map<String, Object> getExternalParameters() {
return externalParameters;
}
}
@@ -16,7 +16,6 @@
*/
package io.cloudbeaver.model;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.model.app.BaseWebAppConfiguration;
import io.cloudbeaver.model.session.WebSession;
@@ -320,10 +319,6 @@ public class WebConnectionInfo {
!dataSourceContainer.getDriver().isAnonymousAccess();
}
public void validateConnection() throws DBWebException {
}
// we don't show non-secured properties in FE when connecting to DB without saved credentials
private boolean isAuthPropertiesEmpty() {
return Arrays.stream(getAuthProperties()).allMatch(f -> f.hasFeature(DBConstants.PROP_FEATURE_NON_SECURED));
@@ -198,7 +198,6 @@ public abstract class BaseServletApplication extends BaseApplicationImpl impleme
}
}
@NotNull
@Override
public Object start(IApplicationContext context) {
initializeApplicationServices();
@@ -211,9 +210,8 @@ public abstract class BaseServletApplication extends BaseApplicationImpl impleme
startServer();
} catch (Exception e) {
log.error(e.getMessage(), e);
return EXIT_ERROR_UNSPECIFIED;
}
return EXIT_OK;
return null;
}
protected abstract void startServer() throws DBException;
@@ -281,9 +279,4 @@ public abstract class BaseServletApplication extends BaseApplicationImpl impleme
public ApplicationInstanceController getInstanceServer() {
return instanceServer;
}
@Override
public boolean isAnonymousAccessEnabled() {
return getAppConfiguration().isAnonymousAccessEnabled();
}
}
@@ -100,6 +100,4 @@ public interface ServletApplication extends DBPApplication {
default void getStatusInfo(Map<String, Object> infoMap) {
}
boolean isAnonymousAccessEnabled();
}
@@ -20,7 +20,7 @@ import org.apache.commons.cli.CommandLine;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.cli.ApplicationInstanceController;
import org.jkiss.dbeaver.model.cli.ApplicationInstanceServer;
import org.jkiss.dbeaver.model.cli.CLIProcessResult;
import org.jkiss.dbeaver.model.cli.CliProcessResult;
import java.io.IOException;
@@ -31,17 +31,16 @@ public class CloudBeaverInstanceServer extends ApplicationInstanceServer<Applica
@NotNull
@Override
public CLIProcessResult handleCommandLine(@NotNull String[] args) {
public CliProcessResult handleCommandLine(@NotNull String[] args) {
CommandLine cmd = CloudBeaverCommandLine.getInstance().getCommandLine(args);
try {
return CloudBeaverCommandLine.getInstance().executeCommandLineCommands(
cmd,
this,
false,
false
);
} catch (Exception e) {
return new CLIProcessResult(CLIProcessResult.PostAction.ERROR, "Error executing command: " + e.getMessage());
return new CliProcessResult(CliProcessResult.PostAction.ERROR, "Error executing command: " + e.getMessage());
}
}
}
@@ -19,6 +19,7 @@ package io.cloudbeaver.model.rm;
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.Log;
import org.jkiss.dbeaver.model.DBPHiddenObject;
@@ -140,9 +141,6 @@ public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject,
case PROJECT_ADD:
addProjectNode(event.getProject());
break;
case PROJECT_UPDATE:
updateProjectNode(event.getProject());
break;
}
}
@@ -189,14 +187,4 @@ public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject,
private void addProjectNode(RMProject project) {
projects = ArrayUtils.add(DBNResourceManagerProject.class, projects, new DBNResourceManagerProject(this, project));
}
private void updateProjectNode(@NotNull RMProject project) {
var projectNode = getProjectNode(project);
projectNode.ifPresent(
dbnResourceManagerProject -> {
dbnResourceManagerProject.getProject().setName(project.getName());
dbnResourceManagerProject.getProject().setDescription(project.getDescription());
}
);
}
}
@@ -99,7 +99,7 @@ public abstract class BaseLocalResourceController implements RMController {
@NotNull String propName,
@NotNull Object propValue
) throws DBException {
RMLocalProject webProject = getWebProject(projectId, false);
BaseWebProjectImpl webProject = getWebProject(projectId, false);
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
() -> {
log.debug("Updating value for property '" + propName + "' in project '" + projectId + "'");
@@ -284,7 +284,7 @@ public abstract class BaseLocalResourceController implements RMController {
}
}
protected abstract RMLocalProject getWebProject(String projectId, boolean refresh) throws DBException;
protected abstract BaseWebProjectImpl getWebProject(String projectId, boolean refresh) throws DBException;
protected abstract <T> T doFileWriteOperation(String projectId, Path file, RMFileOperation<T> operation)
throws DBException;
@@ -16,12 +16,12 @@
*/
package io.cloudbeaver.model.rm.local;
import io.cloudbeaver.BaseWebProjectImpl;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.model.app.ServletApplication;
import io.cloudbeaver.service.security.SMUtils;
import io.cloudbeaver.service.sql.WebSQLConstants;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebRMUtils;
import io.cloudbeaver.utils.file.UniversalFileVisitor;
import org.eclipse.core.runtime.IPath;
import org.jkiss.code.NotNull;
@@ -81,7 +81,7 @@ public class LocalResourceController extends BaseLocalResourceController {
private Supplier<SMController> smControllerSupplier;
protected final List<RMFileOperationHandler> fileHandlers;
private final Map<String, RMLocalProject> projectRegistries = new LinkedHashMap<>();
private final Map<String, BaseWebProjectImpl> projectRegistries = new LinkedHashMap<>();
public LocalResourceController(
DBPWorkspace workspace,
@@ -116,11 +116,13 @@ public class LocalResourceController extends BaseLocalResourceController {
return userId == null ? null : this.userProjectsPath.resolve(userId);
}
protected RMLocalProject getWebProject(String projectId, boolean refresh) throws DBException {
protected BaseWebProjectImpl getWebProject(String projectId, boolean refresh) throws DBException {
synchronized (projectRegistries) {
RMLocalProject project = projectRegistries.get(projectId);
BaseWebProjectImpl project = projectRegistries.get(projectId);
if (project == null || refresh) {
project = createWebProjectImpl(projectId, new SessionContextImpl(null));
SessionContextImpl sessionContext = new SessionContextImpl(null);
RMProject rmProject = makeProjectFromId(projectId, false);
project = createWebProjectImpl(projectId, sessionContext, rmProject);
projectRegistries.put(projectId, project);
}
return project;
@@ -128,11 +130,12 @@ public class LocalResourceController extends BaseLocalResourceController {
}
@NotNull
protected RMLocalProject createWebProjectImpl(
@NotNull String projectId,
@NotNull SessionContextImpl sessionContext
protected InternalWebProjectImpl createWebProjectImpl(
String projectId,
SessionContextImpl sessionContext,
RMProject rmProject
) throws DBException {
return new RMLocalProject(workspace, sessionContext, getProjectPath(projectId), WebRMUtils.parseProjectName(projectId).getType());
return new InternalWebProjectImpl(sessionContext, rmProject, getProjectPath(projectId));
}
@NotNull
@@ -187,7 +190,7 @@ public class LocalResourceController extends BaseLocalResourceController {
.stream()
.filter(smObjectPermissions -> CommonUtils.isNotEmpty(smObjectPermissions.getObjectId()))
.map(projectPermission -> makeProjectFromPath(
sharedProjectsPath.resolve(WebRMUtils.parseProjectNameUnsafe(projectPermission.getObjectId()).getName()),
sharedProjectsPath.resolve(parseProjectNameUnsafe(projectPermission.getObjectId()).getName()),
Arrays.stream(projectPermission.getPermissions()).map(RMProjectPermission::fromPermission).collect(Collectors.toSet()),
RMProjectType.SHARED, true)
)
@@ -253,7 +256,7 @@ public class LocalResourceController extends BaseLocalResourceController {
var allPaths = list.toList();
for (Path path : allPaths) {
var projectPerms = getProjectPermissions(
RMUtils.makeProjectIdFromPath(path, RMProjectType.SHARED),
makeProjectIdFromPath(path, RMProjectType.SHARED),
RMProjectType.SHARED
);
var rmProject = makeProjectFromPath(path, projectPerms, RMProjectType.SHARED, false);
@@ -278,54 +281,28 @@ public class LocalResourceController extends BaseLocalResourceController {
}
}
validateResourcePath(name);
validateProjectName(null, name);
RMProject project;
var projectPath = sharedProjectsPath.resolve(name);
if (Files.exists(projectPath)) {
throw new DBException("Project '" + name + "' already exists");
}
RMLocalProject webProject = new RMLocalProject(workspace, new SessionContextImpl(null), projectPath, RMProjectType.SHARED);
webProject.updateProject(name, description);
RMProject rmProject = createRmProjectFromWebProject(projectPath, webProject, new String[0]);
project = makeProjectFromPath(projectPath, Set.of(), RMProjectType.SHARED, false);
if (project == null) {
throw new DBException("Project '" + name + "' not created");
}
try {
log.debug("Creating project '" + rmProject.getId() + "'");
log.debug("Creating project '" + project.getId() + "'");
Files.createDirectories(projectPath);
if (ServletAppUtils.getServletApplication().isMultiNode()) {
createResourceTypeFolders(projectPath);
}
fireRmProjectAddEvent(rmProject);
return rmProject;
fireRmProjectAddEvent(project);
return project;
} catch (IOException e) {
throw new DBException("Error creating project path", e);
}
}
@Override
public RMProject updateProject(@NotNull String projectId, @NotNull RMProjectInfo projectInfo) throws DBException {
validateProjectName(projectId, projectInfo.getName());
try (var projectLock = lockController.lock(projectId, "updateProject")) {
RMLocalProject project = getWebProject(projectId, false);
Path targetPath = getProjectPath(projectId);
if (!Files.exists(targetPath)) {
throw new DBException("Project folder '" + projectId + "' not found");
}
if (!project.canUpdateProjectName()) {
throw new DBException("Project '" + projectId + "' is not shared");
}
project.updateProject(projectInfo.getName(), projectInfo.getDescription());
return WebRMUtils.createRmProjectFromWebProject(project);
}
}
private void validateProjectName(@Nullable String projectId, @Nullable String name) throws DBException {
boolean duplicatedName = Arrays.stream(listAllSharedProjects())
.filter(p -> !p.getId().equals(projectId))
.map(RMProject::getName)
.noneMatch(n -> n.equalsIgnoreCase(name));
if (!duplicatedName) {
throw new DBException("Project name '" + name + "' is already used");
}
}
@Override
public void deleteProject(@NotNull String projectId) throws DBException {
try (var projectLock = lockController.lock(projectId, "deleteProject")) {
@@ -898,7 +875,7 @@ public class LocalResourceController extends BaseLocalResourceController {
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "resourcePropertyUpdate")) {
validateResourcePath(resourcePath);
RMLocalProject webProject = getWebProject(projectId, false);
BaseWebProjectImpl webProject = getWebProject(projectId, false);
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
() -> {
log.debug("Updating resource property '" + propertyName + "' in project '" + projectId + "'");
@@ -919,7 +896,7 @@ public class LocalResourceController extends BaseLocalResourceController {
) throws DBException {
try (var ignoredLock = lockController.lock(projectId, "resourcePropertyUpdate")) {
validateResourcePath(resourcePath);
RMLocalProject webProject = getWebProject(projectId, false);
BaseWebProjectImpl webProject = getWebProject(projectId, false);
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
() -> {
log.debug("Updating resource '" + resourcePath + "' properties in project '" + projectId + "'");
@@ -953,9 +930,15 @@ public class LocalResourceController extends BaseLocalResourceController {
}
}
private String makeProjectIdFromPath(Path path, RMProjectType type) {
String projectName = path.getFileName().toString();
return type.getPrefix() + "_" + projectName;
}
@Nullable
protected RMProject makeProjectFromId(String projectId, boolean loadPermissions) throws DBException {
var projectName = WebRMUtils.parseProjectName(projectId);
var projectName = parseProjectName(projectId);
var projectPath = getProjectPath(projectId);
if (!Files.exists(projectPath)) {
if (isPrivateProject(projectId) && isProjectOwner(projectId)) {
@@ -992,8 +975,28 @@ public class LocalResourceController extends BaseLocalResourceController {
.flatMap(rmProjectPermission -> rmProjectPermission.getAllPermissions().stream())
.toArray(String[]::new);
RMLocalProject webProject = new RMLocalProject(workspace, new SessionContextImpl(null), path, type);
return createRmProjectFromWebProject(path, webProject, allProjectPermissions);
RMProject project = new RMProject();
String projectName = path.getFileName().toString();
project.setName(projectName);
project.setId(makeProjectIdFromPath(path, type));
project.setType(type);
project.setProjectPermissions(allProjectPermissions);
if (Files.exists(path)) {
try {
project.setCreateTime(
OffsetDateTime.ofInstant(Files.getLastModifiedTime(path).toInstant(), ZoneId.of("UTC")).toInstant().toEpochMilli());
} catch (IOException e) {
log.error(e);
}
}
// Resource types
project.setResourceTypes(ResourceTypeRegistry.getInstance().getResourceTypes()
.stream()
.filter(ResourceTypeDescriptor::isManagable)
.map(RMResourceType::new)
.toArray(RMResourceType[]::new));
return project;
}
private void createResourceTypeFolders(Path path) {
@@ -1072,7 +1075,7 @@ public class LocalResourceController extends BaseLocalResourceController {
}
protected Path getProjectPath(String projectId) throws DBException {
RMProjectName project = WebRMUtils.parseProjectName(projectId);
RMProjectName project = parseProjectName(projectId);
RMProjectType type = project.getType();
String projectName = project.getName();
switch (type) {
@@ -1234,13 +1237,56 @@ public class LocalResourceController extends BaseLocalResourceController {
}
}
public static class RMProjectName {
String prefix;
String name;
private RMProjectName(String prefix, String name) {
this.prefix = prefix;
this.name = name;
}
public String getPrefix() {
return prefix;
}
public String getName() {
return name;
}
public RMProjectType getType() {
return RMProjectType.getByPrefix(prefix);
}
}
public static RMProjectName parseProjectName(String projectId) throws DBException {
if (CommonUtils.isEmpty(projectId)) {
throw new DBException("Project id is empty");
}
return parseProjectNameUnsafe(projectId);
}
private static RMProjectName parseProjectNameUnsafe(String projectId) {
String prefix;
String name;
int divPos = projectId.indexOf("_");
if (divPos < 0) {
prefix = RMProjectType.USER.getPrefix();
name = projectId;
} else {
prefix = projectId.substring(0, divPos);
name = projectId.substring(divPos + 1);
}
return new RMProjectName(prefix, name);
}
public static boolean isGlobalProject(String projectId) {
RMProjectName rmProjectName = WebRMUtils.parseProjectNameUnsafe(projectId);
RMProjectName rmProjectName = parseProjectNameUnsafe(projectId);
return RMProjectType.GLOBAL.getPrefix().equals(rmProjectName.getPrefix());
}
public static boolean isPrivateProject(String projectId) {
RMProjectName rmProjectName = WebRMUtils.parseProjectNameUnsafe(projectId);
RMProjectName rmProjectName = parseProjectNameUnsafe(projectId);
return RMProjectType.USER.getPrefix().equals(rmProjectName.getPrefix());
}
@@ -1251,32 +1297,9 @@ public class LocalResourceController extends BaseLocalResourceController {
}
public static boolean isProjectOwner(String projectId, String userId) {
RMProjectName rmProjectName = WebRMUtils.parseProjectNameUnsafe(projectId);
RMProjectName rmProjectName = parseProjectNameUnsafe(projectId);
return RMProjectType.USER.getPrefix().equals(rmProjectName.getPrefix()) &&
rmProjectName.name.equals(userId);
}
@NotNull
private static RMProject createRmProjectFromWebProject(Path path, RMLocalProject webProject, String[] allProjectPermissions) {
RMProject project = WebRMUtils.createRmProjectFromWebProject(webProject);
project.setProjectPermissions(allProjectPermissions);
if (Files.exists(path)) {
try {
project.setCreateTime(
OffsetDateTime.ofInstant(Files.getLastModifiedTime(path).toInstant(), ZoneId.of("UTC")).toInstant().toEpochMilli());
} catch (IOException e) {
log.error(e);
}
}
// Resource types
project.setResourceTypes(ResourceTypeRegistry.getInstance().getResourceTypes()
.stream()
.filter(ResourceTypeDescriptor::isManagable)
.map(RMResourceType::new)
.toArray(RMResourceType[]::new));
return project;
}
}
@@ -1,147 +0,0 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.model.rm.local;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.impl.app.BaseProjectImpl;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.rm.RMUtils;
import org.jkiss.dbeaver.registry.DataSourceRegistry;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.Pair;
import java.nio.file.Path;
import java.util.Collection;
public class RMLocalProject extends BaseProjectImpl {
@NotNull
private final Path projectPath;
@NotNull
private final RMProjectType projectType;
public RMLocalProject(
@NotNull DBPWorkspace workspace,
@Nullable SMSessionContext sessionContext,
@NotNull Path projectPath,
@NotNull RMProjectType type
) {
super(workspace, sessionContext);
this.projectPath = projectPath;
this.projectType = type;
}
@Override
public boolean isVirtual() {
return true;
}
@NotNull
@Override
public String getId() {
return RMUtils.makeProjectIdFromPath(projectPath, projectType);
}
@NotNull
@Override
public String getName() {
Object projectName = this.getProjectProperty(PROP_PROJECT_NAME);
if (projectName != null) {
return projectName.toString();
}
return projectPath.getFileName().toString();
}
@NotNull
@Override
public Path getAbsolutePath() {
return projectPath;
}
@Override
public boolean isOpen() {
return true;
}
@Override
public void ensureOpen() {
}
@Override
public boolean isUseSecretStorage() {
return false;
}
public Path getMetadataFilePath() {
return getMetadataPath().resolve(METADATA_STORAGE_FILE);
}
/**
* Method for Bulk Update of resources properties paths
*
* @param oldToNewPaths collection of OldPath to NewPath pairs
*/
public void moveResourcePropertiesBatch(@NotNull Collection<Pair<String, String>> oldToNewPaths) {
loadMetadata();
synchronized (metadataSync) {
for (var pathsPair : oldToNewPaths) {
final var oldResourcePath = CommonUtils.normalizeResourcePath(pathsPair.getFirst());
final var newResourcePath = CommonUtils.normalizeResourcePath(pathsPair.getSecond());
final var resProps = resourceProperties.remove(oldResourcePath);
if (resProps != null) {
resourceProperties.put(newResourcePath, resProps);
}
}
}
flushMetadata();
}
/**
* Method for Bulk Remove of resources properties
*/
public boolean resetResourcesPropertiesBatch(@NotNull Collection<String> resourcesPaths) {
loadMetadata();
boolean propertiesChanged = false;
synchronized (metadataSync) {
for (var resourcePath : resourcesPaths) {
var removedProperties = resourceProperties.remove(CommonUtils.normalizeResourcePath(resourcePath));
if (removedProperties != null) {
propertiesChanged = true;
}
}
}
if (propertiesChanged) {
flushMetadata();
}
return propertiesChanged;
}
public boolean canUpdateProjectName() {
return RMProjectType.SHARED.equals(projectType);
}
@NotNull
@Override
protected DBPDataSourceRegistry createDataSourceRegistry() {
return new DataSourceRegistry<>(this);
}
}
@@ -1,41 +0,0 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.model.rm.local;
import org.jkiss.dbeaver.model.rm.RMProjectType;
public class RMProjectName {
String prefix;
String name;
public RMProjectName(String prefix, String name) {
this.prefix = prefix;
this.name = name;
}
public String getPrefix() {
return prefix;
}
public String getName() {
return name;
}
public RMProjectType getType() {
return RMProjectType.getByPrefix(prefix);
}
}
@@ -30,7 +30,6 @@ import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.auth.impl.AbstractSessionPersistent;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.security.user.SMTeam;
import org.jkiss.dbeaver.model.rm.RMProjectInfo;
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
import org.jkiss.dbeaver.model.websocket.event.WSEventDeleteTempFile;
import org.jkiss.dbeaver.model.websocket.event.session.WSSessionExpiredEvent;
@@ -58,7 +57,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
protected volatile long lastAccessTime;
private final List<CBWebSessionEventHandler> sessionEventHandlers = new CopyOnWriteArrayList<>();
private WebSessionEventsFilter eventsFilter;
private WebSessionEventsFilter eventsFilter = new WebSessionEventsFilter();
private final WebSessionWorkspace workspace;
public BaseWebSession(@NotNull String id, @NotNull ServletApplication application) throws DBException {
@@ -69,7 +68,6 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
this.workspace = createWebWorkspace();
this.workspace.getAuthContext().addSession(this);
this.userContext = createUserContext();
this.eventsFilter = new WebSessionEventsFilter(this);
}
@NotNull
@@ -235,11 +233,6 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
userContext.getAccessibleProjectIds().add(projectId);
}
public void updateSessionProject(@NotNull String projectId, @NotNull RMProjectInfo rmProjectInfo) throws DBException {
}
public void removeSessionProject(@Nullable String projectId) throws DBException {
userContext.getAccessibleProjectIds().remove(projectId);
}
@@ -18,10 +18,9 @@ package io.cloudbeaver.model.session;
import jakarta.servlet.http.HttpServletRequest;
import org.jkiss.code.Nullable;
import org.jkiss.utils.HttpConstants;
public class WebHttpRequestInfo {
public static final String USER_AGENT = HttpConstants.HEADER_USER_AGENT;
public static final String USER_AGENT = "User-Agent";
@Nullable
private final String id;
@@ -49,7 +49,10 @@ import org.jkiss.dbeaver.model.fs.DBFFileSystemManager;
import org.jkiss.dbeaver.model.meta.Association;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.rm.*;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.rm.RMUtils;
import org.jkiss.dbeaver.model.runtime.AbstractJob;
import org.jkiss.dbeaver.model.runtime.BaseProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
@@ -304,7 +307,7 @@ public class WebSession extends BaseWebSession
for (RMProject project : rmProjects) {
createWebProject(project);
}
if (user == null && application.isAnonymousAccessEnabled()) {
if (user == null && application.getAppConfiguration().isAnonymousAccessEnabled()) {
WebProjectImpl anonymousProject = createWebProject(RMUtils.createAnonymousProject());
anonymousProject.setInMemory(true);
}
@@ -324,7 +327,6 @@ public class WebSession extends BaseWebSession
} else {
sessionProject = createSessionProject(project);
}
sessionProject.refreshProjectSettings();
// do not load data sources for anonymous project
if (project.getType() == RMProjectType.USER && userContext.getUser() == null) {
sessionProject.setInMemory(true);
@@ -397,10 +399,9 @@ public class WebSession extends BaseWebSession
private synchronized void authAsAnonymousUser() throws DBException {
if (!application.isAnonymousAccessEnabled()) {
if (!application.getAppConfiguration().isAnonymousAccessEnabled()) {
return;
}
SMAuthInfo authInfo = getSecurityController().authenticateAnonymousUser(this.id, getSessionParameters(), CB_SESSION_TYPE);
updateSMSession(authInfo);
notifySessionAuthChange();
@@ -793,7 +794,7 @@ public class WebSession extends BaseWebSession
}
}
public List<WebAuthInfo> removeAuthInfo(String providerId, boolean needResetUserState) throws DBException {
public List<WebAuthInfo> removeAuthInfo(String providerId) throws DBException {
List<WebAuthInfo> oldInfo;
if (providerId == null) {
oldInfo = clearAuthTokens();
@@ -806,16 +807,12 @@ public class WebSession extends BaseWebSession
oldInfo = List.of();
}
}
if (authTokens.isEmpty() && needResetUserState) {
if (authTokens.isEmpty()) {
resetUserState();
}
return oldInfo;
}
public List<WebAuthInfo> removeAuthInfo(String providerId) throws DBException {
return removeAuthInfo(providerId, true);
}
public List<DBACredentialsProvider> getContextCredentialsProviders() {
return getAdapters(DBACredentialsProvider.class);
}
@@ -984,16 +981,6 @@ public class WebSession extends BaseWebSession
createWebProject(rmProject);
}
@Override
public void updateSessionProject(@NotNull String projectId, @NotNull RMProjectInfo rmProjectInfo) throws DBException {
super.updateSessionProject(projectId, rmProjectInfo);
var project = getProjectById(projectId);
if (project == null) {
return;
}
project.updateProjectInfo(rmProjectInfo.getName(), rmProjectInfo.getDescription());
}
@Override
public void removeSessionProject(@Nullable String projectId) throws DBException {
super.removeSessionProject(projectId);
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -118,8 +118,6 @@ public class WebSessionAuthProcessor {
// We may need to associate new credentials with active user
if (linkWithActiveUser) {
securityController.setCurrentUserCredentials(authProviderDescriptor.getId(), authAttrs);
//link only first(main) credentials
alreadyLoggedIn = true;
}
}
@@ -21,37 +21,18 @@ import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
import org.jkiss.dbeaver.model.websocket.event.WSProjectResourceEvent;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
public class WebSessionEventsFilter {
private final BaseWebSession session;
private final Set<String> subscribedEventTopics = new CopyOnWriteArraySet<>();
private final Set<String> subscribedProjectIds = new CopyOnWriteArraySet<>();
private final Map<String, List<WebTopicActivityListener>> topicActivityListeners = new ConcurrentHashMap<>();
private final Set<String> handledStartTopics = new CopyOnWriteArraySet<>();
public WebSessionEventsFilter(BaseWebSession session) {
this.session = session;
}
public void subscribeOnEventTopic(@Nullable String topic) {
if (topic == null) {
return;
}
subscribedEventTopics.add(topic);
topicActivityListeners
.getOrDefault(topic, List.of()).stream()
.filter(listener -> !handledStartTopics.contains(listener.getTopicName()))
.forEach(listener -> {
listener.handelStartSubscriptionTopic(session);
handledStartTopics.add(topic);
});
}
public void unsubscribeFromEventTopic(@Nullable String topic) {
@@ -86,10 +67,4 @@ public class WebSessionEventsFilter {
return true;
}
public void addTopicSubscribeListener(WebTopicActivityListener listener) {
topicActivityListeners
.computeIfAbsent(listener.getTopicName(), k -> new CopyOnWriteArrayList<>())
.add(listener);
}
}
@@ -62,12 +62,12 @@ public class WebSessionPreferenceStore extends AbstractUserPreferenceStore {
}
@Override
public String getDefaultString(@NotNull String name) {
public String getDefaultString(String name) {
return parentStore.getDefaultString(name);
}
@Override
public boolean isDefault(@NotNull String name) {
public boolean isDefault(String name) {
return !userPreferences.containsKey(name) && parentStore.isDefault(name);
}
@@ -77,7 +77,7 @@ public class WebSessionPreferenceStore extends AbstractUserPreferenceStore {
}
@Override
public void setToDefault(@NotNull String name) {
public void setToDefault(String name) {
throw new RuntimeException("Not implemented");
}
@@ -239,7 +239,7 @@ public class WebUserContext implements SMCredentialsProvider {
}
private Set<String> getDefaultPermissions() {
return application.isAnonymousAccessEnabled() ? null : Set.of();
return application.getAppConfiguration().isAnonymousAccessEnabled() ? null : Set.of();
}
public RMController getRmController() {
@@ -98,5 +98,4 @@ public class CBConstants {
public static final String BIND_SESSION_ENABLE = "enable";
public static final String BIND_SESSION_DISABLE = "disable";
public static final String DEFAULT_CLOUD_PROJECT_NAME = "GlobalConfiguration";
}
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,11 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.model.session;
package io.cloudbeaver.server;
public interface WebTopicActivityListener {
public interface HttpConstants {
String CONTENT_TYPE = "Content-Type";
void handelStartSubscriptionTopic(BaseWebSession session);
String getTopicName();
String TYPE_JSON = "application/json";
String HEADER_AUTHORIZATION = "Authorization";
}
@@ -18,7 +18,6 @@ package io.cloudbeaver.server;
import io.cloudbeaver.utils.ServletAppUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.impl.preferences.AbstractPreferenceStore;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
@@ -35,37 +34,37 @@ public class WebServerPreferenceStore extends AbstractPreferenceStore {
}
@Override
public boolean contains(@NotNull String name) {
public boolean contains(String name) {
return productConf().containsKey(name) || parentStore.contains(name);
}
@Override
public boolean getBoolean(@NotNull String name) {
public boolean getBoolean(String name) {
return toBoolean(getString(name));
}
@Override
public double getDouble(@NotNull String name) {
public double getDouble(String name) {
return toDouble(getString(name));
}
@Override
public float getFloat(@NotNull String name) {
public float getFloat(String name) {
return toFloat(getString(name));
}
@Override
public int getInt(@NotNull String name) {
public int getInt(String name) {
return toInt(getString(name));
}
@Override
public long getLong(@NotNull String name) {
public long getLong(String name) {
return toLong(getString(name));
}
@Override
public String getString(@NotNull String name) {
public String getString(String name) {
Object value = productConf().get(name);
if (value == null) {
return parentStore.getString(name);
@@ -74,38 +73,38 @@ public class WebServerPreferenceStore extends AbstractPreferenceStore {
}
@Override
public boolean getDefaultBoolean(@NotNull String name) {
public boolean getDefaultBoolean(String name) {
return getBoolean(name);
}
@Override
public double getDefaultDouble(@NotNull String name) {
public double getDefaultDouble(String name) {
return getDouble(name);
}
@Override
public float getDefaultFloat(@NotNull String name) {
public float getDefaultFloat(String name) {
return getFloat(name);
}
@Override
public int getDefaultInt(@NotNull String name) {
public int getDefaultInt(String name) {
return getInt(name);
}
@Override
public long getDefaultLong(@NotNull String name) {
public long getDefaultLong(String name) {
return getLong(name);
}
@Override
public String getDefaultString(@NotNull String name) {
public String getDefaultString(String name) {
// TODO: split product.conf and runtime.product.conf
return getString(name);
}
@Override
public boolean isDefault(@NotNull String name) {
public boolean isDefault(String name) {
return true;
}
@@ -115,68 +114,68 @@ public class WebServerPreferenceStore extends AbstractPreferenceStore {
}
@Override
public void setDefault(@NotNull String name, double value) {
public void setDefault(String name, double value) {
setDefault(name, String.valueOf(value));
}
@Override
public void setDefault(@NotNull String name, float value) {
public void setDefault(String name, float value) {
setDefault(name, String.valueOf(value));
}
@Override
public void setDefault(@NotNull String name, int value) {
public void setDefault(String name, int value) {
setDefault(name, String.valueOf(value));
}
@Override
public void setDefault(@NotNull String name, long value) {
public void setDefault(String name, long value) {
setDefault(name, String.valueOf(value));
}
@Override
public void setDefault(@NotNull String name, @Nullable String defaultObject) {
public void setDefault(String name, String defaultObject) {
// do not store global default properties in product.conf
this.parentStore.setDefault(name, defaultObject);
}
@Override
public void setDefault(@NotNull String name, boolean value) {
public void setDefault(String name, boolean value) {
setDefault(name, String.valueOf(value));
}
@Override
public void setToDefault(@NotNull String name) {
public void setToDefault(String name) {
parentStore.setToDefault(name);
}
@Override
public void setValue(@NotNull String name, double value) {
public void setValue(String name, double value) {
parentStore.setValue(name, value);
}
@Override
public void setValue(@NotNull String name, float value) {
public void setValue(String name, float value) {
parentStore.setValue(name, value);
}
@Override
public void setValue(@NotNull String name, int value) {
public void setValue(String name, int value) {
parentStore.setValue(name, value);
}
@Override
public void setValue(@NotNull String name, long value) {
public void setValue(String name, long value) {
parentStore.setValue(name, value);
}
@Override
public void setValue(@NotNull String name, @Nullable String value) {
public void setValue(String name, String value) {
parentStore.setValue(name, value);
}
@Override
public void setValue(@NotNull String name, boolean value) {
public void setValue(String name, boolean value) {
parentStore.setValue(name, value);
}
@@ -23,7 +23,6 @@ import com.google.gson.Strictness;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebSessionProjectImpl;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.session.WebSession;
@@ -31,25 +30,21 @@ import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.access.DBAAuthCredentials;
import org.jkiss.dbeaver.model.access.DBAAuthCredentialsWithComplexProperties;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDataSourceProviderDescriptor;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNativeCredentials;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.ssh.SSHConstants;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceDisconnectEvent;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.CommonUtils;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class WebDataSourceUtils {
@@ -224,181 +219,4 @@ public class WebDataSourceUtils {
}
credGson.fromJson(credGson.toJsonTree(properties), credentials.getClass());
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials
) {
saveAuthProperties(dataSourceContainer, configuration, authProperties, saveCredentials, sharedCredentials, false);
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials,
boolean isTest
) {
dataSourceContainer.setSavePassword(saveCredentials);
dataSourceContainer.setSharedCredentials(sharedCredentials);
if (!saveCredentials) {
// Reset credentials
if (authProperties == null) {
authProperties = new LinkedHashMap<>();
}
authProperties.replace(AuthModelDatabaseNativeCredentials.PROP_USER_PASSWORD, null);
dataSourceContainer.resetPassword();
} else {
if (authProperties == null) {
// No changes
return;
}
}
{
// Read save credentials
DBAAuthCredentials credentials = configuration.getAuthModel().loadCredentials(dataSourceContainer, configuration);
if (isTest) {
var currentAuthProps = new HashMap<String, String>();
for (Map.Entry<String, Object> stringObjectEntry : authProperties.entrySet()) {
var value = stringObjectEntry.getValue() == null ? null : stringObjectEntry.getValue().toString();
currentAuthProps.put(stringObjectEntry.getKey(), value);
}
configuration.setAuthProperties(currentAuthProps);
}
if (!authProperties.isEmpty()) {
updateCredentialsFromProperties(credentials, authProperties);
}
configuration.getAuthModel().saveCredentials(dataSourceContainer, configuration, credentials);
}
}
public static void setConnectionConfiguration(
@NotNull DBPDriver driver,
@NotNull DBPConnectionConfiguration dsConfig,
@NotNull WebConnectionConfig config
) {
setMainProperties(dsConfig, config);
if (config.getProperties() != null) {
Map<String, String> newProps = new LinkedHashMap<>();
for (Map.Entry<String, Object> pe : config.getProperties().entrySet()) {
newProps.put(pe.getKey(), CommonUtils.toString(pe.getValue()));
}
dsConfig.setProperties(newProps);
}
if (config.getUserName() != null) {
dsConfig.setUserName(config.getUserName());
}
if (config.getUserPassword() != null) {
dsConfig.setUserPassword(config.getUserPassword());
}
if (config.getAuthModelId() != null) {
dsConfig.setAuthModelId(config.getAuthModelId());
}
if (config.getKeepAliveInterval() >= 0) {
dsConfig.setKeepAliveInterval(config.getKeepAliveInterval());
}
if (config.isDefaultAutoCommit() != null) {
dsConfig.getBootstrap().setDefaultAutoCommit(config.isDefaultAutoCommit());
}
dsConfig.getBootstrap().setDefaultCatalogName(config.getDefaultCatalogName());
dsConfig.getBootstrap().setDefaultSchemaName(config.getDefaultSchemaName());
// Save provider props
if (config.getProviderProperties() != null) {
dsConfig.setProviderProperties(new LinkedHashMap<>());
for (Map.Entry<String, Object> e : config.getProviderProperties().entrySet()) {
dsConfig.setProviderProperty(e.getKey(), CommonUtils.toString(e.getValue()));
}
}
if (config.getConfigurationType() != null) {
dsConfig.setConfigurationType(config.getConfigurationType());
}
if (CommonUtils.isEmpty(config.getUrl())) {
dsConfig.setUrl(driver.getConnectionURL(dsConfig));
}
// Save network handlers
if (config.getNetworkHandlersConfig() != null) {
for (WebNetworkHandlerConfigInput nhc : config.getNetworkHandlersConfig()) {
DBWHandlerConfiguration handlerConfig = dsConfig.getHandler(nhc.getId());
if (handlerConfig == null) {
NetworkHandlerDescriptor handlerDescriptor = NetworkHandlerRegistry.getInstance().getDescriptor(nhc.getId());
if (handlerDescriptor == null) {
log.warn("Can't find network handler '" + nhc.getId() + "'");
continue;
} else {
handlerConfig = new DBWHandlerConfiguration(handlerDescriptor, null);
WebDataSourceUtils.updateHandlerConfig(handlerConfig, nhc);
}
} else {
WebDataSourceUtils.updateHandlerConfig(handlerConfig, nhc);
}
dsConfig.updateHandler(handlerConfig);
}
}
}
public static void setMainProperties(@NotNull DBPConnectionConfiguration dsConfig, @NotNull WebConnectionConfig config) {
if (CommonUtils.isNotEmpty(config.getUrl())) {
dsConfig.setUrl(config.getUrl());
return;
}
if (config.getMainPropertyValues() != null) {
for (Map.Entry<String, Object> e : config.getMainPropertyValues().entrySet()) {
if (e.getValue() == null) {
continue;
}
switch (e.getKey()) {
case DBConstants.PROP_HOST -> dsConfig.setHostName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_PORT -> dsConfig.setHostPort(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_DATABASE -> dsConfig.setDatabaseName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_SERVER -> dsConfig.setServerName(CommonUtils.toString(e.getValue()));
default -> throw new IllegalStateException("Unexpected value: " + e.getKey());
}
}
return;
}
if (config.getHost() != null) {
dsConfig.setHostName(config.getHost());
}
if (config.getPort() != null) {
dsConfig.setHostPort(config.getPort());
}
if (config.getDatabaseName() != null) {
dsConfig.setDatabaseName(config.getDatabaseName());
}
if (config.getServerName() != null) {
dsConfig.setServerName(config.getServerName());
}
}
@NotNull
public static DBPDriver getDriverById(String id) throws DBWebException {
int divPos = id.indexOf(':');
if (divPos < 0) {
throw new DBWebException("Bad driver id [" + id + "]");
}
String dsId = id.substring(0, divPos);
String driverId = id.substring(divPos + 1);
DBPDataSourceProviderDescriptor dsProvider = DBWorkbench.getPlatform().getDataSourceProviderRegistry().getDataSourceProvider(dsId);
if (dsProvider == null) {
throw new DBWebException("Data source provider '" + dsId + "' not found");
}
DBPDriver driver = dsProvider.getDriver(driverId);
if (driver == null) {
throw new DBWebException("Driver '" + driverId + "' not found in provider '" + dsId + "'");
}
return driver;
}
public static String getConnectionContainerInfo(@Nullable DBPDataSourceContainer container) {
if (container == null) {
return null;
}
return container.getName() + " [" + container.getId() + "]";
}
}
@@ -1,42 +0,0 @@
package io.cloudbeaver.utils;
import io.cloudbeaver.model.rm.local.RMProjectName;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.utils.CommonUtils;
public class WebRMUtils {
public static RMProject createRmProjectFromWebProject(@NotNull DBPProject project) {
RMProject rmProject = new RMProject();
rmProject.setId(project.getId());
rmProject.setName(project.getName());
rmProject.setDescription(project.getDescription());
rmProject.setType(parseProjectNameUnsafe(rmProject.getId()).getType());
return rmProject;
}
public static RMProjectName parseProjectName(@NotNull String projectId) throws DBException {
if (CommonUtils.isEmpty(projectId)) {
throw new DBException("Project id is empty");
}
return parseProjectNameUnsafe(projectId);
}
public static RMProjectName parseProjectNameUnsafe(String projectId) {
String prefix;
String name;
int divPos = projectId.indexOf("_");
if (divPos < 0) {
prefix = RMProjectType.USER.getPrefix();
name = projectId;
} else {
prefix = projectId.substring(0, divPos);
name = projectId.substring(divPos + 1);
}
return new RMProjectName(prefix, name);
}
}
@@ -1,53 +0,0 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.websocket;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.websocket.WSConstants;
import org.jkiss.dbeaver.model.websocket.event.session.WSAbstractSessionEvent;
public class WSServerNotificationEvent extends WSAbstractSessionEvent {
public static final String EVENT_ID = "cb_server_notification";
private String title;
private String message;
private WSServerNotificationEventType notificationType;
public WSServerNotificationEvent(
@Nullable String title,
@Nullable String message,
@NotNull WSServerNotificationEventType notificationType
) {
super(EVENT_ID, WSConstants.TOPIC_USER_NOTIFICATION);
this.title = title;
this.message = message;
this.notificationType = notificationType;
}
public String getTitle() {
return title;
}
public String getMessage() {
return message;
}
public WSServerNotificationEventType getNotificationType() {
return notificationType;
}
}
@@ -1,24 +0,0 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.websocket;
public enum WSServerNotificationEventType {
INFO,
ERROR,
LOADING,
CUSTOM
}
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Community Product
Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true
Bundle-Version: 25.2.2.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 25.2.1.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.product.ce</artifactId>
<version>25.2.2-SNAPSHOT</version>
<version>25.2.1-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Cloudbeaver Base JDBC drivers
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
Bundle-Version: 1.0.131.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.130.qualifier
Bundle-Release-Date: 20250922
Bundle-Vendor: DBeaver Corp
Bundle-ActivationPolicy: lazy
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
@@ -9,6 +9,6 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.resources.drivers.base</artifactId>
<version>1.0.131-SNAPSHOT</version>
<version>1.0.130-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver CE Server
Bundle-SymbolicName: io.cloudbeaver.server.ce;singleton:=true
Bundle-Version: 25.2.2.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 25.2.1.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.server.ce</artifactId>
<version>25.2.2-SNAPSHOT</version>
<version>25.2.1-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -30,6 +30,8 @@ import io.cloudbeaver.registry.WebDriverRegistry;
import io.cloudbeaver.registry.WebFeatureRegistry;
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.server.jetty.CBJettyServer;
import io.cloudbeaver.service.ConnectionController;
import io.cloudbeaver.service.ConnectionControllerCE;
import io.cloudbeaver.service.DBWServiceInitializer;
import io.cloudbeaver.service.DBWServiceServerConfigurator;
import io.cloudbeaver.service.session.CBSessionManager;
@@ -503,10 +505,9 @@ public abstract class CBApplication<T extends CBServerConfig>
return "";
}
@Nullable
@Override
public String getDefaultProjectName() {
return CBConstants.DEFAULT_CLOUD_PROJECT_NAME;
return "GlobalConfiguration";
}
public boolean isDevelMode() {
@@ -783,6 +784,11 @@ public abstract class CBApplication<T extends CBServerConfig>
return new CBWebServerConfig(this);
}
@Override
public ConnectionController getConnectionController() {
return new ConnectionControllerCE();
}
@NotNull
@Override
public ServletSystemInformationCollector<?> getSystemInformationCollector() {
@@ -36,6 +36,8 @@ import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.auth.SMAuthInfo;
import org.jkiss.dbeaver.model.security.user.SMAuthPermissions;
import org.jkiss.dbeaver.model.websocket.event.WSAbstractEvent;
import org.jkiss.dbeaver.model.websocket.event.WSUserDeletedEvent;
import org.jkiss.dbeaver.model.websocket.event.WSUserDisabledEvent;
import org.jkiss.dbeaver.model.websocket.event.session.WSSessionStateEvent;
import org.jkiss.utils.CommonUtils;
@@ -70,19 +72,13 @@ public class CBSessionManager implements WebAppSessionManager {
@Override
public BaseWebSession closeSession(@NotNull String sessionId) {
return closeSession(sessionId, true);
}
@Override
public BaseWebSession closeSession(@NotNull String sessionId, boolean sendSessionExpiredEvent) {
BaseWebSession webSession;
synchronized (sessionMap) {
webSession = sessionMap.remove(sessionId);
}
if (webSession != null) {
log.debug("> Close session '" + sessionId + "'");
webSession.close(true, sendSessionExpiredEvent);
webSession.close();
return webSession;
}
return null;
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Server
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
Bundle-Version: 25.2.2.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 25.2.1.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
+1 -1
View File
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.server</artifactId>
<version>25.2.2-SNAPSHOT</version>
<version>25.2.1-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -45,8 +45,6 @@ enum CBServerEventId {
"Resource manager project added"
cb_rm_project_added,
"Resource manager project added"
cb_rm_project_updated,
"Resource manager project removed"
cb_rm_project_removed,
@@ -66,9 +64,7 @@ enum CBServerEventId {
"Session async task info updated"
cb_session_task_info_updated @since(version: "24.3.1"),
"Workspace configuration updated"
cb_workspace_config_changed @since(version: "25.1.1"),
"Server notification"
cb_server_notification@since(version: "25.2.1")
cb_workspace_config_changed @since(version: "25.1.1")
}
"Events sent by client"
@@ -100,7 +96,6 @@ enum CBEventTopic {
cb_transaction @since(version: "24.3.3"),
cb_workspace_configuration @since(version: "25.1.1")
cb_ai @since(version: "25.1.1")
cb_notification @since(version: "25.2.1")
}
"Base server event interface"
@@ -279,21 +274,6 @@ type WSAIChatMessageErrorEvent implements CBServerEvent @since(version: "25.1.1"
errorMessage: String
}
enum WSServerNotificationEventType {
INFO
ERROR
LOADING
CUSTOM
}
"General event for showing user notification"
type WSServerNotificationEvent implements CBServerEvent @since(version: "25.2.1") {
id: CBServerEventId!
topicId: CBEventTopic!
title: String
message: String
notificationType: WSServerNotificationEventType!
}
extend type Query {
emptyEvent: Boolean
}
@@ -119,8 +119,6 @@ type DatabaseStructContainers {
schemaList: [ NavigatorNodeInfo! ]!
supportsCatalogChange: Boolean!
supportsSchemaChange: Boolean!
defaultCatalog: String @since(version: "25.2.2")
defaultSchema: String @since(version: "25.2.2")
}
####################################################
@@ -18,7 +18,10 @@ package io.cloudbeaver;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.WebPropertyInfo;
import io.cloudbeaver.model.app.ServletApplication;
import io.cloudbeaver.model.app.WebAppConfiguration;
import io.cloudbeaver.model.rm.DBNResourceManagerResource;
import io.cloudbeaver.model.session.WebActionParameters;
@@ -27,6 +30,7 @@ import io.cloudbeaver.model.utils.ConfigurationUtils;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.registry.WebAuthProviderRegistry;
import io.cloudbeaver.server.WebAppUtils;
import io.cloudbeaver.server.WebApplication;
import io.cloudbeaver.service.navigator.WebPropertyFilter;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebCommonUtils;
@@ -35,14 +39,25 @@ import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.access.DBAAuthCredentials;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.model.impl.auth.AuthModelDatabaseNativeCredentials;
import org.jkiss.dbeaver.model.navigator.*;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
import org.jkiss.dbeaver.registry.DataSourceProviderDescriptor;
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
import org.jkiss.dbeaver.registry.driver.DriverDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.runtime.properties.PropertyCollector;
import org.jkiss.utils.CommonUtils;
@@ -59,6 +74,25 @@ public class WebServiceUtils extends WebCommonUtils {
private static final Gson gson = new GsonBuilder().create();
@NotNull
public static DBPDriver getDriverById(String id) throws DBWebException {
int divPos = id.indexOf(':');
if (divPos < 0) {
throw new DBWebException("Bad driver id [" + id + "]");
}
String dsId = id.substring(0, divPos);
String driverId = id.substring(divPos + 1);
DataSourceProviderDescriptor dsProvider = DataSourceProviderRegistry.getInstance().getDataSourceProvider(dsId);
if (dsProvider == null) {
throw new DBWebException("Data source provider '" + dsId + "' not found");
}
DriverDescriptor driver = dsProvider.getDriver(driverId);
if (driver == null) {
throw new DBWebException("Driver '" + driverId + "' not found in provider '" + dsId + "'");
}
return driver;
}
@NotNull
public static DBPDataSourceRegistry getGlobalDataSourceRegistry() throws DBWebException {
return WebDataSourceUtils.getGlobalDataSourceRegistry();
@@ -68,6 +102,198 @@ public class WebServiceUtils extends WebCommonUtils {
return WebServiceUtils.class.getClassLoader().getResourceAsStream(path);
}
@NotNull
public static DBPDataSourceContainer createConnectionFromConfig(WebConnectionConfig config, DBPDataSourceRegistry registry) throws DBWebException {
DBPDataSourceContainer newDataSource;
if (!CommonUtils.isEmpty(config.getDriverId())) {
String driverId = config.getDriverId();
if (CommonUtils.isEmpty(driverId)) {
throw new DBWebException("Driver not specified");
}
DBPDriver driver = getDriverById(driverId);
DBPConnectionConfiguration dsConfig = new DBPConnectionConfiguration();
setConnectionConfiguration(driver, dsConfig, config);
newDataSource = registry.createDataSource(driver, dsConfig);
} else {
throw new DBWebException("Template connection or driver must be specified");
}
newDataSource.setSavePassword(true);
newDataSource.setName(config.getName());
newDataSource.setDescription(config.getDescription());
newDataSource.setConnectionReadOnly(config.isReadOnly());
if (config.getFolder() != null) {
newDataSource.setFolder(registry.getFolder(config.getFolder()));
}
ServletApplication app = ServletAppUtils.getServletApplication();
if (app instanceof WebApplication webApplication) {
((DataSourceDescriptor) newDataSource).setNavigatorSettings(
webApplication.getAppConfiguration().getDefaultNavigatorSettings());
}
saveAuthProperties(
newDataSource,
newDataSource.getConnectionConfiguration(),
config.getCredentials(),
config.isSaveCredentials(),
config.isSharedCredentials()
);
return newDataSource;
}
public static void setConnectionConfiguration(DBPDriver driver, DBPConnectionConfiguration dsConfig, WebConnectionConfig config) {
setMainProperties(dsConfig, config);
if (config.getProperties() != null) {
Map<String, String> newProps = new LinkedHashMap<>();
for (Map.Entry<String, Object> pe : config.getProperties().entrySet()) {
newProps.put(pe.getKey(), CommonUtils.toString(pe.getValue()));
}
dsConfig.setProperties(newProps);
}
if (config.getUserName() != null) {
dsConfig.setUserName(config.getUserName());
}
if (config.getUserPassword() != null) {
dsConfig.setUserPassword(config.getUserPassword());
}
if (config.getAuthModelId() != null) {
dsConfig.setAuthModelId(config.getAuthModelId());
}
if (config.getKeepAliveInterval() >= 0) {
dsConfig.setKeepAliveInterval(config.getKeepAliveInterval());
}
if (config.isDefaultAutoCommit() != null) {
dsConfig.getBootstrap().setDefaultAutoCommit(config.isDefaultAutoCommit());
}
dsConfig.getBootstrap().setDefaultCatalogName(config.getDefaultCatalogName());
dsConfig.getBootstrap().setDefaultSchemaName(config.getDefaultSchemaName());
// Save provider props
if (config.getProviderProperties() != null) {
dsConfig.setProviderProperties(new LinkedHashMap<>());
for (Map.Entry<String, Object> e : config.getProviderProperties().entrySet()) {
dsConfig.setProviderProperty(e.getKey(), CommonUtils.toString(e.getValue()));
}
}
if (config.getConfigurationType() != null) {
dsConfig.setConfigurationType(config.getConfigurationType());
}
if (CommonUtils.isEmpty(config.getUrl())) {
dsConfig.setUrl(driver.getConnectionURL(dsConfig));
}
// Save network handlers
if (config.getNetworkHandlersConfig() != null) {
for (WebNetworkHandlerConfigInput nhc : config.getNetworkHandlersConfig()) {
DBWHandlerConfiguration handlerConfig = dsConfig.getHandler(nhc.getId());
if (handlerConfig == null) {
NetworkHandlerDescriptor handlerDescriptor = NetworkHandlerRegistry.getInstance().getDescriptor(nhc.getId());
if (handlerDescriptor == null) {
log.warn("Can't find network handler '" + nhc.getId() + "'");
continue;
} else {
handlerConfig = new DBWHandlerConfiguration(handlerDescriptor, null);
WebDataSourceUtils.updateHandlerConfig(handlerConfig, nhc);
}
} else {
WebDataSourceUtils.updateHandlerConfig(handlerConfig, nhc);
}
dsConfig.updateHandler(handlerConfig);
}
}
}
private static void setMainProperties(DBPConnectionConfiguration dsConfig, WebConnectionConfig config) {
if (CommonUtils.isNotEmpty(config.getUrl())) {
dsConfig.setUrl(config.getUrl());
return;
}
if (config.getMainPropertyValues() != null) {
for (Map.Entry<String, Object> e : config.getMainPropertyValues().entrySet()) {
if (e.getValue() == null) {
continue;
}
switch (e.getKey()) {
case DBConstants.PROP_HOST -> dsConfig.setHostName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_PORT -> dsConfig.setHostPort(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_DATABASE -> dsConfig.setDatabaseName(CommonUtils.toString(e.getValue()));
case DBConstants.PROP_SERVER -> dsConfig.setServerName(CommonUtils.toString(e.getValue()));
default -> throw new IllegalStateException("Unexpected value: " + e.getKey());
}
}
return;
}
if (config.getHost() != null) {
dsConfig.setHostName(config.getHost());
}
if (config.getPort() != null) {
dsConfig.setHostPort(config.getPort());
}
if (config.getDatabaseName() != null) {
dsConfig.setDatabaseName(config.getDatabaseName());
}
if (config.getServerName() != null) {
dsConfig.setServerName(config.getServerName());
}
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials
) {
saveAuthProperties(dataSourceContainer, configuration, authProperties, saveCredentials, sharedCredentials, false);
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials,
boolean isTest
) {
dataSourceContainer.setSavePassword(saveCredentials);
dataSourceContainer.setSharedCredentials(sharedCredentials);
if (!saveCredentials) {
// Reset credentials
if (authProperties == null) {
authProperties = new LinkedHashMap<>();
}
authProperties.replace(AuthModelDatabaseNativeCredentials.PROP_USER_PASSWORD, null);
dataSourceContainer.resetPassword();
} else {
if (authProperties == null) {
// No changes
return;
}
}
{
// Read save credentials
DBAAuthCredentials credentials = configuration.getAuthModel().loadCredentials(dataSourceContainer, configuration);
if (isTest) {
var currentAuthProps = new HashMap<String, String>();
for (Map.Entry<String, Object> stringObjectEntry : authProperties.entrySet()) {
var value = stringObjectEntry.getValue() == null ? null : stringObjectEntry.getValue().toString();
currentAuthProps.put(stringObjectEntry.getKey(), value);
}
configuration.setAuthProperties(currentAuthProps);
}
if (!authProperties.isEmpty()) {
WebDataSourceUtils.updateCredentialsFromProperties(credentials, authProperties);
}
configuration.getAuthModel().saveCredentials(dataSourceContainer, configuration, credentials);
}
}
public static DBNBrowseSettings parseNavigatorSettings(Map<String, Object> settingsMap) {
return gson.fromJson(
gson.toJsonTree(settingsMap), DataSourceNavigatorSettings.class);
@@ -84,6 +310,13 @@ public class WebServiceUtils extends WebCommonUtils {
WebActionParameters.saveToSession(webSession, actionParameters);
}
public static String getConnectionContainerInfo(DBPDataSourceContainer container) {
if (container == null) {
return null;
}
return container.getName() + " [" + container.getId() + "]";
}
public static void refreshDatabases(WebSession session, String projectId) throws DBWebException {
DBNProject projectNode = session.getNavigatorModelOrThrow().getRoot().getProjectNode(session.getProjectById(projectId));
if (projectNode != null) {
@@ -34,8 +34,6 @@ public interface WebAppSessionManager {
BaseWebSession closeSession(@NotNull String sessionId);
BaseWebSession closeSession(@NotNull String sessionId, boolean sendSessionExpiredEvent);
@NotNull
WebSession getWebSession(
@NotNull HttpServletRequest request,
@@ -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();
}
@@ -38,13 +38,6 @@ public class WSProjectUpdatedEventHandler extends WSAbstractProjectEventHandler<
} else if (WSProjectUpdateEvent.REMOVED.equals(eventId)) {
activeUserSession.removeSessionProject(projectId);
log.info("Project '" + projectId + "' removed from '" + activeUserSession.getSessionId() + "' session");
} else if (WSProjectUpdateEvent.UPDATED.equals(eventId)) {
if (event.getProjectInfo() == null) {
log.warn("No project info provided for update event: " + event);
return;
}
activeUserSession.updateSessionProject(projectId, event.getProjectInfo());
log.info("Project '" + projectId + "' updated in '" + activeUserSession.getSessionId() + "' session");
}
activeUserSession.addSessionEvent(event);
} catch (DBException e) {
@@ -55,7 +48,7 @@ public class WSProjectUpdatedEventHandler extends WSAbstractProjectEventHandler<
@Override
protected boolean isAcceptableInSession(@NotNull BaseWebSession activeUserSession, @NotNull WSProjectUpdateEvent event) {
return !WSWebUtils.isSessionIdEquals(activeUserSession, event.getSessionId()) &&
(!event.getId().equals(WSProjectUpdateEvent.ADDED) ||
(event.getId().equals(WSProjectUpdateEvent.REMOVED) ||
activeUserSession.getUserContext().hasPermission(DBWConstants.PERMISSION_ADMIN));
}
}
@@ -32,6 +32,7 @@ import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.model.apilog.ApiCallInterceptor;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.server.HttpConstants;
import io.cloudbeaver.server.WebAppUtils;
import io.cloudbeaver.service.DBWBindingContext;
import io.cloudbeaver.service.DBWServiceBindingGraphQL;
@@ -45,7 +46,6 @@ import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.HttpConstants;
import org.jkiss.utils.IOUtils;
import java.io.IOException;
@@ -146,7 +146,7 @@ public class GraphQLEndpoint extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
String contentType = request.getContentType();
if (CommonUtils.isEmpty(contentType) || !contentType.startsWith(HttpConstants.CONTENT_TYPE_JSON)) {
if (CommonUtils.isEmpty(contentType) || !contentType.startsWith(HttpConstants.TYPE_JSON)) {
String error = "Bad request," + (CommonUtils.isEmpty(contentType)
? " content type is missing"
: " incorrect content type:" + contentType);
@@ -18,6 +18,7 @@ package io.cloudbeaver.server.websockets;
import io.cloudbeaver.model.session.WebHeadlessSession;
import io.cloudbeaver.model.session.WebHttpRequestInfo;
import io.cloudbeaver.server.HttpConstants;
import io.cloudbeaver.server.WebAppSessionManager;
import jakarta.servlet.http.HttpSession;
import jakarta.websocket.HandshakeResponse;
@@ -32,7 +33,6 @@ import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.security.exception.SMAccessTokenExpiredException;
import org.jkiss.dbeaver.model.websocket.WSConstants;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.HttpConstants;
import org.jkiss.utils.WSClientUtils;
import java.util.List;
@@ -0,0 +1,99 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.service;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebObjectId;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import java.util.List;
import java.util.Map;
public interface ConnectionController {
DBPDataSourceContainer createDataSourceContainer(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull WebConnectionConfig connectionConfig
) throws DBWebException;
WebConnectionInfo createConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
DBPDataSourceRegistry sessionRegistry,
DBPDataSourceContainer newDataSource
) throws DBWebException;
DBPDataSourceContainer getDatasourceConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull WebConnectionConfig connectionConfig) throws DBWebException;
WebConnectionInfo updateConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig config,
DBPDataSourceContainer dataSource,
DBPDataSourceRegistry sessionRegistry
) throws DBWebException;
boolean deleteConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull String connectionId) throws DBWebException;
DataSourceDescriptor prepareTestConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig) throws DBWebException;
WebConnectionInfo testConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig,
DataSourceDescriptor dataSource
) throws DBWebException;
WebConnectionInfo getConnectionState(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId
) throws DBWebException;
WebConnectionInfo initConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId,
@NotNull Map<String, Object> authProperties,
@Nullable List<WebNetworkHandlerConfigInput> networkCredentials,
boolean saveCredentials,
boolean sharedCredentials,
@Nullable String selectedSecretId
) throws DBWebException;
void validateConnection(DBPDataSourceContainer dataSourceContainer) throws DBWebException;
}
@@ -0,0 +1,496 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.service;
import io.cloudbeaver.*;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.exec.DBCConnectException;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.DBWHandlerType;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.secret.DBSSecretValue;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.dbeaver.runtime.jobs.ConnectionTestJob;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;
import java.util.List;
import java.util.Map;
public class ConnectionControllerCE implements ConnectionController {
private static final Log log = Log.getLog(ConnectionController.class);
@Override
public DBPDataSourceContainer createDataSourceContainer(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig
) throws DBWebException {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
var rmProject = project.getRMProject();
if (rmProject.getType() == RMProjectType.USER
&& !webSession.hasPermission(DBWConstants.PERMISSION_ADMIN)
&& !ServletAppUtils.getServletApplication().getAppConfiguration().isSupportsCustomConnections()
) {
throw new DBWebException("New connection create is restricted by server configuration");
}
webSession.addInfoMessage("Create new connection");
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
DBPDataSourceContainer newDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig,
sessionRegistry);
if (CommonUtils.isEmpty(newDataSource.getName())) {
newDataSource.setName(CommonUtils.notNull(connectionConfig.getName(), "NewConnection"));
}
return newDataSource;
}
@Override
@NotNull
public WebConnectionInfo createConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
DBPDataSourceRegistry sessionRegistry,
DBPDataSourceContainer newDataSource
) throws DBWebException {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
try {
sessionRegistry.addDataSource(newDataSource);
sessionRegistry.checkForErrors();
} catch (DBException e) {
sessionRegistry.removeDataSource(newDataSource);
throw new DBWebException("Failed to create connection", e);
}
WebConnectionInfo connectionInfo = project.addConnection(newDataSource);
webSession.addInfoMessage("New connection was created - " + WebServiceUtils.getConnectionContainerInfo(
newDataSource));
log.info(String.format(
"New connection was created: [info=%s, user=%s]",
WebServiceUtils.getConnectionContainerInfo(newDataSource),
webSession.getUserId()
));
return connectionInfo;
}
@Override
public DBPDataSourceContainer getDatasourceConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig config
) throws DBWebException {
// Do not check for custom connection option. Already created connections can be edited.
// Also template connections can be edited
// if (!CBApplication.getInstance().getAppConfiguration().isSupportsCustomConnections()) {
// throw new DBWebException("Connection edit is restricted by server configuration");
// }
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, config.getConnectionId());
DBPDataSourceContainer dataSource = connectionInfo.getDataSourceContainer();
webSession.addInfoMessage("Update connection - " + WebServiceUtils.getConnectionContainerInfo(dataSource));
getOldDataSource(dataSource);
if (!CommonUtils.isEmpty(config.getName())) {
dataSource.setName(config.getName());
}
if (config.getDescription() != null) {
dataSource.setDescription(config.getDescription());
}
WebSessionProjectImpl project = getProjectById(webSession, projectId);
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
dataSource.setFolder(config.getFolder() != null ? sessionRegistry.getFolder(config.getFolder()) : null);
if (config.isDefaultAutoCommit() != null) {
dataSource.setDefaultAutoCommit(config.isDefaultAutoCommit());
}
dataSource.setConnectionReadOnly(config.isReadOnly());
WebServiceUtils.setConnectionConfiguration(dataSource.getDriver(),
dataSource.getConnectionConfiguration(),
config);
// we should check that the config has changed but not check for password changes
dataSource.setSharedCredentials(config.isSharedCredentials());
dataSource.setSavePassword(config.isSaveCredentials());
boolean sharedCredentials = isSharedCredentials(dataSource);
if (sharedCredentials) {
//we must notify about the shared password change
WebServiceUtils.saveAuthProperties(
dataSource,
dataSource.getConnectionConfiguration(),
config.getCredentials(),
config.isSaveCredentials(),
config.isSharedCredentials()
);
}
connectionInfo.setCredentialsSavedInSession(null);
// same here
return dataSource;
}
private static boolean isSharedCredentials(DBPDataSourceContainer dataSource) {
return dataSource.isSharedCredentials() || !dataSource.getProject()
.isUseSecretStorage() && dataSource.isSavePassword();
}
private static DataSourceDescriptor getOldDataSource(DBPDataSourceContainer dataSource) {
DataSourceDescriptor oldDataSource;
oldDataSource = dataSource.getRegistry().createDataSource(dataSource);
oldDataSource.setId(dataSource.getId());
return oldDataSource;
}
@Override
public WebConnectionInfo updateConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig config,
DBPDataSourceContainer dataSource,
DBPDataSourceRegistry sessionRegistry
) throws DBWebException {
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, config.getConnectionId());
if (!isSharedCredentials(dataSource)) {
// secret controller is responsible for notification, password changes applied after checks
WebServiceUtils.saveAuthProperties(
dataSource,
dataSource.getConnectionConfiguration(),
config.getCredentials(),
config.isSaveCredentials(),
config.isSharedCredentials()
);
}
try {
sessionRegistry.updateDataSource(dataSource);
sessionRegistry.checkForErrors();
} catch (DBException e) {
throw new DBWebException("Failed to update connection", e);
}
log.info(String.format(
"Connection updated: [info=%s, userId=%s]",
WebServiceUtils.getConnectionContainerInfo(dataSource),
webSession.getUser()
));
return connectionInfo;
}
@Override
public boolean deleteConnection(
@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId
) throws DBWebException {
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
if (connectionInfo.getDataSourceContainer().getProject() != getProjectById(webSession, projectId)) {
throw new DBWebException("Global connection '" + connectionInfo.getName() + "' configuration cannot be deleted");
}
webSession.addInfoMessage("Delete connection - " +
WebServiceUtils.getConnectionContainerInfo(connectionInfo.getDataSourceContainer()));
closeAndDeleteConnection(webSession, projectId, connectionId, true);
log.info(String.format(
"Connection deleted: [info=%s, userId=%s]",
WebServiceUtils.getConnectionContainerInfo(connectionInfo.getDataSourceContainer()),
webSession.getUserId()
));
return true;
}
@Override
public DataSourceDescriptor prepareTestConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig
) throws DBWebException {
String connectionId = connectionConfig.getConnectionId();
connectionConfig.setSaveCredentials(true); // It is used in createConnectionFromConfig
DataSourceDescriptor dataSource = (DataSourceDescriptor) WebDataSourceUtils.getLocalOrGlobalDataSource(
webSession, projectId, connectionId);
validateConnection(dataSource);
WebProjectImpl project = getProjectById(webSession, projectId);
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
DataSourceDescriptor testDataSource;
if (dataSource != null) {
try {
// Check that creds are saved to trigger secrets resolve
dataSource.isCredentialsSaved();
} catch (DBException e) {
throw new DBWebException("Can't determine whether datasource credentials are saved", e);
}
testDataSource = (DataSourceDescriptor) dataSource.createCopy(dataSource.getRegistry());
WebServiceUtils.setConnectionConfiguration(
testDataSource.getDriver(),
testDataSource.getConnectionConfiguration(),
connectionConfig
);
if (connectionConfig.getSelectedSecretId() != null) {
try {
dataSource.listSharedCredentials()
.stream()
.filter(secret -> connectionConfig.getSelectedSecretId().equals(secret.getSubjectId()))
.findFirst()
.ifPresent(testDataSource::setSelectedSharedCredentials);
} catch (DBException e) {
throw new DBWebException("Failed to load secret value: " + connectionConfig.getSelectedSecretId());
}
}
WebServiceUtils.saveAuthProperties(
testDataSource,
testDataSource.getConnectionConfiguration(),
connectionConfig.getCredentials(),
true,
false,
true
);
} else {
testDataSource = (DataSourceDescriptor) WebServiceUtils.createConnectionFromConfig(connectionConfig,
sessionRegistry);
}
return testDataSource;
}
@Override
@NotNull
public WebConnectionInfo testConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull WebConnectionConfig connectionConfig,
DataSourceDescriptor testDataSource
) throws DBWebException {
validateDriverLibrariesPresence(testDataSource);
webSession.provideAuthParameters(webSession.getProgressMonitor(),
testDataSource,
testDataSource.getConnectionConfiguration());
testDataSource.setSavePassword(true); // We need for test to avoid password callback
if (DataSourceDescriptor.class.isAssignableFrom(testDataSource.getClass())) {
testDataSource.setAccessCheckRequired(!webSession.hasPermission(DBWConstants.PERMISSION_ADMIN));
}
try {
ConnectionTestJob ct = new ConnectionTestJob(testDataSource, param -> {
});
ct.run(webSession.getProgressMonitor());
if (ct.getConnectError() != null) {
if (ct.getConnectError() instanceof DBCConnectException error) {
Throwable rootCause = CommonUtils.getRootCause(error);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(testDataSource);
}
}
throw new DBWebException("Connection failed", ct.getConnectError());
}
WebConnectionInfo connectionInfo = new WebConnectionInfo(webSession, testDataSource);
connectionInfo.setConnectError(ct.getConnectError());
connectionInfo.setServerVersion(ct.getServerVersion());
connectionInfo.setClientVersion(ct.getClientVersion());
connectionInfo.setConnectTime(RuntimeUtils.formatExecutionTime(ct.getConnectTime()));
return connectionInfo;
} catch (DBException e) {
throw new DBWebException("Error connecting to database", e);
}
}
private WebSessionProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException {
WebSessionProjectImpl project = webSession.getProjectById(projectId);
if (project == null) {
throw new DBWebException("Project '" + projectId + "' not found");
}
return project;
}
@NotNull
private WebConnectionInfo closeAndDeleteConnection(
@NotNull WebSession webSession,
@NotNull String projectId,
@NotNull String connectionId,
boolean forceDelete
) throws DBWebException {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
WebConnectionInfo connectionInfo = project.getWebConnectionInfo(connectionId);
DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer();
boolean disconnected = WebDataSourceUtils.disconnectDataSource(webSession, dataSourceContainer);
if (forceDelete) {
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
registry.removeDataSource(dataSourceContainer);
try {
registry.checkForErrors();
} catch (DBException e) {
try {
registry.addDataSource(dataSourceContainer);
} catch (DBException ex) {
log.error("Error re-adding after delete attempt", e);
}
throw new DBWebException("Failed to delete connection", e);
}
project.removeConnection(dataSourceContainer);
} else {
// Just reset saved credentials
connectionInfo.clearCache();
}
return connectionInfo;
}
@Override
public WebConnectionInfo getConnectionState(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId
) throws DBWebException {
return WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
}
@Override
public WebConnectionInfo initConnection(@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId, @NotNull Map<String, Object> authProperties, @Nullable List<WebNetworkHandlerConfigInput> networkCredentials, boolean saveCredentials, boolean sharedCredentials, @Nullable String selectedSecretId) throws DBWebException {
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
connectionInfo.setSavedCredentials(authProperties, networkCredentials);
var dataSourceContainer = connectionInfo.getDataSourceContainer();;
validateConnection(dataSourceContainer);
if (dataSourceContainer.isConnected()) {
throw new DBWebException("Datasource '" + dataSourceContainer.getName() + "' is already connected");
}
if (dataSourceContainer.isSharedCredentials() && selectedSecretId != null) {
List<DBSSecretValue> allSecrets;
try {
allSecrets = dataSourceContainer.listSharedCredentials();
} catch (DBException e) {
throw new DBWebException("Error loading connection secret", e);
}
DBSSecretValue selectedSecret =
allSecrets.stream()
.filter(secret -> selectedSecretId.equals(secret.getUniqueId()))
.findFirst().orElse(null);
if (selectedSecret == null) {
throw new DBWebException("Secret not found:" + selectedSecretId);
}
dataSourceContainer.setSelectedSharedCredentials(selectedSecret);
}
boolean oldSavePassword = dataSourceContainer.isSavePassword();
DBRProgressMonitor monitor = webSession.getProgressMonitor();
validateDriverLibrariesPresence(dataSourceContainer);
try {
boolean connect = dataSourceContainer.connect(monitor, true, false);
} catch (Exception e) {
if (e instanceof DBCConnectException) {
Throwable rootCause = CommonUtils.getRootCause(e);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(dataSourceContainer);
}
}
throw new DBWebException("Error connecting to database", e);
} finally {
dataSourceContainer.setSavePassword(oldSavePassword);
connectionInfo.clearCache();
}
// Mark all specified network configs as saved
boolean[] saveConfig = new boolean[1];
if (networkCredentials != null) {
networkCredentials.forEach(c -> {
if (CommonUtils.toBoolean(c.isSavePassword())) {
DBWHandlerConfiguration handlerCfg = dataSourceContainer.getConnectionConfiguration()
.getHandler(c.getId());
if (handlerCfg != null &&
// check username param only for ssh config
!(CommonUtils.isEmpty(c.getUserName()) && CommonUtils.equalObjects(handlerCfg.getType(),
DBWHandlerType.TUNNEL))
) {
WebDataSourceUtils.updateHandlerCredentials(handlerCfg, c);
handlerCfg.setSavePassword(true);
saveConfig[0] = true;
}
}
});
}
if (saveCredentials) {
// Save all passed credentials in the datasource container
WebServiceUtils.saveAuthProperties(
dataSourceContainer,
dataSourceContainer.getConnectionConfiguration(),
authProperties,
true,
sharedCredentials
);
var project = dataSourceContainer.getProject();
if (project.isUseSecretStorage()) {
try {
dataSourceContainer.persistSecrets(
DBSSecretController.getProjectSecretController(dataSourceContainer.getProject())
);
} catch (DBException e) {
throw new DBWebException("Failed to save credentials", e);
}
}
WebDataSourceUtils.saveCredentialsInDataSource(connectionInfo,
dataSourceContainer,
dataSourceContainer.getConnectionConfiguration());
saveConfig[0] = true;
}
if (WebServiceUtils.isGlobalProject(dataSourceContainer.getProject())) {
// Do not flush config for global project (only admin can do it - CB-2415)
if (saveCredentials) {
connectionInfo.setCredentialsSavedInSession(true);
}
saveConfig[0] = false;
}
if (saveConfig[0]) {
dataSourceContainer.persistConfiguration();
}
return connectionInfo;
}
@Override
public void validateConnection(DBPDataSourceContainer dataSourceContainer) throws DBWebException {
}
private void validateDriverLibrariesPresence(@NotNull DBPDataSourceContainer container) throws DBWebException {
if (!DBWorkbench.isDistributed() && container.getDriver().getDriverLoader(container).needsExternalDependencies()) {
throwDriverNotFoundException(container);
}
}
@NotNull
private static String throwDriverNotFoundException(@NotNull DBPDataSourceContainer container) throws DBWebException {
throw new DBWebException("Driver files for %s are not found. Please ask the administrator to download it."
.formatted(container.getDriver().getName()));
}
}
@@ -130,37 +130,31 @@ public interface DBWServiceCore extends DBWService {
WebConnectionInfo createConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull Map<String, Object> connectionConfig
@NotNull WebConnectionConfig connectionConfig
) throws DBWebException;
@WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT})
WebConnectionInfo updateConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull Map<String, Object> connectionConfig
) throws DBWebException;
@NotNull WebConnectionConfig connectionConfig) throws DBWebException;
@WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT})
boolean deleteConnection(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull String connectionId
) throws DBWebException;
@NotNull String connectionId) throws DBWebException;
@WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT})
WebConnectionInfo copyConnectionFromNode(
@NotNull WebSession webSession,
@Nullable @WebObjectId String projectId,
@NotNull String nodePath,
@NotNull Map<String, Object> connectionConfig
) throws DBWebException;
@NotNull WebConnectionConfig config) throws DBWebException;
@WebAction
WebConnectionInfo testConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull Map<String, Object> connectionConfig
) throws DBWebException;
@NotNull WebSession webSession, @Nullable String projectId, @NotNull WebConnectionConfig connectionConfig) throws DBWebException;
@WebAction
WebNetworkEndpointInfo testNetworkHandler(@NotNull WebSession webSession, @NotNull WebNetworkHandlerConfigInput nhConfig) throws DBWebException;
@@ -17,9 +17,11 @@
package io.cloudbeaver.service.core;
import graphql.TypeResolutionEnvironment;
import graphql.schema.DataFetchingEnvironment;
import graphql.schema.idl.TypeRuntimeWiring;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.model.WebConnectionConfig;
import io.cloudbeaver.model.WebNetworkHandlerConfigInput;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.WebAppSessionManager;
@@ -103,20 +105,16 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
.dataFetcher("changeSessionLanguage", env -> getService(env).changeSessionLanguage(getWebSession(env), env.getArgument("locale")))
.dataFetcher("createConnection", env -> getService(env).createConnection(
getWebSession(env), getProjectReference(env), env.getArgument("config"))
)
getWebSession(env), getProjectReference(env), getConnectionConfig(env)))
.dataFetcher("updateConnection", env -> getService(env).updateConnection(
getWebSession(env), getProjectReference(env), env.getArgument("config"))
)
getWebSession(env), getProjectReference(env), getConnectionConfig(env)))
.dataFetcher("deleteConnection", env -> getService(env).deleteConnection(
getWebSession(env), getProjectReference(env), env.getArgument("id")))
.dataFetcher("copyConnectionFromNode", env -> getService(env).copyConnectionFromNode(
getWebSession(env),
getProjectReference(env),
env.getArgument("nodePath"),
env.getArgument("config")
)
)
new WebConnectionConfig(env.getArgument("config"))))
.dataFetcher("initConnection", env -> {
List<Map<String, Object>> networkCredentials = env.getArgument("networkCredentials");
List<WebNetworkHandlerConfigInput> nhc = null;
@@ -136,7 +134,7 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
}
)
.dataFetcher("testConnection", env -> getService(env).testConnection(
getWebSession(env), getProjectReference(env), env.getArgument("config")
getWebSession(env), getProjectReference(env), getConnectionConfig(env)
))
.dataFetcher("testNetworkHandler", env -> getService(env).testNetworkHandler(
getWebSession(env), new WebNetworkHandlerConfigInput(env.getArgument("config"))
@@ -179,4 +177,8 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
);
}
private WebConnectionConfig getConnectionConfig(DataFetchingEnvironment env) {
return new WebConnectionConfig(env.getArgument("config"));
}
}
@@ -44,29 +44,23 @@ import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.model.exec.DBCConnectException;
import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
import org.jkiss.dbeaver.model.navigator.DBNDataSource;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.navigator.DBNNode;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.DBWHandlerType;
import org.jkiss.dbeaver.model.net.DBWNetworkHandler;
import org.jkiss.dbeaver.model.net.DBWTunnel;
import org.jkiss.dbeaver.model.net.ssh.SSHSession;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.secret.DBSSecretValue;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
import org.jkiss.dbeaver.registry.settings.ProductSettingsRegistry;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.dbeaver.runtime.jobs.ConnectionTestJob;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;
import java.util.*;
@@ -286,7 +280,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);
}
@@ -301,137 +295,65 @@ public class WebServiceCore implements DBWServiceCore {
boolean sharedCredentials,
@Nullable String selectedSecretId
) throws DBWebException {
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
connectionInfo.validateConnection();
connectionInfo.setSavedCredentials(authProperties, networkCredentials);
var dataSourceContainer = connectionInfo.getDataSourceContainer();
if (dataSourceContainer.isConnected()) {
throw new DBWebException("Datasource '" + dataSourceContainer.getName() + "' is already connected");
}
if (dataSourceContainer.isSharedCredentials() && selectedSecretId != null) {
List<DBSSecretValue> allSecrets;
try {
allSecrets = dataSourceContainer.listSharedCredentials();
} catch (DBException e) {
throw new DBWebException("Error loading connection secret", e);
}
DBSSecretValue selectedSecret =
allSecrets.stream()
.filter(secret -> selectedSecretId.equals(secret.getUniqueId()))
.findFirst().orElse(null);
if (selectedSecret == null) {
throw new DBWebException("Secret not found:" + selectedSecretId);
}
dataSourceContainer.setSelectedSharedCredentials(selectedSecret);
}
boolean oldSavePassword = dataSourceContainer.isSavePassword();
DBRProgressMonitor monitor = webSession.getProgressMonitor();
validateDriverLibrariesPresence(dataSourceContainer);
try {
boolean connect = dataSourceContainer.connect(monitor, true, false);
} catch (Exception e) {
if (e instanceof DBCConnectException) {
Throwable rootCause = CommonUtils.getRootCause(e);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(dataSourceContainer);
}
}
throw new DBWebException("Error connecting to database", e);
} finally {
dataSourceContainer.setSavePassword(oldSavePassword);
connectionInfo.clearCache();
}
// Mark all specified network configs as saved
boolean[] saveConfig = new boolean[1];
if (networkCredentials != null) {
networkCredentials.forEach(c -> {
if (CommonUtils.toBoolean(c.isSavePassword())) {
DBWHandlerConfiguration handlerCfg = dataSourceContainer.getConnectionConfiguration()
.getHandler(c.getId());
if (handlerCfg != null &&
// check username param only for ssh config
!(CommonUtils.isEmpty(c.getUserName()) && CommonUtils.equalObjects(
handlerCfg.getType(),
DBWHandlerType.TUNNEL
))
) {
WebDataSourceUtils.updateHandlerCredentials(handlerCfg, c);
handlerCfg.setSavePassword(true);
saveConfig[0] = true;
}
}
});
}
if (saveCredentials) {
// Save all passed credentials in the datasource container
WebDataSourceUtils.saveAuthProperties(
dataSourceContainer,
dataSourceContainer.getConnectionConfiguration(),
authProperties,
true,
sharedCredentials
);
var project = dataSourceContainer.getProject();
if (project.isUseSecretStorage()) {
try {
dataSourceContainer.persistSecrets(
DBSSecretController.getProjectSecretController(dataSourceContainer.getProject())
);
} catch (DBException e) {
throw new DBWebException("Failed to save credentials", e);
}
}
WebDataSourceUtils.saveCredentialsInDataSource(
connectionInfo,
dataSourceContainer,
dataSourceContainer.getConnectionConfiguration()
);
saveConfig[0] = true;
}
if (WebServiceUtils.isGlobalProject(dataSourceContainer.getProject())) {
// Do not flush config for global project (only admin can do it - CB-2415)
if (saveCredentials) {
connectionInfo.setCredentialsSavedInSession(true);
}
saveConfig[0] = false;
}
if (saveConfig[0]) {
dataSourceContainer.persistConfiguration();
}
return connectionInfo;
return WebAppUtils.getWebApplication().getConnectionController().initConnection(webSession, projectId,
connectionId, authProperties, networkCredentials, saveCredentials, sharedCredentials, selectedSecretId);
}
@Override
public WebConnectionInfo createConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull Map<String, Object> connectionConfig
@NotNull WebConnectionConfig connectionConfig
) throws DBWebException {
return getProjectById(webSession, projectId).createConnection(connectionConfig);
DBPDataSourceContainer dataSourceContainer =
WebAppUtils.getWebApplication().getConnectionController().createDataSourceContainer(webSession, projectId, connectionConfig);
return WebAppUtils.getWebApplication().getConnectionController().createConnection(
webSession,
projectId,
dataSourceContainer.getRegistry(),
dataSourceContainer
);
}
@Override
public WebConnectionInfo updateConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull Map<String, Object> connectionConfig
@NotNull WebConnectionConfig config
) throws DBWebException {
return getProjectById(webSession, projectId).updateConnection(connectionConfig);
DBPDataSourceContainer dataSourceContainer =
WebAppUtils.getWebApplication().getConnectionController().getDatasourceConnection(webSession, projectId, config);
return WebAppUtils.getWebApplication().getConnectionController().updateConnection(
webSession,
projectId,
config,
dataSourceContainer,
dataSourceContainer.getRegistry()
);
}
private WSDataSourceProperty getDatasourceEventProperty(
DataSourceDescriptor oldDataSource,
DBPDataSourceContainer dataSource
) {
if (!oldDataSource.equalConfiguration((DataSourceDescriptor) dataSource)) {
return WSDataSourceProperty.CONFIGURATION;
}
var nameChanged = !CommonUtils.equalObjects(oldDataSource.getName(), dataSource.getName());
var descriptionChanged = !CommonUtils.equalObjects(oldDataSource.getDescription(), dataSource.getDescription());
if (nameChanged && descriptionChanged) {
return WSDataSourceProperty.CONFIGURATION;
}
return nameChanged ? WSDataSourceProperty.NAME : WSDataSourceProperty.CONFIGURATION;
}
@Override
public boolean deleteConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId
@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId
) throws DBWebException {
return getProjectById(webSession, projectId).deleteConnection(connectionId);
return WebAppUtils.getWebApplication().getConnectionController().deleteConnection(webSession, projectId, connectionId);
}
@@ -440,7 +362,7 @@ public class WebServiceCore implements DBWServiceCore {
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String nodePath,
@NotNull Map<String, Object> connectionConfig
@NotNull WebConnectionConfig config
) throws DBWebException {
try {
DBNModel navigatorModel = webSession.getNavigatorModelOrThrow();
@@ -451,20 +373,19 @@ public class WebServiceCore implements DBWServiceCore {
if (srcNode == null) {
throw new DBException("Node '" + nodePath + "' not found");
}
if (!(srcNode instanceof DBNDataSource dbnDataSource)) {
if (!(srcNode instanceof DBNDataSource)) {
throw new DBException("Node '" + nodePath + "' is not a datasource node");
}
DBPDataSourceContainer dataSourceTemplate = dbnDataSource.getDataSourceContainer();
DBPDataSourceContainer dataSourceTemplate = ((DBNDataSource) srcNode).getDataSourceContainer();
DataSourceDescriptor newDataSource = dataSourceRegistry.createDataSource(dataSourceTemplate);
DBPDataSourceContainer newDataSource = dataSourceRegistry.createDataSource(dataSourceTemplate);
ServletApplication app = ServletAppUtils.getServletApplication();
if (app instanceof WebApplication webApplication) {
newDataSource.setNavigatorSettings(webApplication.getAppConfiguration().getDefaultNavigatorSettings());
((DataSourceDescriptor) newDataSource).setNavigatorSettings(
webApplication.getAppConfiguration().getDefaultNavigatorSettings());
}
WebConnectionConfig config = project.getConnectionConfigInput(connectionConfig);
// Copy props from config
if (!CommonUtils.isEmpty(config.getName())) {
newDataSource.setName(config.getName());
@@ -486,84 +407,12 @@ public class WebServiceCore implements DBWServiceCore {
public WebConnectionInfo testConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull Map<String, Object> connectionConfig
@NotNull WebConnectionConfig connectionConfig
) throws DBWebException {
WebSessionProjectImpl project = getProjectById(webSession, projectId);
WebConnectionConfig configInput = project.getConnectionConfigInput(connectionConfig);
DataSourceDescriptor dataSource = (DataSourceDescriptor) WebDataSourceUtils.getLocalOrGlobalDataSource(
webSession, projectId, configInput.getConnectionId());
DataSourceDescriptor testDataSource;
if (dataSource != null) {
try {
// Check that creds are saved to trigger secrets resolve
dataSource.isCredentialsSaved();
} catch (DBException e) {
throw new DBWebException("Can't determine whether datasource credentials are saved", e);
}
testDataSource = (DataSourceDescriptor) dataSource.createCopy(dataSource.getRegistry());
WebDataSourceUtils.setConnectionConfiguration(
testDataSource.getDriver(),
testDataSource.getConnectionConfiguration(),
configInput
);
if (configInput.getSelectedSecretId() != null) {
try {
dataSource.listSharedCredentials()
.stream()
.filter(secret -> configInput.getSelectedSecretId().equals(secret.getSubjectId()))
.findFirst()
.ifPresent(testDataSource::setSelectedSharedCredentials);
} catch (DBException e) {
throw new DBWebException("Failed to load secret value: " + configInput.getSelectedSecretId());
}
}
WebDataSourceUtils.saveAuthProperties(
testDataSource,
testDataSource.getConnectionConfiguration(),
configInput.getCredentials(),
true,
false,
true
);
} else {
testDataSource = project.getDataSourceContainerFromInput(connectionConfig);
}
validateDriverLibrariesPresence(testDataSource);
webSession.provideAuthParameters(
webSession.getProgressMonitor(),
testDataSource,
testDataSource.getConnectionConfiguration()
);
testDataSource.setSavePassword(true); // We need for test to avoid password callback
testDataSource.setAccessCheckRequired(!webSession.hasPermission(DBWConstants.PERMISSION_ADMIN));
try {
ConnectionTestJob ct = new ConnectionTestJob(
testDataSource, param -> {
}
);
ct.run(webSession.getProgressMonitor());
if (ct.getConnectError() != null) {
if (ct.getConnectError() instanceof DBCConnectException error) {
Throwable rootCause = CommonUtils.getRootCause(error);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(testDataSource);
}
}
throw new DBWebException("Connection failed", ct.getConnectError());
}
WebConnectionInfo connectionInfo = project.createConnectionInfo(testDataSource);
connectionInfo.setConnectError(ct.getConnectError());
connectionInfo.setServerVersion(ct.getServerVersion());
connectionInfo.setClientVersion(ct.getClientVersion());
connectionInfo.setConnectTime(RuntimeUtils.formatExecutionTime(ct.getConnectTime()));
return connectionInfo;
} catch (DBException e) {
throw new DBWebException("Error connecting to database", e);
}
DataSourceDescriptor dataSourceDescriptor = WebAppUtils.getWebApplication().getConnectionController()
.prepareTestConnection(webSession, projectId, connectionConfig);
return WebAppUtils.getWebApplication().getConnectionController()
.testConnection(webSession, projectId, connectionConfig, dataSourceDescriptor);
}
@Override
@@ -622,15 +471,42 @@ public class WebServiceCore implements DBWServiceCore {
@Override
public WebConnectionInfo closeConnection(
@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId
) throws DBWebException {
return closeAndDeleteConnection(webSession, projectId, connectionId, false);
}
@NotNull
private WebConnectionInfo closeAndDeleteConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId
@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;
}
@@ -735,24 +611,11 @@ public class WebServiceCore implements DBWServiceCore {
return new WebGroupPropertiesInfo<>(webSession, ProductSettingsRegistry.getInstance().getSettings());
}
@NotNull
private WebSessionProjectImpl getProjectById(@NotNull WebSession webSession, @Nullable String projectId) throws DBWebException {
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 void validateDriverLibrariesPresence(@NotNull DBPDataSourceContainer container) throws DBWebException {
if (!DBWorkbench.isDistributed() && container.getDriver().getDriverLoader(container).needsExternalDependencies()) {
throwDriverNotFoundException(container);
}
}
@NotNull
private static String throwDriverNotFoundException(@NotNull DBPDataSourceContainer container) throws DBWebException {
throw new DBWebException("Driver files for %s are not found. Please ask the administrator to download it."
.formatted(container.getDriver().getName()));
}
}
@@ -16,7 +16,6 @@
*/
package io.cloudbeaver.service.navigator;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import java.util.ArrayList;
@@ -35,8 +34,6 @@ public class WebStructContainers {
private List<WebNavigatorNodeInfo> schemaList = new ArrayList<>();
private boolean supportsCatalogChange = false;
private boolean supportsSchemaChange = false;
private String defaultCatalog = null;
private String defaultSchema = null;
public Boolean getSupportsCatalogChange() {
return supportsCatalogChange;
@@ -77,22 +74,4 @@ public class WebStructContainers {
public void setSupportsSchemaChange(boolean support) {
this.supportsSchemaChange = support;
}
@Nullable
public String getDefaultCatalog() {
return defaultCatalog;
}
public void setDefaultCatalog(@Nullable String defaultCatalog) {
this.defaultCatalog = defaultCatalog;
}
@Nullable
public String getDefaultSchema() {
return defaultSchema;
}
public void setDefaultSchema(@Nullable String defaultSchema) {
this.defaultSchema = defaultSchema;
}
}
@@ -323,17 +323,8 @@ public class WebServiceNavigator implements DBWServiceNavigator {
WebStructContainers structContainers = new WebStructContainers();
if (contextDefaults != null) {
structContainers.setSupportsCatalogChange(contextDefaults.supportsCatalogChange());
structContainers.setSupportsSchemaChange(contextDefaults.supportsSchemaChange());
if (contextDefaults.getDefaultSchema() != null) {
structContainers.setDefaultSchema(contextDefaults.getDefaultSchema().getName());
}
if (contextDefaults.getDefaultCatalog() != null) {
structContainers.setDefaultCatalog(contextDefaults.getDefaultCatalog().getName());
}
}
structContainers.setSupportsCatalogChange(contextDefaults != null && contextDefaults.supportsCatalogChange());
structContainers.setSupportsSchemaChange(contextDefaults != null && contextDefaults.supportsSchemaChange());
DBRProgressMonitor monitor = connection.getSession().getProgressMonitor();
List<? extends DBSObject> dbsObjects = this.getCatalogs(
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - Administration
Bundle-SymbolicName: io.cloudbeaver.service.admin;singleton:=true
Bundle-Version: 1.0.130.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.129.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.admin</artifactId>
<version>1.0.130-SNAPSHOT</version>
<version>1.0.129-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -35,7 +35,6 @@ import io.cloudbeaver.service.DBWServiceServerConfigurator;
import io.cloudbeaver.service.admin.*;
import io.cloudbeaver.service.security.SMUtils;
import io.cloudbeaver.utils.ServletAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
@@ -702,7 +701,7 @@ public class WebServiceAdmin implements DBWServiceAdmin {
// driver is removed from disabled list
// we need to enable if it is embedded
try {
DBPDriver driver = WebDataSourceUtils.getDriverById(driverId);
DBPDriver driver = WebServiceUtils.getDriverById(driverId);
if (driver.isEmbedded()) {
enabledIds.add(driverId);
}
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - Authentication
Bundle-SymbolicName: io.cloudbeaver.service.auth;singleton:=true
Bundle-Version: 1.0.130.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.129.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.auth</artifactId>
<version>1.0.130-SNAPSHOT</version>
<version>1.0.129-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -22,7 +22,7 @@ import io.cloudbeaver.auth.SMSignOutLinkProvider;
import io.cloudbeaver.auth.provider.local.LocalAuthProvider;
import io.cloudbeaver.model.WebAsyncTaskInfo;
import io.cloudbeaver.model.WebPropertyInfo;
import io.cloudbeaver.model.app.ServletApplication;
import io.cloudbeaver.model.app.ServletAppConfiguration;
import io.cloudbeaver.model.session.WebAuthInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.model.session.WebSessionAuthProcessor;
@@ -224,12 +224,9 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
throw new DBWebException("Not logged in");
}
try {
List<WebAuthInfo> removedInfos = webSession.removeAuthInfo(providerId, false);
var cbApp = CBApplication.getInstance();
cbApp.getSessionManager().closeSession(webSession.getSessionId(), false);
webSession.resetUserState();
List<WebAuthInfo> removedInfos = webSession.removeAuthInfo(providerId);
List<String> logoutUrls = new ArrayList<>();
var cbApp = CBApplication.getInstance();
String origin = ServletAppUtils.getOriginFromRequest(httpRequest);
for (WebAuthInfo removedInfo : removedInfos) {
if (removedInfo.getAuthProviderDescriptor()
@@ -267,12 +264,8 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
@Override
public WebUserInfo activeUser(@NotNull WebSession webSession) throws DBWebException {
if (webSession.getUser() == null) {
ServletApplication application = webSession.getApplication();
if (application.getAppConfiguration().isAnonymousAccessEnabled() && webSession.isAuthorizedInSecurityManager()) {
SMUser anonymous = new SMUser("anonymous", true, null);
return new WebUserInfo(webSession, new WebUser(anonymous));
}
if (!application.isAnonymousAccessEnabled()) {
ServletAppConfiguration appConfiguration = webSession.getApplication().getAppConfiguration();
if (!appConfiguration.isAnonymousAccessEnabled()) {
return null;
}
SMUser anonymous = new SMUser("anonymous", true, null);
@@ -36,7 +36,7 @@ public class LocalSessionHandler extends AbstractActionSessionHandler {
@Override
public boolean handleSessionAuth(WebSession webSession) throws DBException, IOException {
if (webSession.getUser() == null && !CBApplication.getInstance().isAnonymousAccessEnabled()) {
if (webSession.getUser() == null && !CBApplication.getInstance().getAppConfiguration().isAnonymousAccessEnabled()) {
return false;
}
executeAction(webSession);
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - Data Transfer
Bundle-SymbolicName: io.cloudbeaver.service.data.transfer;singleton:=true
Bundle-Version: 1.0.131.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.130.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.data.transfer</artifactId>
<version>1.0.131-SNAPSHOT</version>
<version>1.0.130-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@ public class WebDataTransferStreamProcessor {
@Property
public String getFileExtension() {
return processor.getProcessorFileExtension();
return WebDataTransferUtils.getProcessorFileExtension(processor);
}
@Property
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2025 DBeaver Corp and others
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package io.cloudbeaver.service.data.transfer.impl;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.tools.transfer.registry.DataTransferProcessorDescriptor;
import org.jkiss.utils.CommonUtils;
@@ -31,7 +32,9 @@ class WebDataTransferUtils {
public static String getProcessorFileExtension(DataTransferProcessorDescriptor processor) {
return processor.getProcessorFileExtension();
DBPPropertyDescriptor extProperty = processor.getProperty("extension");
String ext = extProperty == null ? processor.getAppFileExtension() : CommonUtils.toString(extProperty.getDefaultValue(), null);
return CommonUtils.isEmpty(ext) ? "data" : ext;
}
public static String getProcessorFileExtension(DataTransferProcessorDescriptor processor, Map<String, Object> processorProperties) {
@@ -39,7 +42,7 @@ class WebDataTransferUtils {
return CommonUtils.toString(processorProperties.get(EXTENSION), "data");
}
return processor.getProcessorFileExtension();
return getProcessorFileExtension(processor);
}
public static String normalizeFileName(
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - File System
Bundle-SymbolicName: io.cloudbeaver.service.fs;singleton:=true
Bundle-Version: 1.0.48.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.47.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server.ce,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.fs</artifactId>
<version>1.0.48-SNAPSHOT</version>
<version>1.0.47-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Name: Cloudbeaver Web Service - LDAP
Bundle-Vendor: DBeaver Corp
Bundle-SymbolicName: io.cloudbeaver.service.ldap.auth;singleton:=true
Bundle-Version: 1.0.13.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.12.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.ldap.auth</artifactId>
<version>1.0.13-SNAPSHOT</version>
<version>1.0.12-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - Metadata
Bundle-SymbolicName: io.cloudbeaver.service.metadata;singleton:=true
Bundle-Version: 1.0.134.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.133.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.metadata</artifactId>
<version>1.0.134-SNAPSHOT</version>
<version>1.0.133-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Resource manager NIO implementation
Bundle-SymbolicName: io.cloudbeaver.service.rm.nio;singleton:=true
Bundle-Version: 1.0.48.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.47.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.model,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.rm.nio</artifactId>
<version>1.0.48-SNAPSHOT</version>
<version>1.0.47-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Service - Resource manager
Bundle-SymbolicName: io.cloudbeaver.service.rm;singleton:=true
Bundle-Version: 1.0.83.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.82.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: io.cloudbeaver.server,
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.rm</artifactId>
<version>1.0.83-SNAPSHOT</version>
<version>1.0.82-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -67,8 +67,6 @@ extend type Query {
resourcePath: String!
): String!
"Returns project settings that are specified for a current user"
rmUserProjectSettings(projectId: ID!): Object @since(version: "25.2.1")
}
extend type Mutation {
@@ -111,13 +109,6 @@ extend type Mutation {
description: String
): RMProject!
"Updates project with the specified projectId. If projectName is not specified then does not change it."
rmUpdateProject(
projectId: ID!,
projectName: String,
description: String
): RMProject!
"Deletes project by projectId. Returns true if project was deleted, false if project not found"
rmDeleteProject(projectId: ID!): Boolean!
@@ -132,9 +123,4 @@ extend type Mutation {
"Sets resource property by name. If value is null then removes the property (e.g., sets relation between resource and connection)."
rmSetResourceProperty(projectId: String!, resourcePath: String!, name: ID!, value: String): Boolean!
"Adds project settings (e.g. enables simple view for a project) for a current user"
rmAddUserProjectSettings(projectId: ID!, settings: Object!): Boolean! @since(version: "25.2.1")
"Deletes project settings that are specified for a current user"
rmDeleteUserProjectSettings(projectId: ID!, settingIds: [String!]!): Boolean! @since(version: "25.2.1")
}
@@ -31,7 +31,6 @@ import org.jkiss.dbeaver.model.rm.RMResource;
import org.jkiss.dbeaver.model.security.SMObjectPermissionsGrant;
import java.util.List;
import java.util.Map;
/**
* Web service API
@@ -129,14 +128,6 @@ public interface DBWServiceRM extends DBWService {
@NotNull String name,
@Nullable String description) throws DBWebException;
@WebAction(requirePermissions = {RMConstants.PERMISSION_RM_ADMIN})
RMProject updateProject(
@NotNull WebSession session,
@NotNull String projectId,
@Nullable String name,
@Nullable String description
) throws DBWebException;
@WebAction(requirePermissions = {RMConstants.PERMISSION_RM_ADMIN})
boolean deleteProject(
@NotNull WebSession session,
@@ -192,26 +183,4 @@ public interface DBWServiceRM extends DBWService {
@NotNull WebSession webSession,
@NotNull String subjectId
) throws DBWebException;
@NotNull
@WebProjectAction(requireProjectPermissions = RMConstants.PERMISSION_PROJECT_RESOURCE_VIEW)
Map<String, Object> getProjectSettings(
@NotNull WebSession webSession,
@NotNull @WebObjectId String projectId,
@Nullable String settingId
) throws DBWebException;
@WebProjectAction(requireProjectPermissions = RMConstants.PERMISSION_PROJECT_RESOURCE_VIEW)
boolean addProjectSettings(
@NotNull WebSession webSession,
@NotNull @WebObjectId String projectId,
@NotNull Map<String, Object> settings
) throws DBWebException;
@WebProjectAction(requireProjectPermissions = RMConstants.PERMISSION_PROJECT_RESOURCE_VIEW)
boolean deleteProjectSettings(
@NotNull WebSession webSession,
@NotNull @WebObjectId String projectId,
@Nullable List<String> settings
) throws DBWebException;
}
@@ -64,13 +64,6 @@ public class WebServiceBindingRM extends WebServiceBindingBase<DBWServiceRM> {
getWebSession(env),
env.getArgument("subjectId")
))
.dataFetcher(
"rmUserProjectSettings", env -> getService(env).getProjectSettings(
getWebSession(env),
env.getArgument("projectId"),
env.getArgument("settingId")
)
)
;
model.getMutationType()
.dataFetcher("rmCreateResource",
@@ -98,14 +91,6 @@ public class WebServiceBindingRM extends WebServiceBindingBase<DBWServiceRM> {
env.getArgument("projectName"),
env.getArgument("description")
))
.dataFetcher(
"rmUpdateProject", env -> getService(env).updateProject(
getWebSession(env),
getProjectReference(env),
env.getArgument("projectName"),
env.getArgument("description")
)
)
.dataFetcher("rmDeleteProject", env -> getService(env).deleteProject(
getWebSession(env),
getProjectReference(env)
@@ -139,21 +124,6 @@ public class WebServiceBindingRM extends WebServiceBindingBase<DBWServiceRM> {
env.getArgument("subjectIds"),
env.getArgument("permissions")
))
.dataFetcher(
"rmAddUserProjectSettings", env -> getService(env).addProjectSettings(
getWebSession(env),
env.getArgument("projectId"),
env.getArgument("settings")
)
)
.dataFetcher(
"rmDeleteUserProjectSettings", env -> getService(env).deleteProjectSettings(
getWebSession(env),
env.getArgument("projectId"),
env.getArgument("settingIds")
)
)
;
}
}
@@ -31,7 +31,6 @@ import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMProjectInfo;
import org.jkiss.dbeaver.model.rm.RMResource;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.security.*;
@@ -267,31 +266,6 @@ public class WebServiceRM implements DBWServiceRM {
}
}
@Override
public RMProject updateProject(
@NotNull WebSession session,
@NotNull String projectId,
@Nullable String name,
@Nullable String description
) throws DBWebException {
try {
var project = session.getProjectById(projectId);
if (project == null) {
throw new DBException("Project not found: " + projectId);
}
RMProjectInfo projectInfo = new RMProjectInfo(name, description);
RMProject rmProject = getResourceController(session).updateProject(projectId, projectInfo);
project.updateProject(rmProject.getName(), rmProject.getDescription());
ServletAppUtils.getServletApplication().getEventController().addEvent(
WSProjectUpdateEvent.update(session.getSessionId(), session.getUserId(), rmProject.getId(), projectInfo)
);
return project.getRMProject();
} catch (DBException e) {
throw new DBWebException("Error updating project", e);
}
}
@Override
public boolean deleteProject(@NotNull WebSession session, @NotNull String projectId) throws DBWebException {
try {
@@ -469,72 +443,6 @@ public class WebServiceRM implements DBWServiceRM {
}
}
@NotNull
@Override
public Map<String, Object> getProjectSettings(
@NotNull WebSession webSession,
@NotNull String projectId,
@Nullable String settingId
) throws DBWebException {
try {
var project = webSession.getProjectById(projectId);
if (project == null) {
throw new DBWebException("Project '" + projectId + "' not found");
}
return webSession.getSecurityController().getObjectSettings(
projectId,
SMObjectType.project,
settingId
);
} catch (DBException e) {
throw new DBWebException("Error getting project settings", e);
}
}
@Override
public boolean addProjectSettings(
@NotNull WebSession webSession,
@NotNull String projectId,
@NotNull Map<String, Object> settings
) throws DBWebException {
try {
var project = webSession.getProjectById(projectId);
if (project == null) {
throw new DBWebException("Project '" + projectId + "' not found");
}
webSession.getSecurityController().setObjectSettings(
projectId,
SMObjectType.project,
settings
);
return true;
} catch (DBException e) {
throw new DBWebException("Error adding object settings", e);
}
}
@Override
public boolean deleteProjectSettings(
@NotNull WebSession webSession,
@NotNull String projectId,
@Nullable List<String> settings
) throws DBWebException {
try {
var project = webSession.getProjectById(projectId);
if (project == null) {
throw new DBWebException("Project '" + projectId + "' not found");
}
webSession.getSecurityController().deleteObjectSettings(
projectId,
SMObjectType.project,
settings == null ? null : new HashSet<>(settings)
);
return true;
} catch (DBException e) {
throw new DBWebException("Error deleting object settings", e);
}
}
private RMController getResourceController(WebSession webSession) {
return webSession.getRmController();
}
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Name: Cloudbeaver Web Service - Security
Bundle-Vendor: DBeaver Corp
Bundle-SymbolicName: io.cloudbeaver.service.security;singleton:=true
Bundle-Version: 1.0.86.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.85.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
@@ -240,19 +240,3 @@ CREATE TABLE {table_prefix}CB_AUTH_ATTEMPT_INFO
PRIMARY KEY (AUTH_ID, AUTH_PROVIDER_ID),
FOREIGN KEY (AUTH_ID) REFERENCES {table_prefix}CB_AUTH_ATTEMPT (AUTH_ID) ON DELETE CASCADE
);
CREATE TABLE {table_prefix}CB_OBJECT_SETTINGS
(
OBJECT_ID VARCHAR(128) NOT NULL,
OBJECT_TYPE VARCHAR(128) NOT NULL,
SUBJECT_ID VARCHAR(128) NOT NULL,
SETTING_ID VARCHAR(32) NOT NULL,
SETTING_VALUE VARCHAR(1024),
UPDATE_TIME TIMESTAMP NOT NULL,
UPDATED_BY VARCHAR(128) NOT NULL,
PRIMARY KEY (SUBJECT_ID, OBJECT_TYPE, OBJECT_ID, SETTING_ID),
FOREIGN KEY (SUBJECT_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT(SUBJECT_ID) ON DELETE CASCADE
);
@@ -1,14 +0,0 @@
CREATE TABLE {table_prefix}CB_OBJECT_SETTINGS
(
OBJECT_ID VARCHAR(128) NOT NULL,
OBJECT_TYPE VARCHAR(128) NOT NULL,
SUBJECT_ID VARCHAR(128) NOT NULL,
SETTING_ID VARCHAR(32) NOT NULL,
SETTING_VALUE VARCHAR(1024),
UPDATE_TIME TIMESTAMP NOT NULL,
UPDATED_BY VARCHAR(128) NOT NULL,
PRIMARY KEY (SUBJECT_ID, OBJECT_TYPE, OBJECT_ID, SETTING_ID),
FOREIGN KEY (SUBJECT_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT(SUBJECT_ID) ON DELETE CASCADE
);
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.service.security</artifactId>
<version>1.0.86-SNAPSHOT</version>
<version>1.0.85-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -104,107 +104,6 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
this.smConfig = smConfig;
}
@Override
public void setObjectSettings(
@NotNull String objectId,
@NotNull SMObjectType objectType,
@NotNull Map<String, Object> settings
) throws DBException {
String userId = getUserIdOrThrow();
try (Connection dbCon = database.openConnection()) {
try (JDBCTransaction txn = new JDBCTransaction(dbCon)) {
deleteObjectSettings(objectId, objectType, settings.keySet());
try (
PreparedStatement dbStat = dbCon.prepareStatement(
"INSERT INTO {table_prefix}CB_OBJECT_SETTINGS" +
"(OBJECT_ID,OBJECT_TYPE,SUBJECT_ID,SETTING_ID,SETTING_VALUE,UPDATED_BY,UPDATE_TIME) " +
"VALUES(?,?,?,?,?,?,CURRENT_TIMESTAMP)")
) {
for (Map.Entry<String, Object> entry : settings.entrySet()) {
dbStat.setString(1, objectId);
dbStat.setString(2, objectType.name());
dbStat.setString(3, userId);
dbStat.setString(4, entry.getKey());
dbStat.setString(5, CommonUtils.toString(entry.getValue()));
dbStat.setString(6, userId);
dbStat.addBatch();
}
dbStat.executeBatch();
}
txn.commit();
}
} catch (SQLException e) {
throw new DBCException("Error while adding object settings", e);
}
}
@NotNull
@Override
public Map<String, Object> getObjectSettings(
@NotNull String objectId,
@NotNull SMObjectType objectType,
@Nullable String settingId
) throws DBException {
String userId = getUserIdOrThrow();
try (Connection dbCon = database.openConnection()) {
try (
PreparedStatement dbStat = dbCon.prepareStatement("SELECT SETTING_ID,SETTING_VALUE " +
"FROM {table_prefix}CB_OBJECT_SETTINGS " +
"WHERE OBJECT_ID=? AND OBJECT_TYPE=? AND SUBJECT_ID=?" +
(settingId == null ? "" : " AND SETTING_ID=?"))
) {
int index = 1;
dbStat.setString(index++, objectId);
dbStat.setString(index++, objectType.name());
dbStat.setString(index++, userId);
if (settingId != null) {
dbStat.setString(index++, settingId);
}
try (ResultSet dbResult = dbStat.executeQuery()) {
Map<String, Object> result = new LinkedHashMap<>();
while (dbResult.next()) {
result.put(
dbResult.getString(1),
dbResult.getString(2)
);
}
return result;
}
}
} catch (SQLException e) {
throw new DBCException("Error while getting object settings", e);
}
}
@Override
public void deleteObjectSettings(
@NotNull String objectId,
@NotNull SMObjectType objectType,
@Nullable Set<String> settingIds
) throws DBException {
String userId = getUserIdOrThrow();
String sql = "DELETE FROM {table_prefix}CB_OBJECT_SETTINGS WHERE OBJECT_ID=? AND OBJECT_TYPE=? AND SUBJECT_ID=?";
if (settingIds != null && !settingIds.isEmpty()) {
sql += " AND SETTING_ID IN (" + SQLUtils.generateParamList(settingIds.size()) + ")";
}
try (Connection dbCon = database.openConnection()) {
try (PreparedStatement dbStat = dbCon.prepareStatement(sql)) {
int index = 1;
dbStat.setString(index++, objectId);
dbStat.setString(index++, objectType.name());
dbStat.setString(index++, userId);
if (settingIds != null) {
for (String settingId : settingIds) {
dbStat.setString(index++, settingId);
}
}
dbStat.executeUpdate();
}
} catch (SQLException e) {
throw new DBCException("Error while deleting object settings", e);
}
}
protected boolean isSubjectExists(String subjectId) throws DBCException {
try (Connection dbCon = database.openConnection()) {
try (PreparedStatement dbStat = dbCon.prepareStatement(
@@ -1680,7 +1579,7 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
@Override
public SMAuthInfo authenticateAnonymousUser(@NotNull String appSessionId, @NotNull Map<String, Object> sessionParameters, @NotNull SMSessionType sessionType) throws DBException {
if (!application.isAnonymousAccessEnabled()) {
if (!application.getAppConfiguration().isAnonymousAccessEnabled()) {
throw new SMException("Anonymous access restricted");
}
try (Connection dbCon = database.openConnection()) {
@@ -3157,12 +3056,6 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
objectType.name(),
objectId
);
JDBCUtils.executeStatement(
dbCon,
"DELETE FROM {table_prefix}CB_OBJECT_SETTINGS WHERE OBJECT_TYPE=? AND OBJECT_ID=?",
objectType.name(),
objectId
);
} catch (SQLException e) {
throw new DBCException("Error deleting object permissions", e);
@@ -72,7 +72,7 @@ import javax.sql.DataSource;
public class CBDatabase extends InternalDB<WebDatabaseConfig> {
private static final Log log = Log.getLog(CBDatabase.class);
private static final int CURRENT_SCHEMA_VERSION = 26;
private static final int CURRENT_SCHEMA_VERSION = 25;
private static final String SCHEMA_ID = "CB_CE";
private static final SQLSchemaConfig SCHEMA_CREATE_CONFIG = new SQLSchemaConfig(
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: CloudBeaver SLF4j Binding
Bundle-SymbolicName: io.cloudbeaver.slf4j;singleton:=true
Bundle-Version: 1.0.46.qualifier
Bundle-Release-Date: 20251006
Bundle-Version: 1.0.45.qualifier
Bundle-Release-Date: 20250922
Bundle-RequiredExecutionEnvironment: JavaSE-21
Bundle-ActivationPolicy: lazy
Fragment-Host: slf4j.api
+1 -1
View File
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.slf4j</artifactId>
<version>1.0.46-SNAPSHOT</version>
<version>1.0.45-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
-6
View File
@@ -20,12 +20,6 @@
<artifactId>clickhouse-jdbc</artifactId>
<version>0.8.5</version>
<classifier>http</classifier>
<exclusions>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
@@ -2,7 +2,7 @@
<feature
id="io.cloudbeaver.ce.drivers.feature"
label="Cloudbeaver CE 3rd Party Drivers"
version="1.0.154.qualifier"
version="1.0.153.qualifier"
provider-name="DBeaver Corp">
<plugin id="io.cloudbeaver.resources.drivers.base" download-size="0" install-size="0" version="0.0.0"/>

Some files were not shown because too many files have changed in this diff Show More