mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-16 14:50:15 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8155d328a2 | ||
|
|
6118e706e0 | ||
|
|
eab07b9e9f | ||
|
|
449c31bf44 | ||
|
|
32b4e4ec19 | ||
|
|
101d26158b | ||
|
|
8b5aac0093 | ||
|
|
5fd847f209 | ||
|
|
2936b14aed | ||
|
|
6dfbbecd59 | ||
|
|
44b6f8a3ae | ||
|
|
9f46e49e01 | ||
|
|
552163e6ee | ||
|
|
517db739ae | ||
|
|
8004db0f8b | ||
|
|
66f6ccb245 | ||
|
|
77f531ddac | ||
|
|
192da2c0d6 | ||
|
|
f3c6cf94d7 | ||
|
|
eaa26dfe52 | ||
|
|
b54dd5380d | ||
|
|
f548406446 | ||
|
|
ad37e89ecb | ||
|
|
a6a01c2896 | ||
|
|
cae7699a48 | ||
|
|
d9150180f9 | ||
|
|
95b7f35228 | ||
|
|
1fd1ebeecf | ||
|
|
4daf1efe49 | ||
|
|
affbe444a0 | ||
|
|
e9163b8a2b | ||
|
|
b3f7d85687 | ||
|
|
e033a63f5c | ||
|
|
d4a9c6595e | ||
|
|
7f5fb194c5 | ||
|
|
2d44a492fc | ||
|
|
ebb517318b | ||
|
|
23de1131b9 | ||
|
|
a5911223ef | ||
|
|
37e4c699fe |
@@ -40,6 +40,7 @@ server/test/io.cloudbeaver.test.platform/workspace/.data/
|
||||
.classpath
|
||||
.settings/
|
||||
|
||||
workspace-dev-ce/
|
||||
deploy/cloudbeaver
|
||||
server/**/target
|
||||
apps/**/target
|
||||
Vendored
+12
-12
@@ -7,21 +7,19 @@
|
||||
"name": "Chrome",
|
||||
"url": "http://localhost:8080",
|
||||
"webRoot": "${workspaceFolder}/..",
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/../cloudbeaver/packages/**/dist/**/*.{js,jsx}"
|
||||
],
|
||||
"smartStep": true,
|
||||
"sourceMaps": true,
|
||||
"sourceMapPathOverrides": {
|
||||
"webpack:///*": "${workspaceFolder}/../*"
|
||||
},
|
||||
"skipFiles": [
|
||||
"<node_internals>/**",
|
||||
"**/node_modules/**",
|
||||
"${workspaceFolder}/webapp/**/node_modules/**/*.js",
|
||||
"${workspaceFolder}/webapp/**/dist/**/*.js"
|
||||
]
|
||||
"disableNetworkCache": true,
|
||||
"skipFiles": ["<node_internals>/**", "**/node_modules/**"]
|
||||
},
|
||||
{
|
||||
"type": "java",
|
||||
"name": "CloudBeaver CE",
|
||||
"cwd": "${workspaceFolder}/../opt/cbce",
|
||||
"cwd": "${workspaceFolder}/workspace-dev-ce",
|
||||
"preLaunchTask": "Generate dev proprties for CBCE",
|
||||
"request": "launch",
|
||||
"mainClass": "org.jkiss.dbeaver.launcher.DBeaverLauncher",
|
||||
"windows": {
|
||||
@@ -75,8 +73,10 @@
|
||||
"-arch",
|
||||
"aarch64",
|
||||
"-nl",
|
||||
"en_US",
|
||||
"-showsplash"
|
||||
"en",
|
||||
"-showsplash",
|
||||
"-web-config",
|
||||
"conf/cloudbeaver.conf"
|
||||
],
|
||||
"vmArgs": [
|
||||
"-XX:+IgnoreUnrecognizedVMOptions",
|
||||
|
||||
Vendored
+29
@@ -33,6 +33,35 @@
|
||||
"cwd": "${workspaceFolder}/webapp/packages/product-default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Generate dev proprties for CBCE",
|
||||
"type": "shell",
|
||||
"command": "mvn",
|
||||
"osx": {
|
||||
"args": [
|
||||
"package",
|
||||
"-q",
|
||||
"exec:java",
|
||||
"-Dexec.args=-config ${workspaceFolder}/../idea-workspace-dbeaver/rcp-gen.properties -productFile ${workspaceFolder}/server/product/web-server/CloudbeaverServer.product -projectsFolder ${workspaceFolder}/../ -eclipse ${workspaceFolder}/../eclipse/Eclipse.app/Contents/Eclipse -output ${workspaceFolder}/../eclipse/workspace/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product"
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"args": [
|
||||
"package",
|
||||
"-q",
|
||||
"exec:java",
|
||||
"-Dexec.args=-config ${workspaceFolder}/../idea-workspace-dbeaver/rcp-gen.properties -productFile ${workspaceFolder}/server/product/web-server/CloudbeaverServer.product -projectsFolder ${workspaceFolder}/../ -eclipse ${workspaceFolder}/../eclipse/eclipse -output ${workspaceFolder}/../eclipse/workspace/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product"
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../idea-rcp-launch-config-generator"
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "silent",
|
||||
"close": true,
|
||||
"clear": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build CE",
|
||||
"type": "shell",
|
||||
|
||||
@@ -22,7 +22,12 @@ You can see live demo of CloudBeaver here: https://demo.cloudbeaver.io
|
||||
|
||||
## Changelog
|
||||
|
||||
|
||||
### 24.0.1. 2024-03-25
|
||||
- Added support for two modes for committing changes to the database:
|
||||
- Auto-commit transfers all changes that you make immediately to the database;
|
||||
- Manual commit requires your confirmation before committing a change to the database or rolling it back.
|
||||
- Different bug fixes and enhancements have been made.
|
||||
|
||||
### 24.0.0. 2024-03-04
|
||||
- Changes since 23.3.0:
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
// Product configuration. Customized web application behavior
|
||||
// It is in JSONC format
|
||||
{
|
||||
// Global properties
|
||||
core: {
|
||||
// User defaults
|
||||
user: {
|
||||
defaultTheme: "light",
|
||||
defaultLanguage: "en"
|
||||
},
|
||||
app: {
|
||||
// Log viewer config
|
||||
logViewer: {
|
||||
refreshTimeout: 3000,
|
||||
logBatchSize: 1000,
|
||||
maxLogRecords: 2000,
|
||||
maxFailedRequests: 3
|
||||
}
|
||||
}
|
||||
},
|
||||
// Notifications config
|
||||
core_events: {
|
||||
notificationsPool: 20
|
||||
},
|
||||
plugin_data_spreadsheet_new: {
|
||||
hidden: false
|
||||
},
|
||||
plugin_data_export: {
|
||||
disabled: false
|
||||
},
|
||||
sql.proposals.insert.table.alias: true
|
||||
}
|
||||
@@ -11,7 +11,21 @@
|
||||
rootURI: "/",
|
||||
serviceURI: "/api/",
|
||||
|
||||
productConfiguration: "conf/product.conf",
|
||||
productSettings: {
|
||||
# Global properties
|
||||
core.theming.theme: 'light',
|
||||
core.localization.localization: 'en',
|
||||
plugin.sql-editor.autoSave: true,
|
||||
plugin.sql-editor.disabled: false,
|
||||
# max size of the file that can be uploaded to the editor (in kilobytes)
|
||||
plugin.sql-editor.maxFileSize: 10240,
|
||||
plugin.log-viewer.disabled: false,
|
||||
plugin.log-viewer.logBatchSize: 1000,
|
||||
plugin.log-viewer.maxFailedRequests: 3,
|
||||
plugin.log-viewer.maxLogRecords: 2000,
|
||||
plugin.log-viewer.refreshTimeout: 3000,
|
||||
sql.proposals.insert.table.alias: PLAIN
|
||||
},
|
||||
|
||||
expireSessionAfterPeriod: 1800000,
|
||||
|
||||
@@ -33,7 +47,7 @@
|
||||
},
|
||||
|
||||
database: {
|
||||
driver="h2_embedded_v2",
|
||||
driver: "h2_embedded_v2",
|
||||
url: "jdbc:h2:${workspace}/.data/cb.h2v2.dat",
|
||||
initialDataConfiguration: "conf/initial-data.conf",
|
||||
pool: {
|
||||
@@ -48,9 +62,11 @@
|
||||
app: {
|
||||
anonymousAccessEnabled: true,
|
||||
anonymousUserRole: "user",
|
||||
defaultUserTeam: "user",
|
||||
grantConnectionsAccessToAnonymousTeam: false,
|
||||
supportsCustomConnections: false,
|
||||
showReadOnlyConnectionInfo: false,
|
||||
systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}",
|
||||
|
||||
forwardProxy: false,
|
||||
|
||||
|
||||
@@ -9,7 +9,21 @@
|
||||
rootURI: "/",
|
||||
serviceURI: "/api/",
|
||||
|
||||
productConfiguration: "conf/product.conf",
|
||||
productSettings: {
|
||||
# Global properties
|
||||
core.theming.theme: 'light',
|
||||
core.localization.localization: 'en',
|
||||
plugin.sql-editor.autoSave: true,
|
||||
plugin.sql-editor.disabled: false,
|
||||
# max size of the file that can be uploaded to the editor (in kilobytes)
|
||||
plugin.sql-editor.maxFileSize: 10240,
|
||||
plugin.log-viewer.disabled: false,
|
||||
plugin.log-viewer.logBatchSize: 1000,
|
||||
plugin.log-viewer.maxFailedRequests: 3,
|
||||
plugin.log-viewer.maxLogRecords: 2000,
|
||||
plugin.log-viewer.refreshTimeout: 3000,
|
||||
sql.proposals.insert.table.alias: PLAIN
|
||||
},
|
||||
|
||||
expireSessionAfterPeriod: 1800000,
|
||||
|
||||
@@ -18,7 +32,7 @@
|
||||
enableSecurityManager: false,
|
||||
|
||||
database: {
|
||||
driver="h2_embedded_v2",
|
||||
driver:"h2_embedded_v2",
|
||||
url: "jdbc:h2:${workspace}/.data/cb.h2v2.dat",
|
||||
initialDataConfiguration: "conf/initial-data.conf",
|
||||
pool: {
|
||||
@@ -48,6 +62,7 @@
|
||||
grantConnectionsAccessToAnonymousTeam: false,
|
||||
supportsCustomConnections: false,
|
||||
showReadOnlyConnectionInfo: false,
|
||||
systemVariablesResolvingEnabled: "${CLOUDBEAVER_SYSTEM_VARIABLES_RESOLVING_ENABLED:false}",
|
||||
|
||||
forwardProxy: false,
|
||||
|
||||
|
||||
@@ -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.49.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.50.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.model</artifactId>
|
||||
<version>1.0.49-SNAPSHOT</version>
|
||||
<version>1.0.50-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -18,6 +18,7 @@ package io.cloudbeaver.model;
|
||||
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.*;
|
||||
import org.jkiss.dbeaver.model.connection.DBPDriverConfigurationType;
|
||||
@@ -27,6 +28,7 @@ import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.model.meta.PropertyLength;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
|
||||
import org.jkiss.dbeaver.runtime.properties.ObjectPropertyDescriptor;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
@@ -242,4 +244,12 @@ public class WebPropertyInfo {
|
||||
return CommonUtils.toString(value);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Property
|
||||
public List<String> getScopes() {
|
||||
if (property instanceof ProductSettingDescriptor productSettingDescriptor) {
|
||||
return productSettingDescriptor.getScopes();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.model.app;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* Abstract class that contains methods for loading configuration with gson.
|
||||
*/
|
||||
public abstract class BaseServerConfigurationController<T extends WebServerConfiguration> implements WebServerConfigurationController<T> {
|
||||
|
||||
protected Gson getGson() {
|
||||
return getGsonBuilder().create();
|
||||
}
|
||||
|
||||
protected abstract GsonBuilder getGsonBuilder();
|
||||
|
||||
public abstract T getServerConfiguration();
|
||||
}
|
||||
+1
-2
@@ -29,14 +29,13 @@ public abstract class BaseWebAppConfiguration implements WebAppConfiguration {
|
||||
public static final String DEFAULT_APP_ANONYMOUS_TEAM_NAME = "user";
|
||||
|
||||
protected final Map<String, Object> plugins;
|
||||
protected String defaultUserTeam;
|
||||
protected String defaultUserTeam = DEFAULT_APP_ANONYMOUS_TEAM_NAME;
|
||||
protected boolean resourceManagerEnabled;
|
||||
protected boolean showReadOnlyConnectionInfo;
|
||||
protected String[] enabledFeatures;
|
||||
|
||||
public BaseWebAppConfiguration() {
|
||||
this.plugins = new LinkedHashMap<>();
|
||||
this.defaultUserTeam = DEFAULT_APP_ANONYMOUS_TEAM_NAME;
|
||||
this.resourceManagerEnabled = true;
|
||||
this.enabledFeatures = null;
|
||||
this.showReadOnlyConnectionInfo = false;
|
||||
|
||||
+7
-16
@@ -16,8 +16,6 @@
|
||||
*/
|
||||
package io.cloudbeaver.model.app;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.cloudbeaver.DataSourceFilter;
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.WebSessionProjectImpl;
|
||||
@@ -102,8 +100,7 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Path loadServerConfiguration() throws DBException {
|
||||
protected boolean loadServerConfiguration() throws DBException {
|
||||
Path configFilePath = getMainConfigurationFilePath().toAbsolutePath();
|
||||
Path configFolder = configFilePath.getParent();
|
||||
|
||||
@@ -120,13 +117,13 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
|
||||
// Load config file
|
||||
log.debug("Loading configuration from " + configFilePath);
|
||||
try {
|
||||
loadConfiguration(configFilePath);
|
||||
getServerConfigurationController().loadServerConfiguration(configFilePath);
|
||||
} catch (Exception e) {
|
||||
log.error("Error parsing configuration", e);
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return configFilePath;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -153,7 +150,7 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
|
||||
return getLogbackConfigPath(configFolder);
|
||||
}
|
||||
|
||||
private Path getMainConfigurationFilePath() {
|
||||
protected Path getMainConfigurationFilePath() {
|
||||
String configPath = DEFAULT_CONFIG_FILE_PATH;
|
||||
|
||||
String[] args = Platform.getCommandLineArgs();
|
||||
@@ -179,8 +176,6 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
|
||||
return Files.exists(customConfigPath) ? customConfigPath : configPath.resolve(fileName);
|
||||
}
|
||||
|
||||
protected abstract void loadConfiguration(Path configPath) throws DBException;
|
||||
|
||||
@Override
|
||||
public WebProjectImpl createProjectImpl(
|
||||
@NotNull WebSession webSession,
|
||||
@@ -207,7 +202,7 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
|
||||
return VoidSecretController.INSTANCE;
|
||||
}
|
||||
|
||||
protected static Map<String, Object> getServerConfigProps(Map<String, Object> configProps) {
|
||||
public static Map<String, Object> getServerConfigProps(Map<String, Object> configProps) {
|
||||
return JSONUtils.getObject(configProps, "server");
|
||||
}
|
||||
|
||||
@@ -270,11 +265,7 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Gson getGson() {
|
||||
return getGsonBuilder().create();
|
||||
}
|
||||
|
||||
protected abstract GsonBuilder getGsonBuilder();
|
||||
public abstract WebServerConfigurationController getServerConfigurationController();
|
||||
|
||||
@Override
|
||||
public boolean isEnvironmentVariablesAccessible() {
|
||||
|
||||
@@ -43,6 +43,8 @@ public interface WebApplication extends DBPApplication {
|
||||
|
||||
WebAppConfiguration getAppConfiguration();
|
||||
|
||||
WebServerConfiguration getServerConfiguration();
|
||||
|
||||
Path getDataDirectory(boolean create);
|
||||
|
||||
Path getWorkspaceDirectory();
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.model.app;
|
||||
|
||||
/**
|
||||
* Web server configuration.
|
||||
* Contains only server configuration properties.
|
||||
*/
|
||||
public interface WebServerConfiguration {
|
||||
boolean isDevelMode();
|
||||
|
||||
default String getRootURI() {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.model.app;
|
||||
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Server configuration controller.
|
||||
* Works with app server configuration (loads, updates)
|
||||
*/
|
||||
public interface WebServerConfigurationController<T extends WebServerConfiguration> {
|
||||
|
||||
/**
|
||||
* Loads server configuration.
|
||||
*/
|
||||
void loadServerConfiguration(Path configPath) throws DBException;
|
||||
|
||||
}
|
||||
+46
-26
@@ -34,8 +34,6 @@ import io.cloudbeaver.utils.CBModelConstants;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
import io.cloudbeaver.utils.WebDataSourceUtils;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
@@ -125,13 +123,13 @@ public class WebSession extends BaseWebSession
|
||||
private final Map<String, DBWSessionHandler> sessionHandlers;
|
||||
|
||||
public WebSession(
|
||||
@NotNull HttpSession httpSession,
|
||||
@NotNull HttpServletRequest request,
|
||||
@NotNull WebAuthApplication application,
|
||||
@NotNull Map<String, DBWSessionHandler> sessionHandlers
|
||||
) throws DBException {
|
||||
super(httpSession.getId(), application);
|
||||
super(request.getSession().getId(), application);
|
||||
this.lastAccessTime = this.createTime;
|
||||
setLocale(CommonUtils.toString(httpSession.getAttribute(ATTR_LOCALE), this.locale));
|
||||
setLocale(CommonUtils.toString(request.getSession().getAttribute(ATTR_LOCALE), this.locale));
|
||||
this.sessionHandlers = sessionHandlers;
|
||||
//force authorization of anonymous session to avoid access error,
|
||||
//because before authorization could be called by any request,
|
||||
@@ -139,6 +137,7 @@ public class WebSession extends BaseWebSession
|
||||
//and the order of requests is not guaranteed.
|
||||
//look at CB-4747
|
||||
refreshSessionAuth();
|
||||
updateSessionParameters(request);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -283,7 +282,7 @@ public class WebSession extends BaseWebSession
|
||||
switch (type) {
|
||||
case DATASOURCE_CREATED -> {
|
||||
WebConnectionInfo connectionInfo = new WebConnectionInfo(this, ds);
|
||||
this.connections.put(connectionInfo.getId(), connectionInfo);
|
||||
this.connections.put(getConnectionId(ds), connectionInfo);
|
||||
sendDataSourceUpdatedEvent = true;
|
||||
}
|
||||
case DATASOURCE_UPDATED -> // if settings were changed we need to send event
|
||||
@@ -293,7 +292,7 @@ public class WebSession extends BaseWebSession
|
||||
if (registry instanceof DBPDataSourceRegistryCache dsrc) {
|
||||
dsrc.removeDataSourceFromList(ds);
|
||||
}
|
||||
this.connections.remove(ds.getId());
|
||||
this.connections.remove(getConnectionId(ds));
|
||||
sendDataSourceUpdatedEvent = true;
|
||||
}
|
||||
default -> {
|
||||
@@ -303,6 +302,16 @@ public class WebSession extends BaseWebSession
|
||||
return sendDataSourceUpdatedEvent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getConnectionId(@NotNull DBPDataSourceContainer container) {
|
||||
return getConnectionId(container.getProject().getId(), container.getId());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getConnectionId(@NotNull String projectId, @NotNull String dsId) {
|
||||
return projectId + ":" + dsId;
|
||||
}
|
||||
|
||||
// Note: for admin use only
|
||||
public synchronized void resetUserState() throws DBException {
|
||||
clearAuthTokens();
|
||||
@@ -473,7 +482,7 @@ public class WebSession extends BaseWebSession
|
||||
var registry = getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry();
|
||||
var dataSource = registry.getDataSource(dsId);
|
||||
if (dataSource != null) {
|
||||
connections.put(dsId, new WebConnectionInfo(this, dataSource));
|
||||
connections.put(getConnectionId(dataSource), new WebConnectionInfo(this, dataSource));
|
||||
// reflect changes is navigator model
|
||||
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_ADD, dataSource, true));
|
||||
}
|
||||
@@ -484,7 +493,7 @@ public class WebSession extends BaseWebSession
|
||||
var dataSource = registry.getDataSource(dsId);
|
||||
if (dataSource != null) {
|
||||
this.accessibleConnectionIds.remove(dsId);
|
||||
connections.remove(dsId);
|
||||
connections.remove(getConnectionId(dataSource));
|
||||
// reflect changes is navigator model
|
||||
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_REMOVE, dataSource));
|
||||
dataSource.dispose();
|
||||
@@ -525,17 +534,10 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void updateInfo(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response
|
||||
) throws DBWebException {
|
||||
public synchronized void updateInfo(boolean isOldHttpSessionUsed) {
|
||||
log.debug("Update session lifetime " + getSessionId() + " for user " + getUserId());
|
||||
touchSession();
|
||||
HttpSession httpSession = request.getSession();
|
||||
this.lastRemoteAddr = request.getRemoteAddr();
|
||||
this.lastRemoteUserAgent = request.getHeader("User-Agent");
|
||||
this.cacheExpired = false;
|
||||
if (!httpSession.isNew()) {
|
||||
if (isOldHttpSessionUsed) {
|
||||
try {
|
||||
// Persist session
|
||||
if (!isAuthorizedInSecurityManager()) {
|
||||
@@ -555,6 +557,12 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void updateSessionParameters(HttpServletRequest request) {
|
||||
this.lastRemoteAddr = request.getRemoteAddr();
|
||||
this.lastRemoteUserAgent = request.getHeader("User-Agent");
|
||||
this.cacheExpired = false;
|
||||
}
|
||||
|
||||
@Association
|
||||
public List<WebConnectionInfo> getConnections() {
|
||||
synchronized (connections) {
|
||||
@@ -564,9 +572,21 @@ public class WebSession extends BaseWebSession
|
||||
|
||||
@NotNull
|
||||
public WebConnectionInfo getWebConnectionInfo(@Nullable String projectId, String connectionID) throws DBWebException {
|
||||
WebConnectionInfo connectionInfo;
|
||||
WebConnectionInfo connectionInfo = null;
|
||||
synchronized (connections) {
|
||||
connectionInfo = connections.get(connectionID);
|
||||
if (projectId != null) {
|
||||
connectionInfo = connections.get(getConnectionId(projectId, connectionID));
|
||||
} else {
|
||||
addWarningMessage("Project id is not defined in request. Try to find it from connection cache");
|
||||
for (Map.Entry<String, WebConnectionInfo> entry : connections.entrySet()) {
|
||||
String k = entry.getKey();
|
||||
WebConnectionInfo v = entry.getValue();
|
||||
if (k.contains(connectionID)) {
|
||||
connectionInfo = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (connectionInfo == null) {
|
||||
WebProjectImpl project = getProjectById(projectId);
|
||||
@@ -577,7 +597,7 @@ public class WebSession extends BaseWebSession
|
||||
if (dataSource != null) {
|
||||
connectionInfo = new WebConnectionInfo(this, dataSource);
|
||||
synchronized (connections) {
|
||||
connections.put(connectionID, connectionInfo);
|
||||
connections.put(getConnectionId(dataSource), connectionInfo);
|
||||
}
|
||||
} else {
|
||||
throw new DBWebException("Connection '" + connectionID + "' not found");
|
||||
@@ -587,22 +607,22 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WebConnectionInfo findWebConnectionInfo(String connectionID) {
|
||||
public WebConnectionInfo findWebConnectionInfo(String projectId, String connectionId) {
|
||||
synchronized (connections) {
|
||||
return connections.get(connectionID);
|
||||
return connections.get(getConnectionId(projectId, connectionId));
|
||||
}
|
||||
}
|
||||
|
||||
public void addConnection(WebConnectionInfo connectionInfo) {
|
||||
synchronized (connections) {
|
||||
connections.put(connectionInfo.getId(), connectionInfo);
|
||||
connections.put(getConnectionId(connectionInfo.getDataSourceContainer()), connectionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeConnection(WebConnectionInfo connectionInfo) {
|
||||
connectionInfo.clearCache();
|
||||
synchronized (connections) {
|
||||
connections.remove(connectionInfo.getId());
|
||||
connections.remove(getConnectionId(connectionInfo.getDataSourceContainer()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -929,7 +949,7 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
configuration.setRuntimeAttribute(RUNTIME_PARAM_AUTH_INFOS, getAllAuthInfo());
|
||||
|
||||
WebConnectionInfo webConnectionInfo = findWebConnectionInfo(dataSourceContainer.getId());
|
||||
WebConnectionInfo webConnectionInfo = findWebConnectionInfo(dataSourceContainer.getProject().getId(), dataSourceContainer.getId());
|
||||
if (webConnectionInfo != null) {
|
||||
WebDataSourceUtils.saveCredentialsInDataSource(webConnectionInfo, dataSourceContainer, configuration);
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ public class WebAppUtils {
|
||||
sessionCookie.setMaxAge((int) (maxSessionIdleTime / 1000));
|
||||
}
|
||||
|
||||
String path = getWebApplication().getRootURI();
|
||||
String path = getWebApplication().getServerConfiguration().getRootURI();
|
||||
|
||||
if (sameSite != null) {
|
||||
if (!request.isSecure()) {
|
||||
|
||||
@@ -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: 24.0.1.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 24.0.2.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.product.ce</artifactId>
|
||||
<version>24.0.1-SNAPSHOT</version>
|
||||
<version>24.0.2-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Base JDBC drivers
|
||||
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
|
||||
Bundle-Version: 1.0.94.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.95.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<resource name="drivers/sqlite/xerial"/>
|
||||
<resource name="drivers/mssql/new"/>
|
||||
<resource name="drivers/trino"/>
|
||||
<resource name="drivers/kyuubi"/>
|
||||
</extension>
|
||||
|
||||
<!-- Bundles -->
|
||||
@@ -36,6 +37,7 @@
|
||||
<bundle id="drivers.sqlite.xerial" label="SQLite drivers"/>
|
||||
<bundle id="drivers.mssql.new" label="SQL Server drivers"/>
|
||||
<bundle id="drivers.trino" label="Trino drivers"/>
|
||||
<bundle id="drivers.kyuubi" label="Apache Kyuubi drivers"/>
|
||||
</extension>
|
||||
|
||||
<!-- Enabled drivers -->
|
||||
@@ -55,6 +57,7 @@
|
||||
<driver id="sqlserver:microsoft"/>
|
||||
<driver id="generic:trino_jdbc"/>
|
||||
<driver id="generic:duckdb_jdbc"/>
|
||||
<driver id="generic:kyuubi_hive"/>
|
||||
</extension>
|
||||
|
||||
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.resources.drivers.base</artifactId>
|
||||
<version>1.0.94-SNAPSHOT</version>
|
||||
<version>1.0.95-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
|
||||
@@ -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: 24.0.1.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 24.0.2.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.server</artifactId>
|
||||
<version>24.0.1-SNAPSHOT</version>
|
||||
<version>24.0.2-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -38,6 +38,8 @@ type ObjectPropertyInfo {
|
||||
supportedConfigurationTypes: [ String! ]
|
||||
# Required parameters
|
||||
required: Boolean! @since(version: "23.3.1")
|
||||
# Parameter scopes
|
||||
scopes:[String!]
|
||||
}
|
||||
|
||||
enum ObjectPropertyLength {
|
||||
@@ -162,6 +164,16 @@ type ServerConfig {
|
||||
passwordPolicyConfiguration: PasswordPolicyConfig! @since(version: "23.3.3")
|
||||
}
|
||||
|
||||
type ProductSettingsGroup @since(version: "24.0.1") {
|
||||
id: ID!
|
||||
displayName: String!
|
||||
}
|
||||
|
||||
type ProductSettings @since(version: "24.0.1") {
|
||||
groups: [ProductSettingsGroup!]!
|
||||
settings: [ObjectPropertyInfo!]! # each property is associated with a group by category
|
||||
}
|
||||
|
||||
type SessionInfo {
|
||||
createTime: String!
|
||||
lastAccessTime: String!
|
||||
@@ -530,6 +542,8 @@ extend type Query {
|
||||
# Returns server config
|
||||
serverConfig: ServerConfig!
|
||||
|
||||
productSettings: ProductSettings! @since(version: "24.0.1")
|
||||
|
||||
# Returns session state ( initialize if not )
|
||||
sessionState: SessionInfo!
|
||||
|
||||
@@ -566,9 +580,9 @@ extend type Mutation {
|
||||
closeSession: Boolean
|
||||
|
||||
# Refreshes session on server and returns its state
|
||||
touchSession: Boolean @deprecated(reason: "use updateSession instead")
|
||||
touchSession: Boolean @deprecated(reason: "use events to update session")
|
||||
# Refreshes session on server and returns session state
|
||||
updateSession: SessionInfo! @since(version: "24.0.0")
|
||||
updateSession: SessionInfo! @since(version: "24.0.0") @deprecated(reason: "use events to update session")
|
||||
|
||||
# Refresh session connection list
|
||||
refreshSessionConnections: Boolean
|
||||
|
||||
@@ -37,7 +37,8 @@ enum CBServerEventId {
|
||||
enum CBClientEventId {
|
||||
cb_client_topic_subscribe,
|
||||
cb_client_topic_unsubscribe,
|
||||
cb_client_projects_active
|
||||
cb_client_projects_active,
|
||||
cb_client_session_ping
|
||||
}
|
||||
|
||||
# Client subscribes on topic to receive only related events
|
||||
@@ -114,8 +115,12 @@ type WSSocketConnectedEvent implements CBServerEvent {
|
||||
type WSSessionStateEvent implements CBServerEvent {
|
||||
id: CBServerEventId!
|
||||
topicId: CBEventTopic
|
||||
lastAccessTime: Int!
|
||||
remainingTime: Int!
|
||||
isValid: Boolean
|
||||
isCacheExpired: Boolean
|
||||
locale: String!
|
||||
actionParameters: Object
|
||||
}
|
||||
|
||||
# Session expired event
|
||||
|
||||
+1
@@ -182,6 +182,7 @@ public class WebDatabaseDriverInfo {
|
||||
cfg.setUrl(driver.getSampleURL());
|
||||
cfg.setHostName(DBConstants.HOST_LOCALHOST);
|
||||
cfg.setHostPort(driver.getDefaultPort());
|
||||
cfg.setDatabaseName(driver.getDefaultDatabase());
|
||||
cfg.setUrl(driver.getConnectionURL(cfg));
|
||||
DBPPropertyDescriptor[] properties = driver.getDataSourceProvider().getConnectionProperties(webSession.getProgressMonitor(), driver, cfg);
|
||||
if (properties == null) {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.model;
|
||||
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.impl.PropertyGroupDescriptor;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class WebProductSettings {
|
||||
@NotNull
|
||||
private final WebSession webSession;
|
||||
@NotNull
|
||||
private final List<PropertyGroupDescriptor<ProductSettingDescriptor>> groups;
|
||||
|
||||
public WebProductSettings(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull List<PropertyGroupDescriptor<ProductSettingDescriptor>> groups
|
||||
) {
|
||||
this.webSession = webSession;
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Property
|
||||
public List<WebSettingsGroupInfo> getGroups() {
|
||||
return groups.stream()
|
||||
.map(WebSettingsGroupInfo::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Property
|
||||
public List<WebPropertyInfo> getSettings() {
|
||||
return groups.stream()
|
||||
.flatMap(group -> group.getSettings().stream())
|
||||
.map(setting -> new WebPropertyInfo(webSession, setting))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class WebServerConfig {
|
||||
|
||||
@Property
|
||||
public String getName() {
|
||||
return CommonUtils.notEmpty(application.getServerName());
|
||||
return CommonUtils.notEmpty(application.getServerConfiguration().getServerName());
|
||||
}
|
||||
|
||||
@Property
|
||||
@@ -61,12 +61,12 @@ public class WebServerConfig {
|
||||
|
||||
@Property
|
||||
public String getServerURL() {
|
||||
return CommonUtils.notEmpty(application.getServerURL());
|
||||
return CommonUtils.notEmpty(application.getServerConfiguration().getServerURL());
|
||||
}
|
||||
|
||||
@Property
|
||||
public String getRootURI() {
|
||||
return CommonUtils.notEmpty(application.getRootURI());
|
||||
return CommonUtils.notEmpty(application.getServerConfiguration().getRootURI());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -127,7 +127,7 @@ public class WebServerConfig {
|
||||
|
||||
@Property
|
||||
public boolean isDevelopmentMode() {
|
||||
return application.isDevelMode();
|
||||
return application.getServerConfiguration().isDevelMode();
|
||||
}
|
||||
|
||||
@Property
|
||||
@@ -142,7 +142,7 @@ public class WebServerConfig {
|
||||
|
||||
@Property
|
||||
public long getSessionExpireTime() {
|
||||
return application.getConfiguredMaxSessionIdleTime();
|
||||
return application.getServerConfiguration().getMaxSessionIdleTime();
|
||||
}
|
||||
|
||||
@Property
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.model;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.impl.PropertyGroupDescriptor;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
import org.jkiss.dbeaver.registry.settings.ProductSettingDescriptor;
|
||||
|
||||
public class WebSettingsGroupInfo {
|
||||
@NotNull
|
||||
private final PropertyGroupDescriptor<ProductSettingDescriptor> groupDescriptor;
|
||||
|
||||
public WebSettingsGroupInfo(@NotNull PropertyGroupDescriptor<ProductSettingDescriptor> groupDescriptor) {
|
||||
this.groupDescriptor = groupDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Property
|
||||
public String getId() {
|
||||
return groupDescriptor.getFullId();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Property
|
||||
public String getDisplayName() {
|
||||
return groupDescriptor.getDisplayName();
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
private boolean redirectOnFederatedAuth;
|
||||
private boolean anonymousAccessEnabled;
|
||||
private boolean grantConnectionsAccessToAnonymousTeam;
|
||||
private boolean systemVariablesResolvingEnabled;
|
||||
@Deprecated
|
||||
private String anonymousUserRole;
|
||||
private String anonymousUserTeam;
|
||||
@@ -85,6 +86,7 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
this.forwardProxy = false;
|
||||
this.linkExternalCredentialsWithUser = true;
|
||||
this.grantConnectionsAccessToAnonymousTeam = false;
|
||||
this.systemVariablesResolvingEnabled = false;
|
||||
}
|
||||
|
||||
public CBAppConfig(CBAppConfig src) {
|
||||
@@ -106,6 +108,7 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
this.forwardProxy = src.forwardProxy;
|
||||
this.linkExternalCredentialsWithUser = src.linkExternalCredentialsWithUser;
|
||||
this.grantConnectionsAccessToAnonymousTeam = src.grantConnectionsAccessToAnonymousTeam;
|
||||
this.systemVariablesResolvingEnabled = src.systemVariablesResolvingEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -296,4 +299,8 @@ public class CBAppConfig extends BaseAuthWebAppConfiguration implements WebAuthC
|
||||
public boolean isDriverForceEnabled(@NotNull String driverId) {
|
||||
return ArrayUtils.containsIgnoreCase(getEnabledDrivers(), driverId);
|
||||
}
|
||||
|
||||
public boolean isSystemVariablesResolvingEnabled() {
|
||||
return systemVariablesResolvingEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
+70
-670
File diff suppressed because it is too large
Load Diff
+21
-7
@@ -36,37 +36,45 @@ import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CBApplicationCE extends CBApplication {
|
||||
public class CBApplicationCE extends CBApplication<CBServerConfig> {
|
||||
private static final Log log = Log.getLog(CBApplicationCE.class);
|
||||
|
||||
private final CBServerConfigurationControllerEmbedded<CBServerConfig> serverConfigController;
|
||||
|
||||
public CBApplicationCE() {
|
||||
serverConfigController = new CBServerConfigurationControllerEmbedded<>(new CBServerConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SMController createSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException {
|
||||
return new EmbeddedSecurityControllerFactory().createSecurityService(
|
||||
this,
|
||||
databaseConfiguration,
|
||||
getServerConfiguration().getDatabaseConfiguration(),
|
||||
credentialsProvider,
|
||||
securityManagerConfiguration
|
||||
getServerConfigurationController().getSecurityManagerConfiguration()
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public SMAdminController getAdminSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException {
|
||||
return new EmbeddedSecurityControllerFactory().createSecurityService(
|
||||
this,
|
||||
databaseConfiguration,
|
||||
getServerConfiguration().getDatabaseConfiguration(),
|
||||
credentialsProvider,
|
||||
securityManagerConfiguration
|
||||
getServerConfigurationController().getSecurityManagerConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
protected SMAdminController createGlobalSecurityController() throws DBException {
|
||||
return new EmbeddedSecurityControllerFactory().createSecurityService(
|
||||
this,
|
||||
databaseConfiguration,
|
||||
getServerConfiguration().getDatabaseConfiguration(),
|
||||
new NoAuthCredentialsProvider(),
|
||||
securityManagerConfiguration
|
||||
getServerConfigurationController().getSecurityManagerConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public RMController createResourceController(@NotNull SMCredentialsProvider credentialsProvider,
|
||||
@NotNull DBPWorkspace workspace) throws DBException {
|
||||
@@ -79,6 +87,11 @@ public class CBApplicationCE extends CBApplication {
|
||||
return new LocalFileController(DBWorkbench.getPlatform().getWorkspace().getAbsolutePath().resolve(DBFileController.DATA_FOLDER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CBServerConfigurationControllerEmbedded<CBServerConfig> getServerConfigurationController() {
|
||||
return serverConfigController;
|
||||
}
|
||||
|
||||
protected void shutdown() {
|
||||
try {
|
||||
if (securityController instanceof CBEmbeddedSecurityController) {
|
||||
@@ -99,4 +112,5 @@ public class CBApplicationCE extends CBApplication {
|
||||
((CBEmbeddedSecurityController) securityController).finishConfiguration(adminName, adminPassword, authInfoList);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ public class CBConstants {
|
||||
public static final String RUNTIME_PRODUCT_CONFIG_FILE_NAME = ".product.runtime.conf";
|
||||
public static final String AUTO_CONFIG_FILE_NAME = ".cloudbeaver.auto.conf";
|
||||
|
||||
public static final String PARAM_SERVER_CONFIGURATION = "server";
|
||||
public static final String PARAM_SERVER_PORT = "serverPort";
|
||||
public static final String PARAM_SERVER_HOST = "serverHost";
|
||||
public static final String PARAM_SERVER_NAME = "serverName";
|
||||
@@ -35,7 +36,10 @@ public class CBConstants {
|
||||
public static final String PARAM_SERVICES_URI = "serviceURI";
|
||||
public static final String PARAM_DRIVERS_LOCATION = "driversLocation";
|
||||
public static final String PARAM_WORKSPACE_LOCATION = "workspaceLocation";
|
||||
//legacy path to a product.conf file
|
||||
@Deprecated
|
||||
public static final String PARAM_PRODUCT_CONFIGURATION = "productConfiguration";
|
||||
public static final String PARAM_PRODUCT_SETTINGS = "productSettings";
|
||||
public static final String PARAM_EXTERNAL_PROPERTIES = "externalProperties";
|
||||
public static final String PARAM_STATIC_CONTENT = "staticContent";
|
||||
public static final String PARAM_RESOURCE_QUOTAS = "resourceQuotas";
|
||||
|
||||
@@ -68,12 +68,13 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
public static final String PLUGIN_ID = "io.cloudbeaver.server"; //$NON-NLS-1$
|
||||
|
||||
private static final Log log = Log.getLog(CBPlatform.class);
|
||||
private static final String TEMP_FILE_FOLDER = "temp-sql-upload-files";
|
||||
public static final String TEMP_FILE_FOLDER = "temp-sql-upload-files";
|
||||
public static final String TEMP_FILE_IMPORT_FOLDER = "temp-import-files";
|
||||
|
||||
public static final String WORK_DATA_FOLDER_NAME = ".work-data";
|
||||
|
||||
@Nullable
|
||||
private static CBApplication application = null;
|
||||
private static CBApplication<?> application = null;
|
||||
|
||||
private Path tempFolder;
|
||||
|
||||
@@ -133,6 +134,7 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
protected IStatus run(DBRProgressMonitor monitor) {
|
||||
try {
|
||||
IOUtils.deleteDirectory(getTempFolder(monitor, TEMP_FILE_FOLDER));
|
||||
IOUtils.deleteDirectory(getTempFolder(monitor, TEMP_FILE_IMPORT_FOLDER));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -189,7 +191,7 @@ public class CBPlatform extends BasePlatformImpl {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CBApplication getApplication() {
|
||||
public CBApplication<?> getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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.server;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import io.cloudbeaver.auth.CBAuthConstants;
|
||||
import io.cloudbeaver.model.app.WebServerConfiguration;
|
||||
import io.cloudbeaver.service.security.db.WebDatabaseConfig;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CBServerConfig implements WebServerConfiguration {
|
||||
|
||||
private static final Log log = Log.getLog(CBServerConfig.class);
|
||||
|
||||
protected String serverURL;
|
||||
protected int serverPort = CBConstants.DEFAULT_SERVER_PORT;
|
||||
private String serverHost = null;
|
||||
private String serverName = null;
|
||||
private String sslConfigurationPath = null;
|
||||
private String contentRoot = CBConstants.DEFAULT_CONTENT_ROOT;
|
||||
private String rootURI = CBConstants.DEFAULT_ROOT_URI;
|
||||
private String serviceURI = CBConstants.DEFAULT_SERVICES_URI;
|
||||
|
||||
private String workspaceLocation = CBConstants.DEFAULT_WORKSPACE_LOCATION;
|
||||
private String driversLocation = CBConstants.DEFAULT_DRIVERS_LOCATION;
|
||||
@SerializedName("expireSessionAfterPeriod")
|
||||
private long maxSessionIdleTime = CBAuthConstants.MAX_SESSION_IDLE_TIME;
|
||||
private boolean develMode = false;
|
||||
private boolean enableSecurityManager = false;
|
||||
private final Map<String, Object> productSettings = new HashMap<>();
|
||||
|
||||
@SerializedName("database")
|
||||
private WebDatabaseConfig databaseConfiguration = new WebDatabaseConfig();
|
||||
private String staticContent = "";
|
||||
|
||||
public String getServerURL() {
|
||||
if (serverURL == null) {
|
||||
String hostName = serverHost;
|
||||
if (CommonUtils.isEmpty(hostName)) {
|
||||
try {
|
||||
hostName = InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException e) {
|
||||
log.debug("Error resolving localhost address: " + e.getMessage());
|
||||
hostName = CBApplication.HOST_LOCALHOST;
|
||||
}
|
||||
}
|
||||
serverURL = "http://" + hostName + ":" + serverPort;
|
||||
}
|
||||
return serverURL;
|
||||
}
|
||||
|
||||
public int getServerPort() {
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
public String getServerHost() {
|
||||
return serverHost;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
public String getSslConfigurationPath() {
|
||||
return sslConfigurationPath;
|
||||
}
|
||||
|
||||
public String getContentRoot() {
|
||||
return contentRoot;
|
||||
}
|
||||
|
||||
public String getRootURI() {
|
||||
return rootURI;
|
||||
}
|
||||
|
||||
public String getServicesURI() {
|
||||
return serviceURI;
|
||||
}
|
||||
|
||||
public String getWorkspaceLocation() {
|
||||
return workspaceLocation;
|
||||
}
|
||||
|
||||
public String getDriversLocation() {
|
||||
return driversLocation;
|
||||
}
|
||||
|
||||
public WebDatabaseConfig getDatabaseConfiguration() {
|
||||
return databaseConfiguration;
|
||||
}
|
||||
|
||||
public String getStaticContent() {
|
||||
return staticContent;
|
||||
}
|
||||
|
||||
public void setServerURL(String serverURL) {
|
||||
this.serverURL = serverURL;
|
||||
}
|
||||
|
||||
public void setServerPort(int serverPort) {
|
||||
this.serverPort = serverPort;
|
||||
}
|
||||
|
||||
public void setServerHost(String serverHost) {
|
||||
this.serverHost = serverHost;
|
||||
}
|
||||
|
||||
public void setServerName(String serverName) {
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
public void setSslConfigurationPath(String sslConfigurationPath) {
|
||||
this.sslConfigurationPath = sslConfigurationPath;
|
||||
}
|
||||
|
||||
public void setContentRoot(String contentRoot) {
|
||||
this.contentRoot = contentRoot;
|
||||
}
|
||||
|
||||
public void setRootURI(String rootURI) {
|
||||
this.rootURI = rootURI;
|
||||
}
|
||||
|
||||
public void setServicesURI(String servicesURI) {
|
||||
this.serviceURI = servicesURI;
|
||||
}
|
||||
|
||||
public void setWorkspaceLocation(String workspaceLocation) {
|
||||
this.workspaceLocation = workspaceLocation;
|
||||
}
|
||||
|
||||
public void setDriversLocation(String driversLocation) {
|
||||
this.driversLocation = driversLocation;
|
||||
}
|
||||
|
||||
public void setMaxSessionIdleTime(long maxSessionIdleTime) {
|
||||
this.maxSessionIdleTime = maxSessionIdleTime;
|
||||
}
|
||||
|
||||
public void setDevelMode(boolean develMode) {
|
||||
this.develMode = develMode;
|
||||
}
|
||||
|
||||
public void setEnableSecurityManager(boolean enableSecurityManager) {
|
||||
this.enableSecurityManager = enableSecurityManager;
|
||||
}
|
||||
|
||||
public void setDatabaseConfiguration(WebDatabaseConfig databaseConfiguration) {
|
||||
this.databaseConfiguration = databaseConfiguration;
|
||||
}
|
||||
|
||||
public void setStaticContent(String staticContent) {
|
||||
this.staticContent = staticContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDevelMode() {
|
||||
return develMode;
|
||||
}
|
||||
|
||||
public long getMaxSessionIdleTime() {
|
||||
return maxSessionIdleTime;
|
||||
}
|
||||
|
||||
public boolean isEnableSecurityManager() {
|
||||
return enableSecurityManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, Object> getProductSettings() {
|
||||
return productSettings;
|
||||
}
|
||||
}
|
||||
+619
@@ -0,0 +1,619 @@
|
||||
/*
|
||||
* 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.server;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import io.cloudbeaver.model.app.BaseServerConfigurationController;
|
||||
import io.cloudbeaver.model.app.BaseWebApplication;
|
||||
import io.cloudbeaver.service.security.PasswordPolicyConfiguration;
|
||||
import io.cloudbeaver.service.security.SMControllerConfiguration;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.ModelPreferences;
|
||||
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings;
|
||||
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
|
||||
import org.jkiss.dbeaver.registry.DataSourceNavigatorSettings;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
import org.jkiss.dbeaver.runtime.IVariableResolver;
|
||||
import org.jkiss.dbeaver.utils.ContentUtils;
|
||||
import org.jkiss.dbeaver.utils.PrefUtils;
|
||||
import org.jkiss.dbeaver.utils.SystemVariablesResolver;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
extends BaseServerConfigurationController<T> {
|
||||
|
||||
private static final Log log = Log.getLog(CBServerConfigurationController.class);
|
||||
|
||||
// Configurations
|
||||
protected final SMControllerConfiguration securityManagerConfiguration = new SMControllerConfiguration();
|
||||
private final T serverConfiguration;
|
||||
private final CBAppConfig appConfiguration = new CBAppConfig();
|
||||
private Map<String, String> externalProperties = new LinkedHashMap<>();
|
||||
private Map<String, Object> originalConfigurationProperties = new LinkedHashMap<>();
|
||||
|
||||
protected CBServerConfigurationController(T serverConfiguration) {
|
||||
this.serverConfiguration = serverConfiguration;
|
||||
}
|
||||
|
||||
public String getAuthServiceURL() {
|
||||
return Stream.of(serverConfiguration.getServerURL(),
|
||||
serverConfiguration.getRootURI(),
|
||||
serverConfiguration.getServicesURI())
|
||||
.map(WebAppUtils::removeSideSlashes)
|
||||
.filter(CommonUtils::isNotEmpty)
|
||||
.collect(Collectors.joining("/"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadServerConfiguration(Path configPath) throws DBException {
|
||||
log.debug("Using configuration [" + configPath + "]");
|
||||
|
||||
if (!Files.exists(configPath)) {
|
||||
log.error("Configuration file " + configPath + " doesn't exist. Use defaults.");
|
||||
} else {
|
||||
loadConfiguration(configPath);
|
||||
}
|
||||
|
||||
// Try to load configuration from runtime app config file
|
||||
Path runtimeConfigPath = getRuntimeAppConfigPath();
|
||||
if (Files.exists(runtimeConfigPath)) {
|
||||
log.debug("Runtime configuration [" + runtimeConfigPath.toAbsolutePath() + "]");
|
||||
loadConfiguration(runtimeConfigPath);
|
||||
}
|
||||
|
||||
// Set default preferences
|
||||
PrefUtils.setDefaultPreferenceValue(DBWorkbench.getPlatform().getPreferenceStore(),
|
||||
ModelPreferences.UI_DRIVERS_HOME,
|
||||
getServerConfiguration().getDriversLocation());
|
||||
}
|
||||
|
||||
public void loadConfiguration(Path configPath) throws DBException {
|
||||
CBAppConfig prevConfig = new CBAppConfig(appConfiguration);
|
||||
Map<String, Object> configProps = readConfiguration(configPath);
|
||||
try {
|
||||
parseConfiguration(configProps);
|
||||
} catch (Exception e) {
|
||||
throw new DBException("Error parsing server configuration", e);
|
||||
}
|
||||
|
||||
// Backward compatibility: load configs map
|
||||
appConfiguration.loadLegacyCustomConfigs();
|
||||
|
||||
// Merge new config with old one
|
||||
mergeOldConfiguration(prevConfig);
|
||||
|
||||
patchConfigurationWithProperties(getServerConfiguration().getProductSettings());
|
||||
}
|
||||
|
||||
protected void parseConfiguration(Map<String, Object> configProps) throws DBException {
|
||||
Map<String, Object> serverConfig = JSONUtils.getObject(configProps, "server");
|
||||
|
||||
readExternalProperties(serverConfig);
|
||||
patchConfigurationWithProperties(configProps); // patch again because properties can be changed
|
||||
|
||||
Gson gson = getGson();
|
||||
Map<String, Object> currentConfigurationAsMap = gson.fromJson(gson.toJson(getServerConfiguration()),
|
||||
JSONUtils.MAP_TYPE_TOKEN);
|
||||
serverConfig = WebAppUtils.mergeConfigurations(currentConfigurationAsMap, serverConfig);
|
||||
gson.fromJson(
|
||||
gson.toJson(serverConfig),
|
||||
getServerConfiguration().getClass()
|
||||
);
|
||||
|
||||
parseServerConfiguration();
|
||||
|
||||
//SM config
|
||||
gson.fromJson(
|
||||
gson.toJson(JSONUtils.getObject(serverConfig, CBConstants.PARAM_SM_CONFIGURATION)),
|
||||
SMControllerConfiguration.class
|
||||
);
|
||||
// App config
|
||||
Map<String, Object> appConfig = JSONUtils.getObject(configProps, "app");
|
||||
validateConfiguration(appConfig);
|
||||
gson.fromJson(gson.toJson(appConfig), CBAppConfig.class);
|
||||
readProductConfiguration(serverConfig, gson);
|
||||
}
|
||||
|
||||
public T parseServerConfiguration() {
|
||||
var config = getServerConfiguration();
|
||||
if (config.getServerURL() == null) {
|
||||
String hostName = config.getServerHost();
|
||||
if (CommonUtils.isEmpty(hostName)) {
|
||||
try {
|
||||
hostName = InetAddress.getLocalHost().getHostName();
|
||||
} catch (UnknownHostException e) {
|
||||
log.debug("Error resolving localhost address: " + e.getMessage());
|
||||
hostName = CBApplication.HOST_LOCALHOST;
|
||||
}
|
||||
}
|
||||
config.setServerURL("http://" + hostName + ":" + config.getServerPort());
|
||||
}
|
||||
var homeDirectory = CBApplication.getInstance().getHomeDirectory().toString();
|
||||
config.setContentRoot(WebAppUtils.getRelativePath(config.getContentRoot(), homeDirectory));
|
||||
config.setRootURI(readRootUri(config.getRootURI()));
|
||||
config.setDriversLocation(WebAppUtils.getRelativePath(config.getDriversLocation(), homeDirectory));
|
||||
config.setWorkspaceLocation(WebAppUtils.getRelativePath(config.getWorkspaceLocation(), homeDirectory));
|
||||
|
||||
String staticContentsFile = config.getStaticContent();
|
||||
if (!CommonUtils.isEmpty(staticContentsFile)) {
|
||||
try {
|
||||
config.setStaticContent(Files.readString(Path.of(staticContentsFile)));
|
||||
} catch (IOException e) {
|
||||
log.error("Error reading static contents from " + staticContentsFile, e);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
protected void validateConfiguration(Map<String, Object> appConfig) throws DBException {
|
||||
|
||||
}
|
||||
|
||||
private void readExternalProperties(Map<String, Object> serverConfig) {
|
||||
String externalPropertiesFile = JSONUtils.getString(serverConfig, CBConstants.PARAM_EXTERNAL_PROPERTIES);
|
||||
if (!CommonUtils.isEmpty(externalPropertiesFile)) {
|
||||
Properties props = new Properties();
|
||||
try (InputStream is = Files.newInputStream(Path.of(externalPropertiesFile))) {
|
||||
props.load(is);
|
||||
} catch (IOException e) {
|
||||
log.error("Error loading external properties from " + externalPropertiesFile, e);
|
||||
}
|
||||
for (String propName : props.stringPropertyNames()) {
|
||||
this.externalProperties.put(propName, props.getProperty(propName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void mergeOldConfiguration(CBAppConfig prevConfig) {
|
||||
Map<String, Object> mergedPlugins = Stream.concat(
|
||||
prevConfig.getPlugins().entrySet().stream(),
|
||||
appConfiguration.getPlugins().entrySet().stream()
|
||||
)
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (o, o2) -> o2));
|
||||
appConfiguration.setPlugins(mergedPlugins);
|
||||
|
||||
Set<SMAuthProviderCustomConfiguration> mergedAuthProviders = Stream.concat(
|
||||
prevConfig.getAuthCustomConfigurations().stream(),
|
||||
appConfiguration.getAuthCustomConfigurations().stream()
|
||||
)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
appConfiguration.setAuthProvidersConfigurations(mergedAuthProviders);
|
||||
}
|
||||
|
||||
protected void readProductConfiguration(Map<String, Object> serverConfig, Gson gson)
|
||||
throws DBException {
|
||||
// legacy configuration with path to product.conf file
|
||||
if (!serverConfig.containsKey(CBConstants.PARAM_PRODUCT_SETTINGS)
|
||||
&& serverConfig.get(CBConstants.PARAM_PRODUCT_CONFIGURATION) instanceof String
|
||||
) {
|
||||
String productConfigPath = WebAppUtils.getRelativePath(
|
||||
JSONUtils.getString(
|
||||
serverConfig,
|
||||
CBConstants.PARAM_PRODUCT_CONFIGURATION,
|
||||
CBConstants.DEFAULT_PRODUCT_CONFIGURATION
|
||||
),
|
||||
CBApplication.getInstance().getHomeDirectory().toString()
|
||||
);
|
||||
if (!CommonUtils.isEmpty(productConfigPath)) {
|
||||
File productConfigFile = new File(productConfigPath);
|
||||
if (!productConfigFile.exists()) {
|
||||
log.error("Product configuration file not found (" + productConfigFile.getAbsolutePath() + "'");
|
||||
} else {
|
||||
log.debug("Load product configuration from '" + productConfigFile.getAbsolutePath() + "'");
|
||||
try (Reader reader = new InputStreamReader(new FileInputStream(productConfigFile),
|
||||
StandardCharsets.UTF_8)) {
|
||||
serverConfiguration.getProductSettings()
|
||||
.putAll(WebAppUtils.flattenMap(JSONUtils.parseMap(gson, reader)));
|
||||
} catch (Exception e) {
|
||||
throw new DBException("Error reading product configuration", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add product config from runtime
|
||||
File rtConfig = getRuntimeProductConfigFilePath().toFile();
|
||||
if (rtConfig.exists()) {
|
||||
log.debug("Load product runtime configuration from '" + rtConfig.getAbsolutePath() + "'");
|
||||
try (Reader reader = new InputStreamReader(new FileInputStream(rtConfig), StandardCharsets.UTF_8)) {
|
||||
var runtimeProductSettings = JSONUtils.parseMap(gson, reader);
|
||||
var productSettings = serverConfiguration.getProductSettings();
|
||||
productSettings.putAll(runtimeProductSettings);
|
||||
Map<String, Object> flattenConfig = WebAppUtils.flattenMap(productSettings);
|
||||
productSettings.clear();
|
||||
productSettings.putAll(flattenConfig);
|
||||
} catch (Exception e) {
|
||||
throw new DBException("Error reading product runtime configuration", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, Object> readConnectionsPermissionsConfiguration(Path parentPath) {
|
||||
String permissionsConfigPath = WebAppUtils.getRelativePath(CBConstants.DEFAULT_DATASOURCE_PERMISSIONS_CONFIGURATION,
|
||||
parentPath);
|
||||
File permissionsConfigFile = new File(permissionsConfigPath);
|
||||
if (permissionsConfigFile.exists()) {
|
||||
log.debug("Load permissions configuration from '" + permissionsConfigFile.getAbsolutePath() + "'");
|
||||
try (Reader reader = new InputStreamReader(new FileInputStream(permissionsConfigFile),
|
||||
StandardCharsets.UTF_8)) {
|
||||
return JSONUtils.parseMap(getGson(), reader);
|
||||
} catch (Exception e) {
|
||||
log.error("Error reading permissions configuration", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Map<String, Object> readConfiguration(Path configPath) throws DBException {
|
||||
Map<String, Object> configProps = new LinkedHashMap<>();
|
||||
if (Files.exists(configPath)) {
|
||||
log.debug("Read configuration [" + configPath.toAbsolutePath() + "]");
|
||||
// saves original configuration file
|
||||
this.originalConfigurationProperties.putAll(readConfigurationFile(configPath));
|
||||
|
||||
configProps.putAll(readConfigurationFile(configPath));
|
||||
patchConfigurationWithProperties(configProps); // patch original properties
|
||||
}
|
||||
return configProps;
|
||||
}
|
||||
|
||||
public Map<String, Object> readConfigurationFile(Path path) throws DBException {
|
||||
try (Reader reader = new InputStreamReader(new FileInputStream(path.toFile()), StandardCharsets.UTF_8)) {
|
||||
return JSONUtils.parseMap(getGson(), reader);
|
||||
} catch (Exception e) {
|
||||
throw new DBException("Error parsing server configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected GsonBuilder getGsonBuilder() {
|
||||
// Stupid way to populate existing objects but ok google (https://github.com/google/gson/issues/431)
|
||||
InstanceCreator<CBAppConfig> appConfigCreator = type -> appConfiguration;
|
||||
InstanceCreator<DataSourceNavigatorSettings> navSettingsCreator = type -> (DataSourceNavigatorSettings) appConfiguration.getDefaultNavigatorSettings();
|
||||
InstanceCreator<SMControllerConfiguration> smConfigCreator = type -> securityManagerConfiguration;
|
||||
InstanceCreator<T> serverConfigCreator = type -> serverConfiguration;
|
||||
InstanceCreator<PasswordPolicyConfiguration> smPasswordPoliceConfigCreator =
|
||||
type -> securityManagerConfiguration.getPasswordPolicyConfiguration();
|
||||
return new GsonBuilder()
|
||||
.setLenient()
|
||||
.registerTypeAdapter(getServerConfiguration().getClass(), serverConfigCreator)
|
||||
.registerTypeAdapter(CBAppConfig.class, appConfigCreator)
|
||||
.registerTypeAdapter(DataSourceNavigatorSettings.class, navSettingsCreator)
|
||||
.registerTypeAdapter(SMControllerConfiguration.class, smConfigCreator)
|
||||
.registerTypeAdapter(PasswordPolicyConfiguration.class, smPasswordPoliceConfigCreator);
|
||||
}
|
||||
|
||||
protected void saveRuntimeConfig(SMCredentialsProvider credentialsProvider) throws DBException {
|
||||
saveRuntimeConfig(
|
||||
serverConfiguration.getServerName(),
|
||||
serverConfiguration.getServerURL(),
|
||||
serverConfiguration.getMaxSessionIdleTime(),
|
||||
appConfiguration,
|
||||
credentialsProvider
|
||||
);
|
||||
}
|
||||
|
||||
protected void saveRuntimeConfig(
|
||||
String newServerName,
|
||||
String newServerURL,
|
||||
long sessionExpireTime,
|
||||
CBAppConfig appConfig,
|
||||
SMCredentialsProvider credentialsProvider
|
||||
) throws DBException {
|
||||
if (newServerName == null) {
|
||||
throw new DBException("Invalid server configuration, server name cannot be empty");
|
||||
}
|
||||
Map<String, Object> configurationProperties = collectConfigurationProperties(newServerName,
|
||||
newServerURL,
|
||||
sessionExpireTime,
|
||||
appConfig);
|
||||
writeRuntimeConfig(getRuntimeAppConfigPath(), configurationProperties);
|
||||
}
|
||||
|
||||
private void writeRuntimeConfig(Path runtimeConfigPath, Map<String, Object> configurationProperties)
|
||||
throws DBException {
|
||||
if (Files.exists(runtimeConfigPath)) {
|
||||
ContentUtils.makeFileBackup(runtimeConfigPath);
|
||||
}
|
||||
|
||||
try (Writer out = new OutputStreamWriter(new FileOutputStream(runtimeConfigPath.toFile()),
|
||||
StandardCharsets.UTF_8)) {
|
||||
Gson gson = new GsonBuilder()
|
||||
.setLenient()
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
gson.toJson(configurationProperties, out);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new DBException("Error writing runtime configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, Object> collectConfigurationProperties(
|
||||
String newServerName,
|
||||
String newServerURL,
|
||||
long sessionExpireTime,
|
||||
CBAppConfig appConfig
|
||||
) {
|
||||
Map<String, Object> rootConfig = new LinkedHashMap<>();
|
||||
{
|
||||
var originServerConfig = BaseWebApplication.getServerConfigProps(this.originalConfigurationProperties); // get server properties from original configuration file
|
||||
var serverConfigProperties = collectServerConfigProperties(newServerName,
|
||||
newServerURL,
|
||||
sessionExpireTime,
|
||||
originServerConfig);
|
||||
rootConfig.put("server", serverConfigProperties);
|
||||
}
|
||||
{
|
||||
var appConfigProperties = new LinkedHashMap<String, Object>();
|
||||
Map<String, Object> oldAppConfig = JSONUtils.getObject(this.originalConfigurationProperties, "app");
|
||||
rootConfig.put("app", appConfigProperties);
|
||||
|
||||
copyConfigValue(
|
||||
oldAppConfig, appConfigProperties, "anonymousAccessEnabled", appConfig.isAnonymousAccessEnabled());
|
||||
copyConfigValue(
|
||||
oldAppConfig,
|
||||
appConfigProperties,
|
||||
"supportsCustomConnections",
|
||||
appConfig.isSupportsCustomConnections());
|
||||
copyConfigValue(
|
||||
oldAppConfig,
|
||||
appConfigProperties,
|
||||
"publicCredentialsSaveEnabled",
|
||||
appConfig.isPublicCredentialsSaveEnabled());
|
||||
copyConfigValue(
|
||||
oldAppConfig,
|
||||
appConfigProperties,
|
||||
"adminCredentialsSaveEnabled",
|
||||
appConfig.isAdminCredentialsSaveEnabled());
|
||||
copyConfigValue(
|
||||
oldAppConfig, appConfigProperties, "enableReverseProxyAuth", appConfig.isEnabledReverseProxyAuth());
|
||||
copyConfigValue(
|
||||
oldAppConfig, appConfigProperties, "forwardProxy", appConfig.isEnabledForwardProxy());
|
||||
copyConfigValue(
|
||||
oldAppConfig,
|
||||
appConfigProperties,
|
||||
"linkExternalCredentialsWithUser",
|
||||
appConfig.isLinkExternalCredentialsWithUser());
|
||||
copyConfigValue(
|
||||
oldAppConfig, appConfigProperties, "redirectOnFederatedAuth", appConfig.isRedirectOnFederatedAuth());
|
||||
copyConfigValue(
|
||||
oldAppConfig,
|
||||
appConfigProperties,
|
||||
CBConstants.PARAM_RESOURCE_MANAGER_ENABLED,
|
||||
appConfig.isResourceManagerEnabled());
|
||||
copyConfigValue(
|
||||
oldAppConfig,
|
||||
appConfigProperties,
|
||||
CBConstants.PARAM_SHOW_READ_ONLY_CONN_INFO,
|
||||
appConfig.isShowReadOnlyConnectionInfo());
|
||||
copyConfigValue(
|
||||
oldAppConfig,
|
||||
appConfigProperties,
|
||||
CBConstants.PARAM_CONN_GRANT_ANON_ACCESS,
|
||||
appConfig.isGrantConnectionsAccessToAnonymousTeam());
|
||||
copyConfigValue(
|
||||
oldAppConfig,
|
||||
appConfigProperties,
|
||||
"systemVariablesResolvingEnabled",
|
||||
appConfig.isSystemVariablesResolvingEnabled()
|
||||
);
|
||||
Map<String, Object> resourceQuotas = new LinkedHashMap<>();
|
||||
Map<String, Object> originResourceQuotas = JSONUtils.getObject(oldAppConfig,
|
||||
CBConstants.PARAM_RESOURCE_QUOTAS);
|
||||
for (Map.Entry<String, Object> mp : appConfig.getResourceQuotas().entrySet()) {
|
||||
copyConfigValue(originResourceQuotas, resourceQuotas, mp.getKey(), mp.getValue());
|
||||
}
|
||||
appConfigProperties.put(CBConstants.PARAM_RESOURCE_QUOTAS, resourceQuotas);
|
||||
|
||||
{
|
||||
// Save only differences in def navigator settings
|
||||
DBNBrowseSettings navSettings = appConfig.getDefaultNavigatorSettings();
|
||||
var navigatorProperties = new LinkedHashMap<String, Object>();
|
||||
appConfigProperties.put("defaultNavigatorSettings", navigatorProperties);
|
||||
|
||||
if (navSettings.isShowSystemObjects() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isShowSystemObjects()) {
|
||||
navigatorProperties.put("showSystemObjects", navSettings.isShowSystemObjects());
|
||||
}
|
||||
if (navSettings.isShowUtilityObjects() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isShowUtilityObjects()) {
|
||||
navigatorProperties.put("showUtilityObjects", navSettings.isShowUtilityObjects());
|
||||
}
|
||||
if (navSettings.isShowOnlyEntities() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isShowOnlyEntities()) {
|
||||
navigatorProperties.put("showOnlyEntities", navSettings.isShowOnlyEntities());
|
||||
}
|
||||
if (navSettings.isMergeEntities() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isMergeEntities()) {
|
||||
navigatorProperties.put("mergeEntities", navSettings.isMergeEntities());
|
||||
}
|
||||
if (navSettings.isHideFolders() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isHideFolders()) {
|
||||
navigatorProperties.put("hideFolders", navSettings.isHideFolders());
|
||||
}
|
||||
if (navSettings.isHideSchemas() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isHideSchemas()) {
|
||||
navigatorProperties.put("hideSchemas", navSettings.isHideSchemas());
|
||||
}
|
||||
if (navSettings.isHideVirtualModel() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isHideVirtualModel()) {
|
||||
navigatorProperties.put("hideVirtualModel", navSettings.isHideVirtualModel());
|
||||
}
|
||||
}
|
||||
if (appConfig.getEnabledFeatures() != null) {
|
||||
appConfigProperties.put("enabledFeatures", Arrays.asList(appConfig.getEnabledFeatures()));
|
||||
}
|
||||
if (appConfig.getEnabledAuthProviders() != null) {
|
||||
appConfigProperties.put("enabledAuthProviders", Arrays.asList(appConfig.getEnabledAuthProviders()));
|
||||
}
|
||||
if (appConfig.getEnabledDrivers() != null) {
|
||||
appConfigProperties.put("enabledDrivers", Arrays.asList(appConfig.getEnabledDrivers()));
|
||||
}
|
||||
if (appConfig.getDisabledDrivers() != null) {
|
||||
appConfigProperties.put("disabledDrivers", Arrays.asList(appConfig.getDisabledDrivers()));
|
||||
}
|
||||
|
||||
if (!CommonUtils.isEmpty(appConfig.getPlugins())) {
|
||||
appConfigProperties.put("plugins", appConfig.getPlugins());
|
||||
}
|
||||
if (!CommonUtils.isEmpty(appConfig.getAuthCustomConfigurations())) {
|
||||
appConfigProperties.put("authConfigurations", appConfig.getAuthCustomConfigurations());
|
||||
}
|
||||
}
|
||||
return rootConfig;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Map<String, Object> collectServerConfigProperties(
|
||||
String newServerName,
|
||||
String newServerURL,
|
||||
long sessionExpireTime,
|
||||
Map<String, Object> originServerConfig
|
||||
) {
|
||||
var serverConfigProperties = new LinkedHashMap<String, Object>();
|
||||
if (!CommonUtils.isEmpty(newServerName)) {
|
||||
copyConfigValue(originServerConfig,
|
||||
serverConfigProperties,
|
||||
CBConstants.PARAM_SERVER_NAME,
|
||||
newServerName);
|
||||
}
|
||||
if (!CommonUtils.isEmpty(newServerURL)) {
|
||||
copyConfigValue(
|
||||
originServerConfig, serverConfigProperties, CBConstants.PARAM_SERVER_URL, newServerURL);
|
||||
}
|
||||
if (sessionExpireTime > 0) {
|
||||
copyConfigValue(
|
||||
originServerConfig,
|
||||
serverConfigProperties,
|
||||
CBConstants.PARAM_SESSION_EXPIRE_PERIOD,
|
||||
sessionExpireTime);
|
||||
}
|
||||
var productConfigProperties = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
Map<String, Object> oldProductRuntimeConfig = JSONUtils.getObject(originServerConfig,
|
||||
CBConstants.PARAM_PRODUCT_SETTINGS);
|
||||
if (!CommonUtils.isEmpty(getServerConfiguration().getProductSettings())) {
|
||||
for (Map.Entry<String, Object> mp : getServerConfiguration().getProductSettings().entrySet()) {
|
||||
copyConfigValue(oldProductRuntimeConfig, productConfigProperties, mp.getKey(), mp.getValue());
|
||||
}
|
||||
serverConfigProperties.put(CBConstants.PARAM_PRODUCT_SETTINGS, productConfigProperties);
|
||||
}
|
||||
return serverConfigProperties;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Configuration utils
|
||||
|
||||
private void patchConfigurationWithProperties(Map<String, Object> configProps) {
|
||||
IVariableResolver varResolver = new SystemVariablesResolver() {
|
||||
@Override
|
||||
public String get(String name) {
|
||||
String propValue = externalProperties.get(name);
|
||||
if (propValue != null) {
|
||||
return propValue;
|
||||
}
|
||||
return super.get(name);
|
||||
}
|
||||
};
|
||||
BaseWebApplication.patchConfigurationWithProperties(configProps, varResolver);
|
||||
}
|
||||
|
||||
// gets info about patterns from original configuration file and saves it to runtime config
|
||||
protected void copyConfigValue(
|
||||
Map<String, Object> oldConfig,
|
||||
Map<String, Object> newConfig,
|
||||
String key,
|
||||
Object defaultValue
|
||||
) {
|
||||
Object value = oldConfig.get(key);
|
||||
if (value instanceof Map && defaultValue instanceof Map) {
|
||||
Map<String, Object> subValue = new LinkedHashMap<>();
|
||||
Map<String, Object> oldConfigValue = JSONUtils.getObject(oldConfig, key);
|
||||
for (Map.Entry<String, Object> entry : oldConfigValue.entrySet()) {
|
||||
copyConfigValue(oldConfigValue, subValue, entry.getKey(), ((Map) defaultValue).get(entry.getKey()));
|
||||
}
|
||||
newConfig.put(key, subValue);
|
||||
} else {
|
||||
Object newConfigValue = WebAppUtils.getExtractedValue(oldConfig.get(key), defaultValue);
|
||||
newConfig.put(key, newConfigValue);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Path getRuntimeAppConfigPath() {
|
||||
return getDataDirectory(true).resolve(CBConstants.RUNTIME_APP_CONFIG_FILE_NAME);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Path getRuntimeProductConfigFilePath() {
|
||||
return getDataDirectory(false).resolve(CBConstants.RUNTIME_PRODUCT_CONFIG_FILE_NAME);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Path getDataDirectory(boolean create) {
|
||||
File dataDir = new File(serverConfiguration.getWorkspaceLocation(), CBConstants.RUNTIME_DATA_DIR_NAME);
|
||||
if (create && !dataDir.exists()) {
|
||||
if (!dataDir.mkdirs()) {
|
||||
log.error("Can't create data directory '" + dataDir.getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
return dataDir.toPath();
|
||||
}
|
||||
|
||||
public void saveProductConfiguration(Map<String, Object> productConfiguration) throws DBException {
|
||||
Map<String, Object> productSettings = getServerConfiguration().getProductSettings();
|
||||
Map<String, Object> mergedConfig = WebAppUtils.mergeConfigurations(productSettings, productConfiguration);
|
||||
productSettings.clear();
|
||||
productSettings.putAll(WebAppUtils.flattenMap(mergedConfig));
|
||||
}
|
||||
|
||||
public T getServerConfiguration() {
|
||||
return serverConfiguration;
|
||||
}
|
||||
|
||||
public CBAppConfig getAppConfiguration() {
|
||||
return appConfiguration;
|
||||
}
|
||||
|
||||
public Map<String, Object> getProductConfiguration() {
|
||||
return getServerConfiguration().getProductSettings();
|
||||
}
|
||||
|
||||
public SMControllerConfiguration getSecurityManagerConfiguration() {
|
||||
return securityManagerConfiguration;
|
||||
}
|
||||
|
||||
private String readRootUri(String uri) {
|
||||
//slashes are needed to correctly display static resources on ui
|
||||
if (!uri.endsWith("/")) {
|
||||
uri = uri + '/';
|
||||
}
|
||||
if (!uri.startsWith("/")) {
|
||||
uri = '/' + uri;
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.server;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import io.cloudbeaver.service.security.db.WebDatabaseConfig;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Server configuration controller for embedded products.
|
||||
*/
|
||||
public class CBServerConfigurationControllerEmbedded<T extends CBServerConfig> extends CBServerConfigurationController<T> {
|
||||
|
||||
private static final Log log = Log.getLog(CBServerConfigurationControllerEmbedded.class);
|
||||
|
||||
public CBServerConfigurationControllerEmbedded(T serverConfig) {
|
||||
super(serverConfig);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Map<String, Object> collectServerConfigProperties(
|
||||
String newServerName,
|
||||
String newServerURL,
|
||||
long sessionExpireTime,
|
||||
Map<String, Object> originServerConfig
|
||||
) {
|
||||
Map<String, Object> serverConfigProperties = super.collectServerConfigProperties(
|
||||
newServerName, newServerURL, sessionExpireTime, originServerConfig);
|
||||
|
||||
var databaseConfigProperties = new LinkedHashMap<String, Object>();
|
||||
Map<String, Object> oldRuntimeDBConfig = JSONUtils.getObject(originServerConfig,
|
||||
CBConstants.PARAM_DB_CONFIGURATION);
|
||||
Gson gson = getGson();
|
||||
Map<String, Object> dbConfigMap = gson.fromJson(
|
||||
gson.toJsonTree(getServerConfiguration().getDatabaseConfiguration()),
|
||||
JSONUtils.MAP_TYPE_TOKEN
|
||||
);
|
||||
if (!CommonUtils.isEmpty(dbConfigMap)) {
|
||||
for (Map.Entry<String, Object> mp : dbConfigMap.entrySet()) {
|
||||
copyConfigValue(oldRuntimeDBConfig, databaseConfigProperties, mp.getKey(), mp.getValue());
|
||||
}
|
||||
serverConfigProperties.put(CBConstants.PARAM_DB_CONFIGURATION, databaseConfigProperties);
|
||||
}
|
||||
savePasswordPolicyConfig(originServerConfig, serverConfigProperties);
|
||||
return serverConfigProperties;
|
||||
}
|
||||
|
||||
|
||||
private void savePasswordPolicyConfig(Map<String, Object> originServerConfig, Map<String, Object> serverConfigProperties) {
|
||||
// save password policy configuration
|
||||
var passwordPolicyProperties = new LinkedHashMap<String, Object>();
|
||||
|
||||
var oldRuntimePasswordPolicyConfig = JSONUtils.getObject(
|
||||
JSONUtils.getObject(originServerConfig, CBConstants.PARAM_SM_CONFIGURATION),
|
||||
CBConstants.PARAM_PASSWORD_POLICY_CONFIGURATION
|
||||
);
|
||||
Gson gson = getGson();
|
||||
Map<String, Object> passwordPolicyConfig = gson.fromJson(
|
||||
gson.toJsonTree(securityManagerConfiguration.getPasswordPolicyConfiguration()),
|
||||
JSONUtils.MAP_TYPE_TOKEN
|
||||
);
|
||||
if (!CommonUtils.isEmpty(passwordPolicyConfig)) {
|
||||
for (Map.Entry<String, Object> mp : passwordPolicyConfig.entrySet()) {
|
||||
copyConfigValue(oldRuntimePasswordPolicyConfig, passwordPolicyProperties, mp.getKey(), mp.getValue());
|
||||
}
|
||||
serverConfigProperties.put(
|
||||
CBConstants.PARAM_SM_CONFIGURATION,
|
||||
Map.of(CBConstants.PARAM_PASSWORD_POLICY_CONFIGURATION, passwordPolicyProperties)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GsonBuilder getGsonBuilder() {
|
||||
GsonBuilder gsonBuilder = super.getGsonBuilder();
|
||||
var databaseConfiguration = getServerConfiguration().getDatabaseConfiguration();
|
||||
InstanceCreator<WebDatabaseConfig> dbConfigCreator = type -> databaseConfiguration;
|
||||
InstanceCreator<WebDatabaseConfig.Pool> dbPoolConfigCreator = type -> databaseConfiguration.getPool();
|
||||
return gsonBuilder
|
||||
.registerTypeAdapter(WebDatabaseConfig.class, dbConfigCreator)
|
||||
.registerTypeAdapter(WebDatabaseConfig.Pool.class, dbPoolConfigCreator);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+11
-2
@@ -31,11 +31,20 @@ import java.nio.file.Path;
|
||||
public class WSDeleteTempFileHandler implements WSEventHandler<WSEventDeleteTempFile> {
|
||||
|
||||
private static final Log log = Log.getLog(WSDeleteTempFileHandler.class);
|
||||
private static final String TEMP_FILE_FOLDER = "temp-sql-upload-files";
|
||||
|
||||
public void resetTempFolder(String sessionId) {
|
||||
Path path = CBPlatform.getInstance()
|
||||
.getTempFolder(new VoidProgressMonitor(), TEMP_FILE_FOLDER)
|
||||
.getTempFolder(new VoidProgressMonitor(), CBPlatform.TEMP_FILE_FOLDER)
|
||||
.resolve(sessionId);
|
||||
if (Files.exists(path)) {
|
||||
try {
|
||||
IOUtils.deleteDirectory(path);
|
||||
} catch (IOException e) {
|
||||
log.error("Error deleting temp path", e);
|
||||
}
|
||||
}
|
||||
path = CBPlatform.getInstance()
|
||||
.getTempFolder(new VoidProgressMonitor(), CBPlatform.TEMP_FILE_IMPORT_FOLDER)
|
||||
.resolve(sessionId);
|
||||
if (Files.exists(path)) {
|
||||
try {
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ public class WSObjectPermissionUpdatedEventHandler extends WSDefaultEventHandler
|
||||
return;
|
||||
}
|
||||
if (WSEventType.OBJECT_PERMISSIONS_UPDATED.getEventId().equals(event.getId())) {
|
||||
isAccessibleNow = webSession.findWebConnectionInfo(objectId) != null;
|
||||
isAccessibleNow = webSession.findWebConnectionInfo(project.getId(), objectId) != null;
|
||||
if (isAccessibleNow) {
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ public class WSUserSecretEventHandlerImpl extends WSDefaultEventHandler<WSUserSe
|
||||
activeUserSession.addSessionEvent(event);
|
||||
return;
|
||||
}
|
||||
var connectionInfo = ((WebSession) activeUserSession).findWebConnectionInfo(event.getDataSourceId());
|
||||
var connectionInfo = ((WebSession) activeUserSession).findWebConnectionInfo(event.getProjectId(), event.getDataSourceId());
|
||||
if (connectionInfo == null) {
|
||||
log.debug("Connection " + event.getDataSourceId() + " is not found in session " + activeUserSession.getSessionId());
|
||||
return;
|
||||
|
||||
+29
-29
@@ -18,6 +18,7 @@ package io.cloudbeaver.server.jetty;
|
||||
|
||||
import io.cloudbeaver.registry.WebServiceRegistry;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBServerConfig;
|
||||
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
|
||||
import io.cloudbeaver.server.servlets.CBImageServlet;
|
||||
import io.cloudbeaver.server.servlets.CBStaticServlet;
|
||||
@@ -37,6 +38,7 @@ import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
@@ -68,12 +70,12 @@ public class CBJettyServer {
|
||||
}
|
||||
|
||||
public void runServer() {
|
||||
CBApplication application = CBApplication.getInstance();
|
||||
try {
|
||||
CBServerConfig serverConfiguration = application.getServerConfiguration();
|
||||
JettyServer server;
|
||||
int serverPort = application.getServerPort();
|
||||
String serverHost = application.getServerHost();
|
||||
Path sslPath = application.getSslConfigurationPath();
|
||||
int serverPort = serverConfiguration.getServerPort();
|
||||
String serverHost = serverConfiguration.getServerHost();
|
||||
Path sslPath = getSslConfigurationPath();
|
||||
|
||||
boolean sslConfigurationExists = sslPath != null && Files.exists(sslPath);
|
||||
if (sslConfigurationExists) {
|
||||
@@ -97,8 +99,8 @@ public class CBJettyServer {
|
||||
{
|
||||
// Handler configuration
|
||||
ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
servletContextHandler.setResourceBase(application.getContentRoot());
|
||||
String rootURI = application.getRootURI();
|
||||
servletContextHandler.setResourceBase(serverConfiguration.getContentRoot());
|
||||
String rootURI = serverConfiguration.getRootURI();
|
||||
servletContextHandler.setContextPath(rootURI);
|
||||
|
||||
ServletHolder staticServletHolder = new ServletHolder("static", new CBStaticServlet());
|
||||
@@ -106,11 +108,11 @@ public class CBJettyServer {
|
||||
servletContextHandler.addServlet(staticServletHolder, "/*");
|
||||
|
||||
ServletHolder imagesServletHolder = new ServletHolder("images", new CBImageServlet());
|
||||
servletContextHandler.addServlet(imagesServletHolder, application.getServicesURI() + "images/*");
|
||||
servletContextHandler.addServlet(imagesServletHolder, serverConfiguration.getServicesURI() + "images/*");
|
||||
|
||||
servletContextHandler.addServlet(new ServletHolder("status", new CBStatusServlet()), "/status");
|
||||
|
||||
servletContextHandler.addServlet(new ServletHolder("graphql", new GraphQLEndpoint()), application.getServicesURI() + "gql/*");
|
||||
servletContextHandler.addServlet(new ServletHolder("graphql", new GraphQLEndpoint()), serverConfiguration.getServicesURI() + "gql/*");
|
||||
servletContextHandler.addEventListener(new CBServerContextListener());
|
||||
|
||||
// Add extensions from services
|
||||
@@ -118,7 +120,7 @@ public class CBJettyServer {
|
||||
CBJettyServletContext servletContext = new CBJettyServletContext(servletContextHandler);
|
||||
for (DBWServiceBindingServlet wsd : WebServiceRegistry.getInstance().getWebServices(DBWServiceBindingServlet.class)) {
|
||||
try {
|
||||
wsd.addServlets(application, servletContext);
|
||||
wsd.addServlets(this.application, servletContext);
|
||||
} catch (DBException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
@@ -133,8 +135,8 @@ public class CBJettyServer {
|
||||
wsContainer.setIdleTimeout(Duration.ofMinutes(5));
|
||||
// Add websockets
|
||||
wsContainer.addMapping(
|
||||
application.getServicesURI() + "ws/*",
|
||||
new CBJettyWebSocketManager(application.getSessionManager())
|
||||
serverConfiguration.getServicesURI() + "ws/*",
|
||||
new CBJettyWebSocketManager(this.application.getSessionManager())
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -172,6 +174,16 @@ public class CBJettyServer {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Path getSslConfigurationPath() {
|
||||
var sslConfigurationPath = application.getServerConfiguration().getSslConfigurationPath();
|
||||
if (sslConfigurationPath == null) {
|
||||
return null;
|
||||
}
|
||||
var sslConfiguration = Path.of(sslConfigurationPath);
|
||||
return sslConfiguration.isAbsolute() ? sslConfiguration : application.getHomeDirectory().resolve(sslConfiguration);
|
||||
}
|
||||
|
||||
private void initSessionManager(
|
||||
@NotNull CBApplication application,
|
||||
@NotNull ServletContextHandler servletContextHandler
|
||||
@@ -188,31 +200,19 @@ public class CBJettyServer {
|
||||
}
|
||||
}
|
||||
|
||||
SessionHandler sessionHandler = new SessionHandler()/* {
|
||||
public HttpCookie access(HttpSession session, boolean secure) {
|
||||
HttpCookie cookie = getSessionCookie(session, _context == null ? "/" : (_context.getContextPath()), secure);
|
||||
return cookie;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRefreshCookieAge() {
|
||||
// Refresh cookie always (we need it for FA requests)
|
||||
return 1;
|
||||
}
|
||||
}*/;
|
||||
var maxIdleSeconds = application.getMaxSessionIdleTime();
|
||||
SessionHandler sessionHandler = new SessionHandler();
|
||||
var maxIdleTime = application.getMaxSessionIdleTime();
|
||||
int intMaxIdleSeconds;
|
||||
if (maxIdleSeconds > Integer.MAX_VALUE) {
|
||||
if (maxIdleTime > Integer.MAX_VALUE) {
|
||||
log.warn("Max session idle time value is greater than Integer.MAX_VALUE. Integer.MAX_VALUE will be used instead");
|
||||
intMaxIdleSeconds = Integer.MAX_VALUE;
|
||||
} else {
|
||||
intMaxIdleSeconds = (int) maxIdleSeconds;
|
||||
maxIdleTime = Integer.MAX_VALUE;
|
||||
}
|
||||
intMaxIdleSeconds = (int) (maxIdleTime / 1000);
|
||||
log.debug("Max http session idle time: " + intMaxIdleSeconds + "s");
|
||||
sessionHandler.setMaxInactiveInterval(intMaxIdleSeconds);
|
||||
|
||||
DefaultSessionCache sessionCache = new DefaultSessionCache(sessionHandler);
|
||||
FileSessionDataStore sessionStore = new FileSessionDataStore();
|
||||
|
||||
sessionStore.setStoreDir(sessionCacheFolder.toFile());
|
||||
sessionCache.setSessionDataStore(sessionStore);
|
||||
sessionHandler.setSessionCache(sessionCache);
|
||||
|
||||
+4
-2
@@ -29,6 +29,7 @@ import io.cloudbeaver.registry.WebServletHandlerDescriptor;
|
||||
import io.cloudbeaver.server.CBAppConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.server.CBServerConfig;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.WebServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -212,9 +213,10 @@ public class CBStaticServlet extends DefaultServlet {
|
||||
IOUtils.copyStream(fis, baos);
|
||||
}
|
||||
String indexContents = baos.toString(StandardCharsets.UTF_8);
|
||||
CBServerConfig serverConfig = CBApplication.getInstance().getServerConfiguration();
|
||||
indexContents = indexContents
|
||||
.replace("{ROOT_URI}", CBApplication.getInstance().getRootURI())
|
||||
.replace("{STATIC_CONTENT}", CBApplication.getInstance().getStaticContent());
|
||||
.replace("{ROOT_URI}", serverConfig.getRootURI())
|
||||
.replace("{STATIC_CONTENT}", serverConfig.getStaticContent());
|
||||
byte[] indexBytes = indexContents.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
putHeaders(response, content, indexBytes.length);
|
||||
|
||||
+7
@@ -18,6 +18,7 @@ package io.cloudbeaver.server.websockets;
|
||||
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.websocket.CBWebSessionEventHandler;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
@@ -76,6 +77,12 @@ public class CBEventsWebSocket extends CBAbstractWebSocket implements CBWebSessi
|
||||
this.webSession.getEventsFilter().setSubscribedProjects(projectEvent.getProjectIds());
|
||||
break;
|
||||
}
|
||||
case SESSION_PING: {
|
||||
if (webSession instanceof WebSession session) {
|
||||
session.updateInfo(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
var e = new DBWebException("Unknown websocket client event: " + clientEvent.getId());
|
||||
log.error(e.getMessage(), e);
|
||||
|
||||
+2
@@ -29,6 +29,7 @@ import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.security.exception.SMAccessTokenExpiredException;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -54,6 +55,7 @@ public class CBJettyWebSocketManager implements JettyWebSocketCreator {
|
||||
var httpRequest = request.getHttpServletRequest();
|
||||
var webSession = webSessionManager.getOrRestoreSession(httpRequest);
|
||||
if (webSession != null) {
|
||||
webSession.updateSessionParameters(httpRequest);
|
||||
// web client session
|
||||
return createNewEventsWebSocket(webSession);
|
||||
}
|
||||
|
||||
+4
@@ -41,6 +41,9 @@ public interface DBWServiceCore extends DBWService {
|
||||
@WebAction(authRequired = false)
|
||||
WebServerConfig getServerConfig() throws DBWebException;
|
||||
|
||||
@WebAction(authRequired = false)
|
||||
WebProductSettings getProductSettings(@NotNull WebSession webSession);
|
||||
|
||||
@WebAction
|
||||
List<WebDatabaseDriverInfo> getDriverList(@NotNull WebSession webSession, String driverId) throws DBWebException;
|
||||
|
||||
@@ -94,6 +97,7 @@ public interface DBWServiceCore extends DBWService {
|
||||
@WebAction(authRequired = false)
|
||||
boolean touchSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse servletResponse) throws DBWebException;
|
||||
|
||||
@Deprecated
|
||||
@WebAction(authRequired = false)
|
||||
WebSession updateSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response)
|
||||
throws DBWebException;
|
||||
|
||||
+1
@@ -53,6 +53,7 @@ public class WebServiceBindingCore extends WebServiceBindingBase<DBWServiceCore>
|
||||
WebSessionManager sessionManager = platform.getSessionManager();
|
||||
model.getQueryType()
|
||||
.dataFetcher("serverConfig", env -> getService(env).getServerConfig())
|
||||
.dataFetcher("productSettings", env -> getService(env).getProductSettings(getWebSession(env)))
|
||||
|
||||
.dataFetcher("driverList", env -> getService(env).getDriverList(getWebSession(env), env.getArgument("id")))
|
||||
.dataFetcher("authModels", env -> getService(env).getAuthModels(getWebSession(env)))
|
||||
|
||||
+64
-29
@@ -62,6 +62,7 @@ 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.ProductSettingsRegistry;
|
||||
import org.jkiss.dbeaver.runtime.jobs.ConnectionTestJob;
|
||||
import org.jkiss.dbeaver.utils.RuntimeUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
@@ -177,8 +178,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
|
||||
for (DBPDataSourceContainer ds : registry.getDataSources()) {
|
||||
if (ds.isTemplate() &&
|
||||
CBPlatform.getInstance().getApplicableDrivers().contains(ds.getDriver()))
|
||||
{
|
||||
CBPlatform.getInstance().getApplicableDrivers().contains(ds.getDriver())) {
|
||||
result.add(new WebConnectionInfo(webSession, ds));
|
||||
}
|
||||
}
|
||||
@@ -206,13 +206,13 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
@NotNull DBPProject project
|
||||
) {
|
||||
return project.getDataSourceRegistry().getAllFolders().stream()
|
||||
.map(f -> new WebConnectionFolderInfo(webSession, f)).collect(Collectors.toList());
|
||||
.map(f -> new WebConnectionFolderInfo(webSession, f)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSessionPermissions(@NotNull WebSession webSession) throws DBWebException {
|
||||
if (CBApplication.getInstance().isConfigurationMode()) {
|
||||
return new String[] {
|
||||
return new String[]{
|
||||
DBWConstants.PERMISSION_ADMIN
|
||||
};
|
||||
}
|
||||
@@ -224,8 +224,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
@NotNull WebSession webSession,
|
||||
@Nullable String defaultLocale,
|
||||
@NotNull HttpServletRequest servletRequest,
|
||||
@NotNull HttpServletResponse servletResponse) throws DBWebException
|
||||
{
|
||||
@NotNull HttpServletResponse servletResponse
|
||||
) throws DBWebException {
|
||||
for (WebSessionHandlerDescriptor hd : WebHandlerRegistry.getInstance().getSessionHandlers()) {
|
||||
try {
|
||||
hd.getInstance().handleSessionOpen(webSession, servletRequest, servletResponse);
|
||||
@@ -255,7 +255,11 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WebServerMessage> readSessionLog(@NotNull WebSession webSession, Integer maxEntries, Boolean clearEntries) {
|
||||
public List<WebServerMessage> readSessionLog(
|
||||
@NotNull WebSession webSession,
|
||||
Integer maxEntries,
|
||||
Boolean clearEntries
|
||||
) {
|
||||
return webSession.readLog(maxEntries, clearEntries);
|
||||
}
|
||||
|
||||
@@ -282,11 +286,13 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean touchSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws DBWebException {
|
||||
return CBPlatform.getInstance().getSessionManager().touchSession(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public WebSession updateSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response)
|
||||
throws DBWebException {
|
||||
WebSessionManager sessionManager = CBPlatform.getInstance().getSessionManager();
|
||||
@@ -295,7 +301,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean refreshSessionConnections(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws DBWebException {
|
||||
public boolean refreshSessionConnections(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response)
|
||||
throws DBWebException {
|
||||
WebSession session = CBPlatform.getInstance().getSessionManager().getWebSession(request, response);
|
||||
if (session == null) {
|
||||
return false;
|
||||
@@ -370,10 +377,12 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
if (networkCredentials != null) {
|
||||
networkCredentials.forEach(c -> {
|
||||
if (CommonUtils.toBoolean(c.isSavePassword())) {
|
||||
DBWHandlerConfiguration handlerCfg = dataSourceContainer.getConnectionConfiguration().getHandler(c.getId());
|
||||
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))
|
||||
!(CommonUtils.isEmpty(c.getUserName()) && CommonUtils.equalObjects(handlerCfg.getType(),
|
||||
DBWHandlerType.TUNNEL))
|
||||
) {
|
||||
WebDataSourceUtils.updateHandlerCredentials(handlerCfg, c);
|
||||
handlerCfg.setSavePassword(true);
|
||||
@@ -396,14 +405,16 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
if (project.isUseSecretStorage()) {
|
||||
try {
|
||||
dataSourceContainer.persistSecrets(
|
||||
DBSSecretController.getProjectSecretController(dataSourceContainer.getProject())
|
||||
DBSSecretController.getProjectSecretController(dataSourceContainer.getProject())
|
||||
);
|
||||
} catch (DBException e) {
|
||||
throw new DBWebException("Failed to save credentials", e);
|
||||
}
|
||||
}
|
||||
|
||||
WebDataSourceUtils.saveCredentialsInDataSource(connectionInfo, dataSourceContainer, dataSourceContainer.getConnectionConfiguration());
|
||||
WebDataSourceUtils.saveCredentialsInDataSource(connectionInfo,
|
||||
dataSourceContainer,
|
||||
dataSourceContainer.getConnectionConfiguration());
|
||||
saveConfig[0] = true;
|
||||
}
|
||||
if (WebServiceUtils.isGlobalProject(dataSourceContainer.getProject())) {
|
||||
@@ -438,7 +449,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
if (connectionConfig.isTemplate()) {
|
||||
connectionConfig.setSaveCredentials(false);
|
||||
}
|
||||
DBPDataSourceContainer newDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig, sessionRegistry);
|
||||
DBPDataSourceContainer newDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig,
|
||||
sessionRegistry);
|
||||
if (CommonUtils.isEmpty(newDataSource.getName())) {
|
||||
newDataSource.setName(CommonUtils.notNull(connectionConfig.getName(), "NewConnection"));
|
||||
}
|
||||
@@ -454,7 +466,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
|
||||
WebConnectionInfo connectionInfo = new WebConnectionInfo(webSession, newDataSource);
|
||||
webSession.addConnection(connectionInfo);
|
||||
webSession.addInfoMessage("New connection was created - " + WebServiceUtils.getConnectionContainerInfo(newDataSource));
|
||||
webSession.addInfoMessage("New connection was created - " + WebServiceUtils.getConnectionContainerInfo(
|
||||
newDataSource));
|
||||
WebEventUtils.addDataSourceUpdatedEvent(
|
||||
webSession.getProjectById(projectId),
|
||||
webSession,
|
||||
@@ -469,7 +482,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
public WebConnectionInfo updateConnection(
|
||||
@NotNull WebSession webSession,
|
||||
@Nullable String projectId,
|
||||
@NotNull WebConnectionConfig config) throws DBWebException {
|
||||
@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()) {
|
||||
@@ -492,7 +506,9 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
|
||||
dataSource.setFolder(config.getFolder() != null ? sessionRegistry.getFolder(config.getFolder()) : null);
|
||||
|
||||
WebServiceUtils.setConnectionConfiguration(dataSource.getDriver(), dataSource.getConnectionConfiguration(), config);
|
||||
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());
|
||||
@@ -541,7 +557,10 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
private WSDataSourceProperty getDatasourceEventProperty(DataSourceDescriptor oldDataSource, DBPDataSourceContainer dataSource) {
|
||||
private WSDataSourceProperty getDatasourceEventProperty(
|
||||
DataSourceDescriptor oldDataSource,
|
||||
DBPDataSourceContainer dataSource
|
||||
) {
|
||||
if (!oldDataSource.equalConfiguration((DataSourceDescriptor) dataSource)) {
|
||||
return WSDataSourceProperty.CONFIGURATION;
|
||||
}
|
||||
@@ -581,8 +600,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String projectId,
|
||||
@NotNull String templateId,
|
||||
@Nullable String connectionName) throws DBWebException
|
||||
{
|
||||
@Nullable String connectionName
|
||||
) throws DBWebException {
|
||||
DBPDataSourceRegistry templateRegistry = getProjectById(webSession, projectId).getDataSourceRegistry();
|
||||
DBPDataSourceContainer dataSourceTemplate = templateRegistry.getDataSource(templateId);
|
||||
if (dataSourceTemplate == null) {
|
||||
@@ -616,7 +635,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
@NotNull WebSession webSession,
|
||||
@Nullable String projectId,
|
||||
@NotNull String nodePath,
|
||||
@NotNull WebConnectionConfig config) throws DBWebException {
|
||||
@NotNull WebConnectionConfig config
|
||||
) throws DBWebException {
|
||||
try {
|
||||
DBNModel navigatorModel = webSession.getNavigatorModel();
|
||||
DBPDataSourceRegistry dataSourceRegistry = getProjectById(webSession, projectId).getDataSourceRegistry();
|
||||
@@ -628,7 +648,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
if (!(srcNode instanceof DBNDataSource)) {
|
||||
throw new DBException("Node '" + nodePath + "' is not a datasource node");
|
||||
}
|
||||
DBPDataSourceContainer dataSourceTemplate = ((DBNDataSource)srcNode).getDataSourceContainer();
|
||||
DBPDataSourceContainer dataSourceTemplate = ((DBNDataSource) srcNode).getDataSourceContainer();
|
||||
|
||||
DBPDataSourceContainer newDataSource = dataSourceRegistry.createDataSource(dataSourceTemplate);
|
||||
|
||||
@@ -716,7 +736,9 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
testDataSource = (DataSourceDescriptor) WebServiceUtils.createConnectionFromConfig(connectionConfig,
|
||||
sessionRegistry);
|
||||
}
|
||||
webSession.provideAuthParameters(webSession.getProgressMonitor(), testDataSource, testDataSource.getConnectionConfiguration());
|
||||
webSession.provideAuthParameters(webSession.getProgressMonitor(),
|
||||
testDataSource,
|
||||
testDataSource.getConnectionConfiguration());
|
||||
testDataSource.setSavePassword(true); // We need for test to avoid password callback
|
||||
if (DataSourceDescriptor.class.isAssignableFrom(testDataSource.getClass())) {
|
||||
((DataSourceDescriptor) testDataSource).setAccessCheckRequired(!webSession.hasPermission(DBWConstants.PERMISSION_ADMIN));
|
||||
@@ -740,21 +762,26 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebNetworkEndpointInfo testNetworkHandler(@NotNull WebSession webSession, @NotNull WebNetworkHandlerConfigInput nhConfig) throws DBWebException {
|
||||
public WebNetworkEndpointInfo testNetworkHandler(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull WebNetworkHandlerConfigInput nhConfig
|
||||
) throws DBWebException {
|
||||
DBRProgressMonitor monitor = webSession.getProgressMonitor();
|
||||
monitor.beginTask("Instantiate SSH tunnel", 2);
|
||||
|
||||
NetworkHandlerDescriptor handlerDescriptor = NetworkHandlerRegistry.getInstance().getDescriptor(nhConfig.getId());
|
||||
NetworkHandlerDescriptor handlerDescriptor = NetworkHandlerRegistry.getInstance()
|
||||
.getDescriptor(nhConfig.getId());
|
||||
if (handlerDescriptor == null) {
|
||||
throw new DBWebException("Network handler '" + nhConfig.getId() + "' not found");
|
||||
}
|
||||
try {
|
||||
DBWNetworkHandler handler = handlerDescriptor.createHandler(DBWNetworkHandler.class);
|
||||
if (handler instanceof DBWTunnel) {
|
||||
DBWTunnel tunnel = (DBWTunnel)handler;
|
||||
DBWTunnel tunnel = (DBWTunnel) handler;
|
||||
DBPConnectionConfiguration connectionConfig = new DBPConnectionConfiguration();
|
||||
connectionConfig.setHostName(DBConstants.HOST_LOCALHOST);
|
||||
connectionConfig.setHostPort(CommonUtils.toString(nhConfig.getProperties().get(DBWHandlerConfiguration.PROP_PORT)));
|
||||
connectionConfig.setHostPort(CommonUtils.toString(nhConfig.getProperties()
|
||||
.get(DBWHandlerConfiguration.PROP_PORT)));
|
||||
try {
|
||||
monitor.subTask("Initialize tunnel");
|
||||
|
||||
@@ -858,7 +885,9 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
}
|
||||
WebProjectImpl project = getProjectById(session, projectId);
|
||||
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
|
||||
DBPDataSourceFolder newFolder = WebConnectionFolderUtils.createFolder(parentNode, folderName, sessionRegistry);
|
||||
DBPDataSourceFolder newFolder = WebConnectionFolderUtils.createFolder(parentNode,
|
||||
folderName,
|
||||
sessionRegistry);
|
||||
WebConnectionFolderInfo folderInfo = new WebConnectionFolderInfo(session, newFolder);
|
||||
WebServiceUtils.updateConfigAndRefreshDatabases(session, projectId);
|
||||
WebEventUtils.addNavigatorNodeUpdatedEvent(
|
||||
@@ -934,7 +963,7 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
WebSession webSession, @Nullable String projectId, String id, DBNBrowseSettings settings
|
||||
) throws DBWebException {
|
||||
WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, id);
|
||||
DataSourceDescriptor dataSourceDescriptor = ((DataSourceDescriptor)connectionInfo.getDataSourceContainer());
|
||||
DataSourceDescriptor dataSourceDescriptor = ((DataSourceDescriptor) connectionInfo.getDataSourceContainer());
|
||||
dataSourceDescriptor.setNavigatorSettings(settings);
|
||||
dataSourceDescriptor.persistConfiguration();
|
||||
WebEventUtils.addDataSourceUpdatedEvent(
|
||||
@@ -947,7 +976,8 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebAsyncTaskInfo getAsyncTaskInfo(WebSession webSession, String taskId, Boolean removeOnFinish) throws DBWebException {
|
||||
public WebAsyncTaskInfo getAsyncTaskInfo(WebSession webSession, String taskId, Boolean removeOnFinish)
|
||||
throws DBWebException {
|
||||
return webSession.asyncTaskStatus(taskId, CommonUtils.toBoolean(removeOnFinish));
|
||||
}
|
||||
|
||||
@@ -956,6 +986,11 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
return webSession.asyncTaskCancel(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebProductSettings getProductSettings(@NotNull WebSession webSession) {
|
||||
return new WebProductSettings(webSession, ProductSettingsRegistry.getInstance().getSettings());
|
||||
}
|
||||
|
||||
private WebProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException {
|
||||
WebProjectImpl project = webSession.getProjectById(projectId);
|
||||
if (project == null) {
|
||||
|
||||
+15
-7
@@ -79,10 +79,12 @@ public class WebSessionManager {
|
||||
return application;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean touchSession(@NotNull HttpServletRequest request,
|
||||
@NotNull HttpServletResponse response) throws DBWebException {
|
||||
WebSession webSession = getWebSession(request, response, false);
|
||||
webSession.updateInfo(request, response);
|
||||
webSession.updateSessionParameters(request);
|
||||
webSession.updateInfo(!request.getSession().isNew());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,14 +107,14 @@ public class WebSessionManager {
|
||||
var baseWebSession = sessionMap.get(sessionId);
|
||||
if (baseWebSession == null && CBApplication.getInstance().isConfigurationMode()) {
|
||||
try {
|
||||
webSession = createWebSessionImpl(httpSession);
|
||||
webSession = createWebSessionImpl(request);
|
||||
} catch (DBException e) {
|
||||
throw new DBWebException("Failed to create web session", e);
|
||||
}
|
||||
sessionMap.put(sessionId, webSession);
|
||||
} else if (baseWebSession == null) {
|
||||
try {
|
||||
webSession = createWebSessionImpl(httpSession);
|
||||
webSession = createWebSessionImpl(request);
|
||||
} catch (DBException e) {
|
||||
throw new DBWebException("Failed to create web session", e);
|
||||
}
|
||||
@@ -174,7 +176,7 @@ public class WebSessionManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
webSession = createWebSessionImpl(httpSession);
|
||||
webSession = createWebSessionImpl(request);
|
||||
restorePreviousUserSession(webSession, oldAuthInfo);
|
||||
|
||||
sessionMap.put(sessionId, webSession);
|
||||
@@ -208,8 +210,8 @@ public class WebSessionManager {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected WebSession createWebSessionImpl(@NotNull HttpSession httpSession) throws DBException {
|
||||
return new WebSession(httpSession, application, getSessionHandlers());
|
||||
protected WebSession createWebSessionImpl(@NotNull HttpServletRequest request) throws DBException {
|
||||
return new WebSession(request, application, getSessionHandlers());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -330,7 +332,13 @@ public class WebSessionManager {
|
||||
})
|
||||
.forEach(session -> {
|
||||
try {
|
||||
session.addSessionEvent(new WSSessionStateEvent(session.getRemainingTime(), session.isValid()));
|
||||
session.addSessionEvent(new WSSessionStateEvent(
|
||||
session.getLastAccessTimeMillis(),
|
||||
session.getRemainingTime(),
|
||||
session.isValid(),
|
||||
((WebSession) session).isCacheExpired(),
|
||||
((WebSession) session).getLocale(),
|
||||
((WebSession) session).getActionParameters()));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to refresh session state: " + session.getSessionId(), e);
|
||||
}
|
||||
|
||||
+5
-1
@@ -16,11 +16,13 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.sql;
|
||||
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.*;
|
||||
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
|
||||
import org.jkiss.dbeaver.model.sql.SQLModelPreferences;
|
||||
import org.jkiss.dbeaver.model.sql.SQLSyntaxManager;
|
||||
import org.jkiss.dbeaver.model.sql.completion.SQLCompletionContext;
|
||||
import org.jkiss.dbeaver.model.sql.completion.SQLCompletionProposalBase;
|
||||
@@ -66,7 +68,9 @@ public class WebSQLCompletionContext implements SQLCompletionContext {
|
||||
|
||||
@Override
|
||||
public boolean isUseFQNames() {
|
||||
return false;
|
||||
return CBPlatform.getInstance()
|
||||
.getPreferenceStore()
|
||||
.getBoolean(SQLModelPreferences.SQL_EDITOR_PROPOSAL_ALWAYS_FQ);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-1
@@ -364,9 +364,16 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
isAutoCommitEnabled = txnManager.isAutoCommit();
|
||||
if (txnManager.isSupportsTransactions() && isAutoCommitEnabled) {
|
||||
txnManager.setAutoCommit(monitor, false);
|
||||
savepoint = txnManager.setSavepoint(monitor, null);
|
||||
revertToAutoCommit = true;
|
||||
}
|
||||
if (!txnManager.isAutoCommit() && txnManager.supportsSavepoints()) {
|
||||
try {
|
||||
savepoint = txnManager.setSavepoint(monitor, null);
|
||||
} catch (Throwable e) {
|
||||
// May be savepoints not supported
|
||||
log.debug("Can't set savepoint", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
Map<String, Object> options = Collections.emptyMap();
|
||||
|
||||
@@ -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.93.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.94.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.admin</artifactId>
|
||||
<version>1.0.93-SNAPSHOT</version>
|
||||
<version>1.0.94-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -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.93.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.94.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.auth</artifactId>
|
||||
<version>1.0.93-SNAPSHOT</version>
|
||||
<version>1.0.94-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -163,9 +163,12 @@ extend type Query {
|
||||
|
||||
}
|
||||
|
||||
|
||||
extend type Mutation {
|
||||
|
||||
# Set user config parameter. If parameter value is null then removes the parameter
|
||||
setUserConfigurationParameter(name: String!, value: Object): Boolean!
|
||||
# Updates user preferences
|
||||
setUserPreferences(preferences: Object!): UserInfo! @since(version: "24.0.1")
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -69,4 +69,10 @@ public interface DBWServiceAuth extends DBWService {
|
||||
@NotNull String name,
|
||||
@Nullable String value) throws DBWebException;
|
||||
|
||||
@WebAction()
|
||||
WebUserInfo setUserConfigurationParameters(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull Map<String, Object> parameters
|
||||
) throws DBWebException;
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -73,6 +73,9 @@ public class WebServiceBindingAuth extends WebServiceBindingBase<DBWServiceAuth>
|
||||
env -> getService(env).setUserConfigurationParameter(getWebSession(env),
|
||||
env.getArgument("name"),
|
||||
env.getArgument("value")))
|
||||
.dataFetcher("setUserPreferences",
|
||||
env -> getService(env).setUserConfigurationParameters(getWebSession(env),
|
||||
env.getArgument("preferences")))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
+27
-2
@@ -18,7 +18,6 @@ package io.cloudbeaver.service.auth.impl;
|
||||
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebServiceUtils;
|
||||
import io.cloudbeaver.auth.SMAuthProviderFederated;
|
||||
import io.cloudbeaver.auth.SMSignOutLinkProvider;
|
||||
import io.cloudbeaver.auth.provider.local.LocalAuthProvider;
|
||||
import io.cloudbeaver.model.WebPropertyInfo;
|
||||
@@ -249,14 +248,40 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String name,
|
||||
@Nullable String value
|
||||
) throws DBWebException {
|
||||
if (webSession.getUser() == null) {
|
||||
throw new DBWebException("Preferences cannot be changed for anonymous user");
|
||||
}
|
||||
return setPreference(webSession, name, value);
|
||||
}
|
||||
|
||||
private static boolean setPreference(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String name,
|
||||
@Nullable Object value
|
||||
) throws DBWebException {
|
||||
webSession.addInfoMessage("Set user parameter - " + name);
|
||||
try {
|
||||
webSession.getSecurityController().setCurrentUserParameter(name, value);
|
||||
String serializedValue = value == null ? null : value.toString();
|
||||
webSession.getSecurityController().setCurrentUserParameter(name, serializedValue);
|
||||
return true;
|
||||
} catch (DBException e) {
|
||||
throw new DBWebException("Error setting user parameter", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebUserInfo setUserConfigurationParameters(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull Map<String, Object> parameters
|
||||
) throws DBWebException {
|
||||
if (webSession.getUser() == null) {
|
||||
throw new DBWebException("Preferences cannot be changed for anonymous user");
|
||||
}
|
||||
for (Map.Entry<String, Object> parameter : parameters.entrySet()) {
|
||||
setPreference(webSession, parameter.getKey(), parameter.getValue());
|
||||
}
|
||||
return new WebUserInfo(webSession, webSession.getUser());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -31,6 +31,7 @@ import java.io.IOException;
|
||||
public class LocalServletHandler extends AbstractActionServletHandler {
|
||||
|
||||
public static final String URI_PREFIX = "open";
|
||||
public static final String PARAM_PROJECT_ID = "project_id";
|
||||
public static final String PARAM_CONNECTION_ID = "id";
|
||||
public static final String PARAM_CONNECTION_NAME = "name";
|
||||
public static final String PARAM_CONNECTION_URL = "url";
|
||||
|
||||
+10
-19
@@ -25,9 +25,7 @@ import io.cloudbeaver.server.actions.CBServerAction;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* LocalSessionHandler
|
||||
@@ -52,29 +50,22 @@ public class LocalSessionHandler extends AbstractActionSessionHandler {
|
||||
|
||||
@Override
|
||||
protected void openDatabaseConsole(WebSession webSession, CBServerAction action) throws DBException {
|
||||
String projectId = action.getParameter(LocalServletHandler.PARAM_PROJECT_ID);
|
||||
String connectionId = action.getParameter(LocalServletHandler.PARAM_CONNECTION_ID);
|
||||
String connectionName = action.getParameter(LocalServletHandler.PARAM_CONNECTION_NAME);
|
||||
String connectionURL = action.getParameter(LocalServletHandler.PARAM_CONNECTION_URL);
|
||||
WebConnectionInfo connectionInfo = null;
|
||||
Stream<WebConnectionInfo> stream = webSession.getConnections().stream();
|
||||
if (projectId != null) {
|
||||
stream = stream.filter(c -> c.getProjectId().equals(projectId));
|
||||
}
|
||||
if (connectionId != null) {
|
||||
connectionInfo = webSession.findWebConnectionInfo(connectionId);
|
||||
stream = stream.filter(c -> c.getId().equals(connectionId));
|
||||
} else if (connectionName != null) {
|
||||
connectionInfo = findConnection(webSession, t -> t.getName().equals(connectionName));
|
||||
stream = stream.filter(t -> t.getName().equals(connectionName));
|
||||
} else if (connectionURL != null) {
|
||||
connectionInfo = findConnection(webSession, t -> t.getUrl().equals(connectionURL));
|
||||
}
|
||||
if (connectionInfo == null) {
|
||||
throw new DBException("Connection is not found in the session");
|
||||
stream = stream.filter(t -> t.getUrl().equals(connectionURL));
|
||||
}
|
||||
WebConnectionInfo connectionInfo = stream.findFirst().orElseThrow(() -> new DBException("Connection is not found in the session"));
|
||||
WebServiceUtils.fireActionParametersOpenEditor(webSession, connectionInfo.getDataSourceContainer(), false);
|
||||
}
|
||||
|
||||
private WebConnectionInfo findConnection(WebSession webSession, Predicate<WebConnectionInfo> filter) {
|
||||
List<WebConnectionInfo> filteredConnections = webSession.getConnections().stream().filter(filter).collect(Collectors.toList());
|
||||
if (filteredConnections.size() != 1) {
|
||||
return null;
|
||||
}
|
||||
return filteredConnections.get(0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.94.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.95.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.data.transfer</artifactId>
|
||||
<version>1.0.94-SNAPSHOT</version>
|
||||
<version>1.0.95-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+3
@@ -53,6 +53,9 @@ extend type Query {
|
||||
# Available transfer processors
|
||||
dataTransferAvailableStreamProcessors: [ DataTransferProcessorInfo! ]!
|
||||
|
||||
# Available transfer processors for import file
|
||||
dataTransferAvailableImportStreamProcessors: [ DataTransferProcessorInfo! ]!
|
||||
|
||||
dataTransferDefaultExportSettings: DataTransferDefaultExportSettings!
|
||||
|
||||
dataTransferExportDataFromContainer(
|
||||
|
||||
+13
@@ -26,7 +26,10 @@ import io.cloudbeaver.service.data.transfer.impl.WebDataTransferParameters;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferStreamProcessor;
|
||||
import io.cloudbeaver.service.sql.WebSQLContextInfo;
|
||||
import io.cloudbeaver.service.sql.WebSQLProcessor;
|
||||
import io.cloudbeaver.service.sql.WebSQLResultsInfo;
|
||||
import org.jkiss.code.NotNull;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -37,12 +40,22 @@ public interface DBWServiceDataTransfer extends DBWService {
|
||||
@WebAction
|
||||
List<WebDataTransferStreamProcessor> getAvailableStreamProcessors(WebSession session) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
List<WebDataTransferStreamProcessor> getAvailableImportStreamProcessors(WebSession session) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
WebAsyncTaskInfo dataTransferExportDataFromContainer(
|
||||
WebSQLProcessor sqlProcessor,
|
||||
String containerNodePath,
|
||||
WebDataTransferParameters parameters) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
WebAsyncTaskInfo asyncImportDataContainer(
|
||||
@NotNull String processorId,
|
||||
@NotNull Path path,
|
||||
@NotNull WebSQLResultsInfo webSQLResultsInfo,
|
||||
@NotNull WebSession webSession) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
WebAsyncTaskInfo dataTransferExportDataFromResults(
|
||||
WebSQLContextInfo sqlContextInfo,
|
||||
|
||||
+8
@@ -24,6 +24,7 @@ import io.cloudbeaver.service.WebServiceBindingBase;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferParameters;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferServlet;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebServiceDataTransfer;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferImportServlet;
|
||||
import io.cloudbeaver.service.sql.WebServiceBindingSQL;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
@@ -42,6 +43,8 @@ public class WebServiceBindingDataTransfer extends WebServiceBindingBase<DBWServ
|
||||
model.getQueryType()
|
||||
.dataFetcher("dataTransferAvailableStreamProcessors",
|
||||
env -> getService(env).getAvailableStreamProcessors(getWebSession(env)))
|
||||
.dataFetcher("dataTransferAvailableImportStreamProcessors",
|
||||
env -> getService(env).getAvailableImportStreamProcessors(getWebSession(env)))
|
||||
.dataFetcher("dataTransferExportDataFromContainer", env -> getService(env).dataTransferExportDataFromContainer(
|
||||
WebServiceBindingSQL.getSQLProcessor(env),
|
||||
env.getArgument("containerNodePath"),
|
||||
@@ -68,5 +71,10 @@ public class WebServiceBindingDataTransfer extends WebServiceBindingBase<DBWServ
|
||||
new WebDataTransferServlet(application, getServiceImpl()),
|
||||
application.getServicesURI() + "data/*"
|
||||
);
|
||||
servletContext.addServlet(
|
||||
"dataTransferImport",
|
||||
new WebDataTransferImportServlet(application, getServiceImpl()),
|
||||
application.getServicesURI() + "data/import/*"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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.service.data.transfer.impl;
|
||||
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.model.WebAsyncTaskInfo;
|
||||
import io.cloudbeaver.model.WebConnectionInfo;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.service.WebServiceServletBase;
|
||||
import io.cloudbeaver.service.data.transfer.DBWServiceDataTransfer;
|
||||
import io.cloudbeaver.service.sql.WebSQLContextInfo;
|
||||
import io.cloudbeaver.service.sql.WebSQLProcessor;
|
||||
import io.cloudbeaver.service.sql.WebSQLResultsInfo;
|
||||
import io.cloudbeaver.service.sql.WebServiceBindingSQL;
|
||||
import jakarta.servlet.MultipartConfigElement;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.MultipartConfig;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
@MultipartConfig
|
||||
public class WebDataTransferImportServlet extends WebServiceServletBase {
|
||||
|
||||
private static final Log log = Log.getLog(WebDataTransferImportServlet.class);
|
||||
public static final String ECLIPSE_JETTY_MULTIPART_CONFIG = "org.eclipse.jetty.multipartConfig";
|
||||
|
||||
DBWServiceDataTransfer dbwServiceDataTransfer;
|
||||
|
||||
|
||||
public WebDataTransferImportServlet(CBApplication application, DBWServiceDataTransfer dbwServiceDataTransfer) {
|
||||
super(application);
|
||||
this.dbwServiceDataTransfer = dbwServiceDataTransfer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processServiceRequest(
|
||||
WebSession session,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response
|
||||
) throws IOException, DBWebException {
|
||||
if (!session.isAuthorizedInSecurityManager()) {
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Import for users only");
|
||||
return;
|
||||
}
|
||||
if ("POST".equalsIgnoreCase(request.getMethod())) {
|
||||
Path tempFolder = CBPlatform.getInstance().getTempFolder(session.getProgressMonitor(), CBPlatform.TEMP_FILE_IMPORT_FOLDER);
|
||||
MultipartConfigElement MULTI_PART_CONFIG = new MultipartConfigElement(tempFolder.toString());
|
||||
|
||||
request.setAttribute(ECLIPSE_JETTY_MULTIPART_CONFIG, MULTI_PART_CONFIG);
|
||||
|
||||
Map<String, Object> variables = getVariables(request);
|
||||
|
||||
String projectId = JSONUtils.getString(variables, "projectId");
|
||||
String connectionId = JSONUtils.getString(variables, "connectionId");
|
||||
String contextId = JSONUtils.getString(variables, "contextId");
|
||||
String resultId = JSONUtils.getString(variables, "resultsId");
|
||||
String processorId = JSONUtils.getString(variables, "processorId");
|
||||
|
||||
if (projectId == null || connectionId == null || contextId == null || resultId == null || processorId == null) {
|
||||
throw new IllegalArgumentException("Missing required parameters");
|
||||
}
|
||||
|
||||
WebConnectionInfo webConnectionInfo = session.getWebConnectionInfo(projectId, connectionId);
|
||||
WebSQLProcessor processor = WebServiceBindingSQL.getSQLProcessor(webConnectionInfo);
|
||||
WebSQLContextInfo webSQLContextInfo = processor.getContext(contextId);
|
||||
|
||||
if (webSQLContextInfo == null) {
|
||||
throw new DBWebException("Context is empty");
|
||||
}
|
||||
|
||||
WebSQLResultsInfo webSQLResultsInfo = webSQLContextInfo.getResults(resultId);
|
||||
Path filePath;
|
||||
|
||||
try {
|
||||
InputStream file = request.getPart("fileData").getInputStream();
|
||||
filePath = tempFolder.resolve(UUID.randomUUID().toString());
|
||||
Files.write(filePath, file.readAllBytes());
|
||||
} catch (ServletException e) {
|
||||
throw new DBWebException(e.getMessage());
|
||||
}
|
||||
|
||||
WebAsyncTaskInfo asyncImportDataContainer =
|
||||
dbwServiceDataTransfer.asyncImportDataContainer(processorId, filePath, webSQLResultsInfo, session);
|
||||
response.setContentType(CBConstants.APPLICATION_JSON);
|
||||
Map<String, Object> parameters = new LinkedHashMap<>();
|
||||
parameters.put("id", asyncImportDataContainer.getId());
|
||||
parameters.put("name", asyncImportDataContainer.getName());
|
||||
parameters.put("running", asyncImportDataContainer.isRunning());
|
||||
parameters.put("status", asyncImportDataContainer.getStatus());
|
||||
parameters.put("error", asyncImportDataContainer.getError());
|
||||
parameters.put("taskResult", asyncImportDataContainer.getTaskResult());
|
||||
try (JsonWriter writer = new JsonWriter(response.getWriter())) {
|
||||
JSONUtils.serializeMap(writer, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+99
-6
@@ -37,24 +37,27 @@ import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
|
||||
import org.jkiss.dbeaver.model.sql.DBQuotaException;
|
||||
import org.jkiss.dbeaver.model.sql.DBSQLException;
|
||||
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
|
||||
import org.jkiss.dbeaver.model.struct.DBSDataManipulator;
|
||||
import org.jkiss.dbeaver.model.struct.DBSEntity;
|
||||
import org.jkiss.dbeaver.model.struct.DBSObjectContainer;
|
||||
import org.jkiss.dbeaver.tools.transfer.IDataTransferConsumer;
|
||||
import org.jkiss.dbeaver.tools.transfer.IDataTransferProcessor;
|
||||
import org.jkiss.dbeaver.tools.transfer.database.DatabaseProducerSettings;
|
||||
import org.jkiss.dbeaver.tools.transfer.database.DatabaseTransferProducer;
|
||||
import org.jkiss.dbeaver.tools.transfer.database.*;
|
||||
import org.jkiss.dbeaver.tools.transfer.registry.DataTransferProcessorDescriptor;
|
||||
import org.jkiss.dbeaver.tools.transfer.registry.DataTransferRegistry;
|
||||
import org.jkiss.dbeaver.tools.transfer.stream.IStreamDataExporter;
|
||||
import org.jkiss.dbeaver.tools.transfer.stream.StreamConsumerSettings;
|
||||
import org.jkiss.dbeaver.tools.transfer.stream.StreamTransferConsumer;
|
||||
import org.jkiss.dbeaver.tools.transfer.stream.*;
|
||||
import org.jkiss.dbeaver.utils.ContentUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.BatchUpdateException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -82,7 +85,19 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
|
||||
@Override
|
||||
public List<WebDataTransferStreamProcessor> getAvailableStreamProcessors(WebSession session) {
|
||||
List<DataTransferProcessorDescriptor> processors = DataTransferRegistry.getInstance().getAvailableProcessors(StreamTransferConsumer.class, DBSEntity.class);
|
||||
List<DataTransferProcessorDescriptor> processors = DataTransferRegistry.getInstance()
|
||||
.getAvailableProcessors(StreamTransferConsumer.class, DBSEntity.class);
|
||||
if (CommonUtils.isEmpty(processors)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return processors.stream().map(x -> new WebDataTransferStreamProcessor(session, x)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WebDataTransferStreamProcessor> getAvailableImportStreamProcessors(WebSession session) {
|
||||
List<DataTransferProcessorDescriptor> processors =
|
||||
DataTransferRegistry.getInstance().getAvailableProcessors(StreamTransferProducer.class, DBSEntity.class);
|
||||
if (CommonUtils.isEmpty(processors)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -205,6 +220,43 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
return sqlProcessor.getWebSession().createAndRunAsyncTask("Data export", runnable);
|
||||
}
|
||||
|
||||
public WebAsyncTaskInfo asyncImportDataContainer(@NotNull String processorId,
|
||||
@NotNull Path path,
|
||||
@NotNull WebSQLResultsInfo sqlContext,
|
||||
@NotNull WebSession webSession) throws DBWebException {
|
||||
webSession.addInfoMessage("Import data");
|
||||
DataTransferProcessorDescriptor processor = DataTransferRegistry.getInstance().getProcessor(processorId);
|
||||
|
||||
DBSDataContainer dataContainer = sqlContext.getDataContainer();
|
||||
WebAsyncTaskProcessor<String> runnable = new WebAsyncTaskProcessor<>() {
|
||||
@Override
|
||||
public void run(DBRProgressMonitor monitor) throws InvocationTargetException {
|
||||
monitor.beginTask("Import data", 1);
|
||||
try {
|
||||
monitor.subTask("Import data using " + processor.getName());
|
||||
try {
|
||||
importData(monitor, processor, (DBSDataManipulator) dataContainer, path);
|
||||
} catch (Exception e) {
|
||||
if (e instanceof DBException) {
|
||||
throw e;
|
||||
}
|
||||
throw new DBException("Error importing data", e);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new InvocationTargetException(e);
|
||||
} finally {
|
||||
try {
|
||||
Files.deleteIfExists(path);
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to delete file: " + e.getMessage(), e);
|
||||
}
|
||||
monitor.done();
|
||||
}
|
||||
}
|
||||
};
|
||||
return webSession.createAndRunAsyncTask("Data import", runnable);
|
||||
}
|
||||
|
||||
private void exportData(
|
||||
DBRProgressMonitor monitor,
|
||||
DataTransferProcessorDescriptor processor,
|
||||
@@ -282,4 +334,45 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
consumer.finishTransfer(monitor, false);
|
||||
}
|
||||
|
||||
private void importData(
|
||||
DBRProgressMonitor monitor,
|
||||
DataTransferProcessorDescriptor processor,
|
||||
@NotNull DBSDataManipulator dataContainer,
|
||||
Path path) throws DBException
|
||||
{
|
||||
IDataTransferProcessor processorInstance = processor.getInstance();
|
||||
|
||||
if (dataContainer.getDataSource() != null) {
|
||||
DatabaseTransferConsumer consumer = new DatabaseTransferConsumer(dataContainer);
|
||||
|
||||
DatabaseConsumerSettings databaseConsumerSettings = new DatabaseConsumerSettings();
|
||||
databaseConsumerSettings.setContainer((DBSObjectContainer) dataContainer.getDataSource());
|
||||
consumer.setSettings(databaseConsumerSettings);
|
||||
DatabaseMappingContainer databaseMappingContainer = new DatabaseMappingContainer(databaseConsumerSettings, dataContainer);
|
||||
databaseMappingContainer.getAttributeMappings(monitor);
|
||||
databaseMappingContainer.setTarget(dataContainer);
|
||||
consumer.setContainerMapping(databaseMappingContainer);
|
||||
|
||||
StreamTransferProducer producer = new StreamTransferProducer(new StreamEntityMapping(path), processor);
|
||||
|
||||
StreamProducerSettings producerSettings = new StreamProducerSettings();
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
for (DBPPropertyDescriptor prop : processor.getProperties()) {
|
||||
properties.put(prop.getId(), prop.getDefaultValue());
|
||||
}
|
||||
producerSettings.setProcessorProperties(properties);
|
||||
producerSettings.updateProducerSettingsFromStream(
|
||||
monitor,
|
||||
producer,
|
||||
processorInstance,
|
||||
properties);
|
||||
|
||||
try {
|
||||
producer.transferData(monitor, consumer, processorInstance, producerSettings, null);
|
||||
} catch (DBException e) {
|
||||
throw new DBWebException("Import failed cause: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.11.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.12.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.fs</artifactId>
|
||||
<version>1.0.11-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.97.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.98.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.metadata</artifactId>
|
||||
<version>1.0.97-SNAPSHOT</version>
|
||||
<version>1.0.98-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.11.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.12.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.rm.nio</artifactId>
|
||||
<version>1.0.11-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 - Resource manager
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.rm;singleton:=true
|
||||
Bundle-Version: 1.0.46.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.47.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.rm</artifactId>
|
||||
<version>1.0.46-SNAPSHOT</version>
|
||||
<version>1.0.47-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: Cloudbeaver Web Service - Security
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.security;singleton:=true
|
||||
Bundle-Version: 1.0.49.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.50.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.security</artifactId>
|
||||
<version>1.0.49-SNAPSHOT</version>
|
||||
<version>1.0.50-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+45
-67
@@ -249,63 +249,20 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
}
|
||||
}
|
||||
|
||||
public void addAllUsersToDefaultTeam() throws DBCException {
|
||||
if (application.isConfigurationMode()) {
|
||||
return;
|
||||
}
|
||||
if (CommonUtils.isEmpty(application.getAppConfiguration().getDefaultUserTeam())) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (Connection dbCon = database.openConnection()) {
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("SELECT USER_ID \n" +
|
||||
"FROM {table_prefix}CB_USER\n" +
|
||||
"WHERE USER_ID NOT IN (\n" +
|
||||
" SELECT USER_ID FROM {table_prefix}CB_USER_TEAM CUT WHERE CUT.TEAM_ID = ? \n" +
|
||||
")")
|
||||
)) {
|
||||
dbStat.setString(1, application.getAppConfiguration().getDefaultUserTeam());
|
||||
ResultSet dbResult = dbStat.executeQuery();
|
||||
List<String> usersIds = new ArrayList<>();
|
||||
while (dbResult.next()) {
|
||||
String userId = dbResult.getString(1);
|
||||
usersIds.add(userId);
|
||||
}
|
||||
|
||||
if (usersIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String usersId : usersIds) {
|
||||
try (PreparedStatement insertStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("INSERT INTO {table_prefix}CB_USER_TEAM(USER_ID, TEAM_ID, GRANT_TIME, GRANTED_BY)" +
|
||||
" VALUES(?,?,?,?)"))) {
|
||||
insertStat.setString(1, usersId);
|
||||
insertStat.setString(2, application.getAppConfiguration().getDefaultUserTeam());
|
||||
insertStat.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
|
||||
insertStat.setString(4, "CloudBeaver Application");
|
||||
insertStat.executeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new DBCException("Error while setting default user teams", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SMTeam[] getUserTeams(String userId) throws DBException {
|
||||
Map<String, SMTeam> teams = new LinkedHashMap<>();
|
||||
try (Connection dbCon = database.openConnection()) {
|
||||
String defaultUserTeam = application.getAppConfiguration().getDefaultUserTeam();
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(database.normalizeTableNames(
|
||||
"SELECT R.*,S.IS_SECRET_STORAGE FROM {table_prefix}CB_USER_TEAM UR, {table_prefix}CB_TEAM R, " +
|
||||
"{table_prefix}CB_AUTH_SUBJECT S " +
|
||||
"WHERE UR.USER_ID=? AND UR.TEAM_ID=R.TEAM_ID AND S.SUBJECT_ID=R.TEAM_ID"))
|
||||
"WHERE UR.USER_ID=? AND UR.TEAM_ID = R.TEAM_ID " +
|
||||
"AND S.SUBJECT_ID IN (R.TEAM_ID,?)"))
|
||||
) {
|
||||
dbStat.setString(1, userId);
|
||||
dbStat.setString(2, defaultUserTeam);
|
||||
try (ResultSet dbResult = dbStat.executeQuery()) {
|
||||
while (dbResult.next()) {
|
||||
var team = fetchTeam(dbResult);
|
||||
@@ -364,14 +321,16 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
readSubjectMetas(dbCon, user);
|
||||
// Teams
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("SELECT TEAM_ID FROM {table_prefix}CB_USER_TEAM WHERE USER_ID=?"))
|
||||
database.normalizeTableNames("SELECT TEAM_ID FROM {table_prefix}CB_USER_TEAM WHERE USER_ID=?"))
|
||||
) {
|
||||
String defaultUserTeam = application.getAppConfiguration().getDefaultUserTeam();
|
||||
dbStat.setString(1, userId);
|
||||
try (ResultSet dbResult = dbStat.executeQuery()) {
|
||||
List<String> teamIDs = new ArrayList<>();
|
||||
Set<String> teamIDs = new LinkedHashSet<>();
|
||||
while (dbResult.next()) {
|
||||
teamIDs.add(dbResult.getString(1));
|
||||
}
|
||||
teamIDs.add(defaultUserTeam);
|
||||
user.setUserTeams(teamIDs.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
@@ -975,21 +934,27 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
@Override
|
||||
public SMTeam[] readAllTeams() throws DBCException {
|
||||
try (Connection dbCon = database.openConnection()) {
|
||||
String defaultUserTeam = application.getAppConfiguration().getDefaultUserTeam();
|
||||
Map<String, SMTeam> teams = new LinkedHashMap<>();
|
||||
try (Statement dbStat = dbCon.createStatement()) {
|
||||
try (ResultSet dbResult = dbStat.executeQuery(
|
||||
database.normalizeTableNames("SELECT T.*,S.IS_SECRET_STORAGE FROM {table_prefix}CB_TEAM T," +
|
||||
"{table_prefix}CB_AUTH_SUBJECT S " +
|
||||
"WHERE T.TEAM_ID=S.SUBJECT_ID ORDER BY TEAM_ID"))) {
|
||||
String query = database.normalizeTableNames(
|
||||
"SELECT T.*, S.IS_SECRET_STORAGE FROM {table_prefix}CB_TEAM T, " +
|
||||
"{table_prefix}CB_AUTH_SUBJECT S " +
|
||||
"WHERE T.TEAM_ID IN (S.SUBJECT_ID, ?) ORDER BY TEAM_ID");
|
||||
try (PreparedStatement dbPreparedStatement = dbCon.prepareStatement(query)) {
|
||||
dbPreparedStatement.setString(1, defaultUserTeam);
|
||||
try (ResultSet dbResult = dbPreparedStatement.executeQuery()) {
|
||||
while (dbResult.next()) {
|
||||
SMTeam team = fetchTeam(dbResult);
|
||||
teams.put(team.getTeamId(), team);
|
||||
}
|
||||
}
|
||||
try (ResultSet dbResult = dbStat.executeQuery(
|
||||
database.normalizeTableNames("SELECT SUBJECT_ID,PERMISSION_ID\n" +
|
||||
"FROM {table_prefix}CB_AUTH_PERMISSIONS AP, {table_prefix}CB_TEAM R\n" +
|
||||
"WHERE AP.SUBJECT_ID=R.TEAM_ID\n"))) {
|
||||
}
|
||||
query = database.normalizeTableNames("SELECT SUBJECT_ID,PERMISSION_ID\n" +
|
||||
"FROM {table_prefix}CB_AUTH_PERMISSIONS AP, {table_prefix}CB_TEAM R\n" +
|
||||
"WHERE AP.SUBJECT_ID IN (R.TEAM_ID,?)\n");
|
||||
try (PreparedStatement dbPreparedStatement = dbCon.prepareStatement(query)) {
|
||||
dbPreparedStatement.setString(1, defaultUserTeam);
|
||||
try (ResultSet dbResult = dbPreparedStatement.executeQuery()) {
|
||||
while (dbResult.next()) {
|
||||
SMTeam team = teams.get(dbResult.getString(1));
|
||||
if (team != null) {
|
||||
@@ -1016,16 +981,29 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
@Override
|
||||
public String[] getTeamMembers(String teamId) throws DBCException {
|
||||
try (Connection dbCon = database.openConnection()) {
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("SELECT USER_ID FROM {table_prefix}CB_USER_TEAM WHERE TEAM_ID=?"))) {
|
||||
dbStat.setString(1, teamId);
|
||||
List<String> subjects = new ArrayList<>();
|
||||
try (ResultSet dbResult = dbStat.executeQuery()) {
|
||||
while (dbResult.next()) {
|
||||
subjects.add(dbResult.getString(1));
|
||||
if (application.getAppConfiguration().getDefaultUserTeam().equals(teamId)) {
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("SELECT USER_ID FROM {table_prefix}CB_USER"))) {
|
||||
List<String> subjects = new ArrayList<>();
|
||||
try (ResultSet dbResult = dbStat.executeQuery()) {
|
||||
while (dbResult.next()) {
|
||||
subjects.add(dbResult.getString(1));
|
||||
}
|
||||
}
|
||||
return subjects.toArray(new String[0]);
|
||||
}
|
||||
} else {
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames("SELECT USER_ID FROM {table_prefix}CB_USER_TEAM WHERE TEAM_ID=?"))) {
|
||||
dbStat.setString(1, teamId);
|
||||
List<String> subjects = new ArrayList<>();
|
||||
try (ResultSet dbResult = dbStat.executeQuery()) {
|
||||
while (dbResult.next()) {
|
||||
subjects.add(dbResult.getString(1));
|
||||
}
|
||||
}
|
||||
return subjects.toArray(new String[0]);
|
||||
}
|
||||
return subjects.toArray(new String[0]);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new DBCException("Error while reading team members", e);
|
||||
@@ -1240,7 +1218,7 @@ public class CBEmbeddedSecurityController<T extends WebAuthApplication>
|
||||
try (PreparedStatement dbStat = dbCon.prepareStatement(
|
||||
database.normalizeTableNames(
|
||||
"SELECT DISTINCT AP.PERMISSION_ID FROM {table_prefix}CB_AUTH_PERMISSIONS AP, {table_prefix}CB_USER_TEAM UR\n" +
|
||||
"WHERE UR.TEAM_ID=AP.SUBJECT_ID AND UR.USER_ID=?"
|
||||
"WHERE UR.TEAM_ID = AP.SUBJECT_ID AND UR.USER_ID=?"
|
||||
)
|
||||
)) {
|
||||
dbStat.setString(1, userId);
|
||||
|
||||
+10
-29
@@ -16,18 +16,13 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.security;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import io.cloudbeaver.model.app.WebAuthApplication;
|
||||
import io.cloudbeaver.service.security.db.CBDatabase;
|
||||
import io.cloudbeaver.service.security.db.CBDatabaseConfig;
|
||||
import io.cloudbeaver.service.security.db.WebDatabaseConfig;
|
||||
import io.cloudbeaver.service.security.internal.ClearAuthAttemptInfoJob;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Embedded Security Controller Factory
|
||||
*/
|
||||
@@ -43,23 +38,19 @@ public class EmbeddedSecurityControllerFactory<T extends WebAuthApplication> {
|
||||
*/
|
||||
public CBEmbeddedSecurityController createSecurityService(
|
||||
T application,
|
||||
Map<String, Object> databaseConfig,
|
||||
WebDatabaseConfig databaseConfig,
|
||||
SMCredentialsProvider credentialsProvider,
|
||||
SMControllerConfiguration smConfig
|
||||
) throws DBException {
|
||||
boolean initDb = false;
|
||||
if (DB_INSTANCE == null) {
|
||||
synchronized (EmbeddedSecurityControllerFactory.class) {
|
||||
if (DB_INSTANCE == null) {
|
||||
initDatabase(application, databaseConfig);
|
||||
initDb = true;
|
||||
DB_INSTANCE = new CBDatabase(application, databaseConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
var securityController = createEmbeddedSecurityController(
|
||||
application, DB_INSTANCE, credentialsProvider, smConfig
|
||||
);
|
||||
if (initDb) {
|
||||
var securityController = createEmbeddedSecurityController(
|
||||
application, DB_INSTANCE, credentialsProvider, smConfig
|
||||
);
|
||||
//FIXME circular dependency
|
||||
DB_INSTANCE.setAdminSecurityController(securityController);
|
||||
DB_INSTANCE.initialize();
|
||||
@@ -67,21 +58,11 @@ public class EmbeddedSecurityControllerFactory<T extends WebAuthApplication> {
|
||||
// delete expired auth info job in enterprise products
|
||||
new ClearAuthAttemptInfoJob(securityController).schedule();
|
||||
}
|
||||
return securityController;
|
||||
}
|
||||
return securityController;
|
||||
}
|
||||
|
||||
private synchronized void initDatabase(WebAuthApplication application, Map<String, Object> databaseConfig) {
|
||||
CBDatabaseConfig databaseConfiguration = new CBDatabaseConfig();
|
||||
InstanceCreator<CBDatabaseConfig> dbConfigCreator = type -> databaseConfiguration;
|
||||
InstanceCreator<CBDatabaseConfig.Pool> dbPoolConfigCreator = type -> databaseConfiguration.getPool();
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(CBDatabaseConfig.class, dbConfigCreator)
|
||||
.registerTypeAdapter(CBDatabaseConfig.Pool.class, dbPoolConfigCreator)
|
||||
.create();
|
||||
gson.fromJson(gson.toJsonTree(databaseConfig), CBDatabaseConfig.class);
|
||||
|
||||
DB_INSTANCE = new CBDatabase(application, databaseConfiguration);
|
||||
return createEmbeddedSecurityController(
|
||||
application, DB_INSTANCE, credentialsProvider, smConfig
|
||||
);
|
||||
}
|
||||
|
||||
protected CBEmbeddedSecurityController createEmbeddedSecurityController(
|
||||
|
||||
+2
-2
@@ -82,7 +82,7 @@ public class CBDatabase {
|
||||
private static final String V2_DB_NAME = "cb.h2v2.dat";
|
||||
|
||||
private final WebApplication application;
|
||||
private final CBDatabaseConfig databaseConfiguration;
|
||||
private final WebDatabaseConfig databaseConfiguration;
|
||||
private PoolingDataSource<PoolableConnection> cbDataSource;
|
||||
private transient volatile Connection exclusiveConnection;
|
||||
|
||||
@@ -90,7 +90,7 @@ public class CBDatabase {
|
||||
private SMAdminController adminSecurityController;
|
||||
private SQLDialect dialect;
|
||||
|
||||
public CBDatabase(WebApplication application, CBDatabaseConfig databaseConfiguration) {
|
||||
public CBDatabase(WebApplication application, WebDatabaseConfig databaseConfiguration) {
|
||||
this.application = application;
|
||||
this.databaseConfiguration = databaseConfiguration;
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import org.jkiss.dbeaver.registry.storage.InternalDatabaseConfig;
|
||||
/**
|
||||
* Database configuration
|
||||
*/
|
||||
public class CBDatabaseConfig implements InternalDatabaseConfig {
|
||||
public class WebDatabaseConfig implements InternalDatabaseConfig {
|
||||
private String driver;
|
||||
private String url;
|
||||
private String user;
|
||||
+4
-4
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.security.internal.utils;
|
||||
|
||||
import io.cloudbeaver.service.security.db.CBDatabaseConfig;
|
||||
import io.cloudbeaver.service.security.db.WebDatabaseConfig;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
@@ -37,7 +37,7 @@ public class DBConfigurationUtils {
|
||||
static final String PARAM_DB_POOL_MAX_CONNECTIONS_CONFIGURATION = "maxConnections";
|
||||
static final String PARAM_DB_POOL_VALIDATION_QUERY_CONFIGURATION = "validationQuery";
|
||||
|
||||
public static Map<String, Object> databaseConfigToMap(@Nullable CBDatabaseConfig databaseConfiguration) {
|
||||
public static Map<String, Object> databaseConfigToMap(@Nullable WebDatabaseConfig databaseConfiguration) {
|
||||
Map<String, Object> res = new LinkedHashMap<>();
|
||||
if (databaseConfiguration == null) {
|
||||
return res;
|
||||
@@ -69,12 +69,12 @@ public class DBConfigurationUtils {
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Map<String, Object> poolDatabaseConfigToMap(@Nullable CBDatabaseConfig databaseConfiguration) {
|
||||
public static Map<String, Object> poolDatabaseConfigToMap(@Nullable WebDatabaseConfig databaseConfiguration) {
|
||||
Map<String, Object> res = new LinkedHashMap<>();
|
||||
if (databaseConfiguration == null) {
|
||||
return res;
|
||||
}
|
||||
CBDatabaseConfig.Pool pool = databaseConfiguration.getPool();
|
||||
WebDatabaseConfig.Pool pool = databaseConfiguration.getPool();
|
||||
if (pool == null) {
|
||||
return res;
|
||||
} else {
|
||||
|
||||
@@ -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.9.qualifier
|
||||
Bundle-Release-Date: 20240325
|
||||
Bundle-Version: 1.0.10.qualifier
|
||||
Bundle-Release-Date: 20240408
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-17
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-ClassPath: .
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.slf4j</artifactId>
|
||||
<version>1.0.9-SNAPSHOT</version>
|
||||
<version>1.0.10-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<dependency>
|
||||
<groupId>com.clickhouse</groupId>
|
||||
<artifactId>clickhouse-jdbc</artifactId>
|
||||
<version>0.5.0</version>
|
||||
<version>0.6.0-patch2</version>
|
||||
<classifier>all</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -14,12 +14,35 @@
|
||||
<deps.output.dir>h2_v2</deps.output.dir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>2.1.214</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-legacy-jar</id>
|
||||
<phase>validate</phase>
|
||||
<configuration>
|
||||
<outputDirectory>../../../deploy/drivers/h2_v2</outputDirectory>
|
||||
<overwrite>true</overwrite>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>lib</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>drivers.kyuubi</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<parent>
|
||||
<groupId>io.cloudbeaver</groupId>
|
||||
<artifactId>drivers</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<deps.output.dir>kyuubi</deps.output.dir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.kyuubi</groupId>
|
||||
<artifactId>kyuubi-hive-jdbc-shaded</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -18,6 +18,7 @@
|
||||
<module>h2</module>
|
||||
<module>h2_v2</module>
|
||||
<module>jaybird</module>
|
||||
<module>kyuubi</module>
|
||||
<module>mysql</module>
|
||||
<module>mariadb</module>
|
||||
<module>oracle</module>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<dependency>
|
||||
<groupId>io.trino</groupId>
|
||||
<artifactId>trino-jdbc</artifactId>
|
||||
<version>422</version>
|
||||
<version>438</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<feature
|
||||
id="io.cloudbeaver.ce.drivers.feature"
|
||||
label="Cloudbeaver CE 3rd Party Drivers"
|
||||
version="1.0.117.qualifier"
|
||||
version="1.0.118.qualifier"
|
||||
provider-name="DBeaver Corp">
|
||||
|
||||
<plugin id="io.cloudbeaver.resources.drivers.base" download-size="0" install-size="0" version="0.0.0"/>
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.ce.drivers.feature</artifactId>
|
||||
<version>1.0.117-SNAPSHOT</version>
|
||||
<version>1.0.118-SNAPSHOT</version>
|
||||
<packaging>eclipse-feature</packaging>
|
||||
</project>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<feature
|
||||
id="io.cloudbeaver.product.ce.feature"
|
||||
label="%featureName"
|
||||
version="24.0.1.qualifier"
|
||||
version="24.0.2.qualifier"
|
||||
provider-name="%providerName"
|
||||
plugin="io.cloudbeaver.product.ce">
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.product.ce.feature</artifactId>
|
||||
<version>24.0.1-SNAPSHOT</version>
|
||||
<version>24.0.2-SNAPSHOT</version>
|
||||
<packaging>eclipse-feature</packaging>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<feature
|
||||
id="io.cloudbeaver.server.feature"
|
||||
label="%featureName"
|
||||
version="24.0.1.qualifier"
|
||||
version="24.0.2.qualifier"
|
||||
provider-name="%providerName"
|
||||
plugin="io.cloudbeaver.server">
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.server.feature</artifactId>
|
||||
<version>24.0.1-SNAPSHOT</version>
|
||||
<version>24.0.2-SNAPSHOT</version>
|
||||
<packaging>eclipse-feature</packaging>
|
||||
</project>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<feature
|
||||
id="io.cloudbeaver.ws.feature"
|
||||
label="%featureName"
|
||||
version="1.0.47.qualifier"
|
||||
version="1.0.48.qualifier"
|
||||
provider-name="%providerName"
|
||||
plugin="io.cloudbeaver.model">
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user