mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-16 14:50:15 +08:00
Compare commits
63
Commits
25.3.4
...
release_26_0_0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13658510a9 | ||
|
|
05b04fc5b2 | ||
|
|
a1f0e1e542 | ||
|
|
d00009ca64 | ||
|
|
2e3ae65e82 | ||
|
|
deee3d7a7b | ||
|
|
1c79a0bb74 | ||
|
|
15dde2ece4 | ||
|
|
8a3f6455ec | ||
|
|
801139e3ff | ||
|
|
457909dd82 | ||
|
|
9f7e086369 | ||
|
|
6e8a09a49e | ||
|
|
8d11f94ad6 | ||
|
|
3b0cd66232 | ||
|
|
a60b7d4496 | ||
|
|
07a3a069fb | ||
|
|
4511208cad | ||
|
|
1ab8d15b00 | ||
|
|
ae331effde | ||
|
|
6c88030106 | ||
|
|
5e53341ba1 | ||
|
|
9338539564 | ||
|
|
af1aa83d8b | ||
|
|
32671ff239 | ||
|
|
f7c33a7f7e | ||
|
|
d70e4976e5 | ||
|
|
a0e6154a08 | ||
|
|
1b6e729506 | ||
|
|
3adb898f5a | ||
|
|
c886ee7bcd | ||
|
|
a5a9700ab9 | ||
|
|
2c38e75a99 | ||
|
|
12bc5ba5dc | ||
|
|
2719f53655 | ||
|
|
a2d336166b | ||
|
|
06da0705d2 | ||
|
|
058a341815 | ||
|
|
f5b0aae8bd | ||
|
|
789760aa9e | ||
|
|
fe77133226 | ||
|
|
8e237d1bbc | ||
|
|
0f3b8033df | ||
|
|
586d4154ab | ||
|
|
e0fe55c3bf | ||
|
|
9c406a4e1e | ||
|
|
05bf79e59c | ||
|
|
d013ece4f6 | ||
|
|
b0205e34c7 | ||
|
|
0b41ae89e8 | ||
|
|
b318c262b9 | ||
|
|
547831d060 | ||
|
|
93af9a8719 | ||
|
|
19125fed5e | ||
|
|
ea5fb47a56 | ||
|
|
89b4d1f970 | ||
|
|
0bd89236d2 | ||
|
|
abe0f6fb7d | ||
|
|
0b2b851772 | ||
|
|
dcb8e536b8 | ||
|
|
7881551821 | ||
|
|
cdc94dce5f | ||
|
|
70b67ce6f4 |
@@ -25,6 +25,36 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
|
||||
|
||||
## Changelog
|
||||
|
||||
### 25.3.5 2026-02-16
|
||||
|
||||
- Data Editor:
|
||||
- Added the ability to automatically generate INSERT, SELECT, DELETE, and UPDATE statements for the selected values in the Data Editor;
|
||||
- Added a status indicator icon in the top-left corner of the Data Editor with tooltips explaining table editability. The icon shows whether the table has a primary key, is read-only due to connection settings, or contains only read-only columns.
|
||||
- Navigator:
|
||||
- The Connection Info tab was added so that all users can see basic information about the current connection;
|
||||
- Added the ability to duplicate connection configuration in the project navigation tree. The "Clone connection" feature is available in the context menu.
|
||||
- General:
|
||||
- The missing pg_dump utility no longer causes errors during initialization or during deployment updates when PostgreSQL is selected as the inner database;
|
||||
- DuckDB: Driver version was updated to 1.4.4.0;
|
||||
- PostgreSQL: Added DDL display support for PostgreSQL policies.
|
||||
|
||||
### 25.3.4 2026-02-02
|
||||
|
||||
- Editors:
|
||||
- Added undo and redo functionality to the Data Editor for cell edits, row operations, and other data modifications. The history retains the last 50 actions across the Data Editor, result sets, and related panels;
|
||||
- The SQL preview panel has been added to the Bind parameters/variables dialog in the SQL Editor, allowing users to review the SQL query with changed values on the fly;
|
||||
- The Tab key can now be used for autocompletion in the SQL editor in the same way as the Enter key;
|
||||
- Fixed an application freeze caused by fetch size canceling for large tables in the Result Set;
|
||||
- Fixed an issue where pressing the Delete key during inline cell editing incorrectly marked the entire row for deletion.
|
||||
- Navigator:
|
||||
- Added independent view preference settings for database connections at both the user and connection levels. Users can configure their preferred navigator view separately from connection-specific settings;
|
||||
- Added "Show children of tables" option to Navigator tree settings. When enabled, the navigator displays nested objects such as columns under tables and views. The setting applies globally across all connections and remains disabled by default;
|
||||
- Added the ability to rename connections via context menu in the Navigator Tree;
|
||||
- General:
|
||||
- Expanded pointer target areas for icons in the navigator, editors, and tabs to a minimum of pixels per accessibility standards. Improved interaction accuracy and reduced errors for users with motor control limitations;
|
||||
- The "Database Native" authentication type has been renamed to "Username/password" for all connectors;
|
||||
- ClickHouse: Fixed an issue with displaying arrays of UUID, IPv4/IPv6, and Map types.
|
||||
|
||||
### 25.3.3 2026-01-19
|
||||
|
||||
- For security reasons, session expiration leads to a complete logout for a user and clears all data from the screen;
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Model
|
||||
Bundle-SymbolicName: io.cloudbeaver.model.cli;singleton:=true
|
||||
Bundle-Version: 1.0.3.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.5.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.model.cli;visibility:=reexport
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.model.cli</artifactId>
|
||||
<version>1.0.3-SNAPSHOT</version>
|
||||
<version>1.0.5-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -45,7 +45,7 @@ public class CloudBeaverCommandLine extends ApplicationCommandLine<ApplicationIn
|
||||
@Override
|
||||
protected CloudBeaverTopLevelCommand createTopLevelCommand(
|
||||
@Nullable ApplicationInstanceController applicationInstanceController,
|
||||
@NotNull CommandLineContext context,
|
||||
@NotNull CLIContextImpl context,
|
||||
@NotNull CLIRunMeta runMeta
|
||||
) {
|
||||
if (authenticator != null) {
|
||||
@@ -58,7 +58,7 @@ public class CloudBeaverCommandLine extends ApplicationCommandLine<ApplicationIn
|
||||
@Override
|
||||
protected CommandLine initCommandLine(
|
||||
@Nullable ApplicationInstanceController applicationInstanceController,
|
||||
@NotNull CommandLineContext context,
|
||||
@NotNull CLIContextImpl context,
|
||||
@NotNull CLIRunMeta runMeta
|
||||
) {
|
||||
var cmd = super.initCommandLine(applicationInstanceController, context, runMeta);
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,8 +19,8 @@ package io.cloudbeaver.model.cli;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.cli.ApplicationInstanceController;
|
||||
import org.jkiss.dbeaver.model.cli.CLIContextImpl;
|
||||
import org.jkiss.dbeaver.model.cli.CLIRunMeta;
|
||||
import org.jkiss.dbeaver.model.cli.CommandLineContext;
|
||||
import org.jkiss.dbeaver.model.cli.command.AbstractTopLevelCommand;
|
||||
import picocli.CommandLine;
|
||||
|
||||
@@ -35,7 +35,7 @@ public class CloudBeaverTopLevelCommand extends AbstractTopLevelCommand {
|
||||
|
||||
protected CloudBeaverTopLevelCommand(
|
||||
@Nullable ApplicationInstanceController controller,
|
||||
@NotNull CommandLineContext context,
|
||||
@NotNull CLIContextImpl context,
|
||||
@NotNull CLIRunMeta meta
|
||||
|
||||
) {
|
||||
|
||||
@@ -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.94.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.96.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.model</artifactId>
|
||||
<version>1.0.94-SNAPSHOT</version>
|
||||
<version>1.0.96-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -146,6 +146,8 @@ public class DBWebException extends DBException implements GraphQLError {
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
} else if (cause.getMessage() == null && cause.getCause() != null) {
|
||||
return message + ":\n" + cause.getCause().getClass().getSimpleName();
|
||||
}
|
||||
if (CommonUtils.isEmpty(message)) {
|
||||
if (cause.getMessage() != null) {
|
||||
|
||||
@@ -218,6 +218,7 @@ public class WebSessionProjectImpl extends WebProjectImpl implements DBPAdaptabl
|
||||
*
|
||||
* @return connections from cache.
|
||||
*/
|
||||
@NotNull
|
||||
public List<WebConnectionInfo> getConnections() {
|
||||
if (!registryIsLoaded) {
|
||||
addDataSourcesToCache();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -20,6 +20,7 @@ import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.model.app.BaseWebAppConfiguration;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import io.cloudbeaver.service.security.SMUtils;
|
||||
import io.cloudbeaver.service.sql.WebDataFormat;
|
||||
import io.cloudbeaver.utils.CBModelConstants;
|
||||
@@ -59,7 +60,6 @@ import java.util.stream.Collectors;
|
||||
public class WebConnectionInfo {
|
||||
|
||||
private static final Log log = Log.getLog(WebConnectionInfo.class);
|
||||
public static final String SECURED_VALUE = "********";
|
||||
|
||||
private static final String FEATURE_HAS_TOOLS = "hasTools";
|
||||
private static final String FEATURE_CONNECTED = "connected";
|
||||
@@ -127,7 +127,7 @@ public class WebConnectionInfo {
|
||||
if (canViewReadOnlyConnections()) {
|
||||
return dataSourceContainer.getConnectionConfiguration().getHostName();
|
||||
}
|
||||
return SECURED_VALUE;
|
||||
return CBConstants.SECURED_VALUE;
|
||||
}
|
||||
|
||||
@Property
|
||||
@@ -135,7 +135,7 @@ public class WebConnectionInfo {
|
||||
if (canViewReadOnlyConnections()) {
|
||||
return dataSourceContainer.getConnectionConfiguration().getHostPort();
|
||||
}
|
||||
return SECURED_VALUE;
|
||||
return CBConstants.SECURED_VALUE;
|
||||
}
|
||||
|
||||
@Property
|
||||
@@ -148,7 +148,7 @@ public class WebConnectionInfo {
|
||||
if (canViewReadOnlyConnections()) {
|
||||
return dataSourceContainer.getConnectionConfiguration().getDatabaseName();
|
||||
}
|
||||
return SECURED_VALUE;
|
||||
return CBConstants.SECURED_VALUE;
|
||||
}
|
||||
|
||||
@Property
|
||||
@@ -156,7 +156,7 @@ public class WebConnectionInfo {
|
||||
if (canViewReadOnlyConnections()) {
|
||||
return dataSourceContainer.getConnectionConfiguration().getUrl();
|
||||
}
|
||||
return SECURED_VALUE;
|
||||
return CBConstants.SECURED_VALUE;
|
||||
}
|
||||
|
||||
@Property
|
||||
|
||||
+5
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.model;
|
||||
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
|
||||
import org.jkiss.dbeaver.model.net.DBWHandlerType;
|
||||
@@ -88,7 +89,9 @@ public class WebNetworkHandlerConfig {
|
||||
DBPPropertyDescriptor[] descriptor = configuration.getHandlerDescriptor().getHandlerProperties();
|
||||
for (DBPPropertyDescriptor p : descriptor) {
|
||||
if (p.hasFeature(RegistryConstants.ATTR_PASSWORD)) {
|
||||
secureProperties.computeIfPresent(p.getId(), (k, v) -> CommonUtils.isEmpty(v) ? null : WebConnectionInfo.SECURED_VALUE);
|
||||
secureProperties.computeIfPresent(p.getId(), (k, v) ->
|
||||
CommonUtils.isEmpty(v) ? null : CBConstants.SECURED_VALUE
|
||||
);
|
||||
}
|
||||
}
|
||||
return secureProperties;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -17,11 +17,13 @@
|
||||
package io.cloudbeaver.model;
|
||||
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
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;
|
||||
import org.jkiss.dbeaver.model.impl.PropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.impl.ProviderPropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.meta.IPropertyValueListProvider;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
@@ -30,6 +32,7 @@ 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.ArrayUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
@@ -136,13 +139,14 @@ public class WebPropertyInfo {
|
||||
@Property
|
||||
public Object getValue() throws DBException {
|
||||
Object value = propertySource == null ? null : propertySource.getPropertyValue(session.getProgressMonitor(), property.getId());
|
||||
if (property instanceof ObjectPropertyDescriptor) {
|
||||
ObjectPropertyDescriptor opd = (ObjectPropertyDescriptor) property;
|
||||
if (!showProtected && opd.isPassword() || opd.isHidden()) {
|
||||
if (value == null || value.toString().isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return "******";
|
||||
if (property instanceof ObjectPropertyDescriptor opd &&
|
||||
(!showProtected && opd.isPassword() || opd.isHidden())
|
||||
) {
|
||||
return maskValue(value);
|
||||
} else if (property instanceof PropertyDescriptor pd) {
|
||||
String[] features = pd.getFeatures();
|
||||
if (features != null && ArrayUtils.contains(features, DBConstants.PROP_FEATURE_PASSWORD)) {
|
||||
return maskValue(value);
|
||||
}
|
||||
}
|
||||
return value == null ? null : makePropertyValue(value);
|
||||
@@ -307,4 +311,13 @@ public class WebPropertyInfo {
|
||||
READ_ONLY
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String maskValue(@Nullable Object value) {
|
||||
if (value == null || value.toString().isEmpty()) {
|
||||
return "";
|
||||
} else {
|
||||
return CBConstants.SECURED_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-3
@@ -80,9 +80,6 @@ public interface ServletApplication extends DBPApplication {
|
||||
@NotNull
|
||||
DBFileController createFileController(@NotNull SMCredentialsProvider credentialsProvider);
|
||||
|
||||
@Nullable
|
||||
String getServerURL();
|
||||
|
||||
@NotNull
|
||||
default String getServicesURI() {
|
||||
return "/";
|
||||
|
||||
+6
-5
@@ -31,8 +31,6 @@ import org.jkiss.dbeaver.model.rm.RMProject;
|
||||
import org.jkiss.dbeaver.model.rm.RMResource;
|
||||
import org.jkiss.dbeaver.model.rm.RMResourceType;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
import org.jkiss.dbeaver.registry.ResourceTypeDescriptor;
|
||||
import org.jkiss.dbeaver.registry.ResourceTypeRegistry;
|
||||
import org.jkiss.utils.ArrayUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
import org.jkiss.utils.IOUtils;
|
||||
@@ -44,7 +42,7 @@ public class DBNResourceManagerResource extends DBNAbstractResourceManagerNode {
|
||||
|
||||
private final RMResource resource;
|
||||
|
||||
DBNResourceManagerResource(DBNNode parentNode, RMResource resource) {
|
||||
DBNResourceManagerResource(@NotNull DBNNode parentNode, @NotNull RMResource resource) {
|
||||
super(parentNode);
|
||||
this.resource = resource;
|
||||
}
|
||||
@@ -71,6 +69,7 @@ public class DBNResourceManagerResource extends DBNAbstractResourceManagerNode {
|
||||
@Override
|
||||
public DBPImage getNodeIcon() {
|
||||
if (resource.isFolder()) {
|
||||
/*
|
||||
if (getParentNode() instanceof DBNResourceManagerResource) {
|
||||
return DBIcon.TREE_FOLDER;
|
||||
}
|
||||
@@ -82,11 +81,12 @@ public class DBNResourceManagerResource extends DBNAbstractResourceManagerNode {
|
||||
if (folderResType != null) {
|
||||
return folderResType.getFolderIcon();
|
||||
}
|
||||
*/
|
||||
return DBIcon.TREE_FOLDER;
|
||||
} else {
|
||||
var fileExtension = IOUtils.getFileExtension(getNodeDisplayName());
|
||||
if (!CommonUtils.isEmpty(fileExtension)) {
|
||||
RMProject project = getProjectNode();
|
||||
RMProject project = getRmProject();
|
||||
if (project != null) {
|
||||
for (RMResourceType rt : project.getResourceTypes()) {
|
||||
if (ArrayUtils.contains(rt.getFileExtensions(), fileExtension)) {
|
||||
@@ -99,7 +99,8 @@ public class DBNResourceManagerResource extends DBNAbstractResourceManagerNode {
|
||||
}
|
||||
}
|
||||
|
||||
private RMProject getProjectNode() {
|
||||
@Nullable
|
||||
public RMProject getRmProject() {
|
||||
for (DBNNode node = this; node != null; node = node.getParentNode()) {
|
||||
if (node instanceof DBNResourceManagerProject) {
|
||||
return ((DBNResourceManagerProject) node).getProject();
|
||||
|
||||
+9
-10
@@ -21,7 +21,6 @@ import io.cloudbeaver.model.app.ServletApplication;
|
||||
import io.cloudbeaver.model.app.ServletAuthApplication;
|
||||
import io.cloudbeaver.websocket.CBWebSessionEventHandler;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.auth.SMAuthInfo;
|
||||
@@ -103,7 +102,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void addSessionError(Throwable exception);
|
||||
public abstract void addSessionError(@NotNull Throwable exception);
|
||||
|
||||
public void addEventHandler(@NotNull CBWebSessionEventHandler handler) {
|
||||
synchronized (sessionEventHandlers) {
|
||||
@@ -117,11 +116,11 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean updateSMSession(SMAuthInfo smAuthInfo) throws DBException {
|
||||
public boolean updateSMSession(SMAuthInfo smAuthInfo) throws DBException {
|
||||
return userContext.refresh(smAuthInfo);
|
||||
}
|
||||
|
||||
public synchronized void refreshUserData() {
|
||||
public void refreshUserData() {
|
||||
try {
|
||||
userContext.refreshPermissions();
|
||||
if (userContext.isAuthorizedInSecurityManager()) {
|
||||
@@ -151,7 +150,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
return workspace.getAuthContext();
|
||||
}
|
||||
|
||||
protected void clearSessionContext() {
|
||||
protected synchronized void clearSessionContext() {
|
||||
this.workspace.getAuthContext().clear();
|
||||
this.workspace.getAuthContext().addSession(this);
|
||||
}
|
||||
@@ -177,12 +176,12 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
return lastAccessTime;
|
||||
}
|
||||
|
||||
public synchronized void touchSession() {
|
||||
public void touchSession() {
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public synchronized WebUserContext getUserContext() {
|
||||
public WebUserContext getUserContext() {
|
||||
return userContext;
|
||||
}
|
||||
|
||||
@@ -227,7 +226,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
this.eventsFilter = eventsFilter;
|
||||
}
|
||||
|
||||
public boolean isProjectAccessible(String projectId) {
|
||||
public boolean isProjectAccessible(@NotNull String projectId) {
|
||||
return userContext.getAccessibleProjectIds().contains(projectId);
|
||||
}
|
||||
|
||||
@@ -240,11 +239,11 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
}
|
||||
|
||||
|
||||
public void removeSessionProject(@Nullable String projectId) throws DBException {
|
||||
public void removeSessionProject(@NotNull String projectId) throws DBException {
|
||||
userContext.getAccessibleProjectIds().remove(projectId);
|
||||
}
|
||||
|
||||
public abstract void addSessionMessage(WebServerMessage message);
|
||||
public abstract void addSessionMessage(@NotNull WebServerMessage message);
|
||||
|
||||
@Property
|
||||
public boolean isValid() {
|
||||
|
||||
+2
-2
@@ -35,12 +35,12 @@ public class WebHeadlessSession extends BaseWebSession {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSessionError(Throwable exception) {
|
||||
public void addSessionError(@NotNull Throwable exception) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSessionMessage(WebServerMessage message) {
|
||||
public void addSessionMessage(@NotNull WebServerMessage message) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
+54
-99
@@ -57,8 +57,6 @@ import org.jkiss.dbeaver.model.websocket.event.MessageType;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSSessionLogUpdatedEvent;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
import org.jkiss.utils.function.ThrowableConsumer;
|
||||
import org.jkiss.utils.function.ThrowableFunction;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Path;
|
||||
@@ -96,7 +94,6 @@ public class WebSession extends BaseWebSession
|
||||
private final List<WebServerMessage> sessionMessages = new ArrayList<>();
|
||||
|
||||
private final Map<String, WebAsyncTaskInfo> asyncTasks = new HashMap<>();
|
||||
private final Map<String, ThrowableConsumer<Object, Exception>> attributeDisposers = new HashMap<>();
|
||||
|
||||
// Map of auth tokens. Key is authentication provider
|
||||
private final List<WebAuthInfo> authTokens = new ArrayList<>();
|
||||
@@ -188,11 +185,12 @@ public class WebSession extends BaseWebSession
|
||||
this.cacheExpired = cacheExpired;
|
||||
}
|
||||
|
||||
public synchronized WebUser getUser() {
|
||||
public WebUser getUser() {
|
||||
return this.userContext.getUser();
|
||||
}
|
||||
|
||||
public synchronized Map<String, String> getUserMetaParameters() {
|
||||
@NotNull
|
||||
public Map<String, String> getUserMetaParameters() {
|
||||
var user = getUser();
|
||||
if (user == null) {
|
||||
return Map.of();
|
||||
@@ -204,20 +202,20 @@ public class WebSession extends BaseWebSession
|
||||
return allMetaParams;
|
||||
}
|
||||
|
||||
public synchronized String getUserId() {
|
||||
public String getUserId() {
|
||||
return userContext.getUserId();
|
||||
}
|
||||
|
||||
public synchronized boolean hasPermission(String perm) {
|
||||
return getSessionPermissions().contains(DBWConstants.PERMISSION_ADMIN) ||
|
||||
getSessionPermissions().contains(perm);
|
||||
Set<String> sessionPermissions = getSessionPermissions();
|
||||
return sessionPermissions.contains(DBWConstants.PERMISSION_ADMIN) || sessionPermissions.contains(perm);
|
||||
}
|
||||
|
||||
public synchronized boolean isAuthorizedInSecurityManager() {
|
||||
public boolean isAuthorizedInSecurityManager() {
|
||||
return userContext.isAuthorizedInSecurityManager();
|
||||
}
|
||||
|
||||
public synchronized Set<String> getSessionPermissions() {
|
||||
public Set<String> getSessionPermissions() {
|
||||
if (userContext.getUserPermissions() == null) {
|
||||
refreshSessionAuth();
|
||||
}
|
||||
@@ -225,28 +223,30 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public synchronized SMController getSecurityController() {
|
||||
public SMController getSecurityController() {
|
||||
return userContext.getSecurityController();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public synchronized SMAdminController getAdminSecurityController() throws DBException {
|
||||
public SMAdminController getAdminSecurityController() throws DBException {
|
||||
if (!hasPermission(DBWConstants.PERMISSION_ADMIN)) {
|
||||
throw new DBException("Admin permissions required");
|
||||
}
|
||||
return userContext.getAdminSecurityController();
|
||||
}
|
||||
|
||||
public synchronized RMController getRmController() {
|
||||
@NotNull
|
||||
public RMController getRmController() {
|
||||
return userContext.getRmController();
|
||||
}
|
||||
|
||||
public synchronized DBFileController getFileController() {
|
||||
@NotNull
|
||||
public DBFileController getFileController() {
|
||||
return userContext.getFileController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void refreshUserData() {
|
||||
public void refreshUserData() {
|
||||
super.refreshUserData();
|
||||
refreshSessionAuth();
|
||||
|
||||
@@ -254,7 +254,7 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
|
||||
// Note: for admin use only
|
||||
public synchronized void resetUserState(boolean needResetUserCache) throws DBException {
|
||||
public void resetUserState(boolean needResetUserCache) throws DBException {
|
||||
clearAuthTokens();
|
||||
if (needResetUserCache) {
|
||||
try {
|
||||
@@ -268,7 +268,7 @@ public class WebSession extends BaseWebSession
|
||||
clearSessionContext();
|
||||
}
|
||||
|
||||
public synchronized void resetUserState() throws DBException {
|
||||
public void resetUserState() throws DBException {
|
||||
resetUserState(true);
|
||||
}
|
||||
|
||||
@@ -277,6 +277,11 @@ public class WebSession extends BaseWebSession
|
||||
return connectListener;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getClientOrigin() {
|
||||
return clientOrigin;
|
||||
}
|
||||
|
||||
public void updateClientOrigin(@NotNull String originFromRequest) {
|
||||
this.clientOrigin = originFromRequest;
|
||||
}
|
||||
@@ -327,7 +332,8 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
private WebSessionProjectImpl createWebProject(RMProject project) throws DBException {
|
||||
@NotNull
|
||||
private WebSessionProjectImpl createWebProject(@NotNull RMProject project) throws DBException {
|
||||
WebSessionProjectImpl sessionProject;
|
||||
if (project.isGlobal()) {
|
||||
sessionProject = createGlobalProject(project);
|
||||
@@ -345,6 +351,7 @@ public class WebSession extends BaseWebSession
|
||||
return sessionProject;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected WebSessionProjectImpl createSessionProject(@NotNull RMProject project) throws DBException {
|
||||
return new WebSessionProjectImpl(this, project, getProjectPath(project));
|
||||
}
|
||||
@@ -354,31 +361,13 @@ public class WebSession extends BaseWebSession
|
||||
return RMUtils.getProjectPath(project);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected WebSessionProjectImpl createGlobalProject(RMProject project) {
|
||||
globalProject = new WebSessionGlobalProjectImpl(this, project);
|
||||
globalProject.refreshAccessibleConnectionIds();
|
||||
return globalProject;
|
||||
}
|
||||
|
||||
private void resetSessionCache() throws DBCException {
|
||||
// Clear attributes
|
||||
synchronized (attributes) {
|
||||
for (Map.Entry<String, ThrowableConsumer<Object, Exception>> attrDisposer : attributeDisposers.entrySet()) {
|
||||
Object attrValue = attributes.get(attrDisposer.getKey());
|
||||
|
||||
try {
|
||||
attrDisposer.getValue().accept(attrValue);
|
||||
} catch (Exception e) {
|
||||
log.error("Error disposing attribute '" + attrDisposer.getKey() + "'", e);
|
||||
}
|
||||
}
|
||||
attributeDisposers.clear();
|
||||
// Remove all non-persistent attributes
|
||||
attributes.entrySet().removeIf(
|
||||
entry -> !(entry.getValue() instanceof PersistentAttribute));
|
||||
}
|
||||
}
|
||||
|
||||
private void resetNavigationModel() {
|
||||
getWorkspace().getProjects().forEach(WebSessionProjectImpl::dispose);
|
||||
|
||||
@@ -449,7 +438,7 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void updateInfo(boolean isOldHttpSessionUsed) {
|
||||
public void updateInfo(boolean isOldHttpSessionUsed) {
|
||||
log.trace("Update session lifetime " + getSessionId() + " for user " + getUserId());
|
||||
touchSession();
|
||||
if (isOldHttpSessionUsed) {
|
||||
@@ -513,6 +502,7 @@ public class WebSession extends BaseWebSession
|
||||
super.close(clearTokens, sendSessionExpiredEvent);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<WebAuthInfo> clearAuthTokens() throws DBException {
|
||||
ArrayList<WebAuthInfo> tokensCopy;
|
||||
synchronized (authTokens) {
|
||||
@@ -642,11 +632,11 @@ public class WebSession extends BaseWebSession
|
||||
return asyncTask;
|
||||
}
|
||||
|
||||
public void addSessionError(Throwable exception) {
|
||||
public void addSessionError(@NotNull Throwable exception) {
|
||||
addSessionMessage(new WebServerMessage(exception));
|
||||
}
|
||||
|
||||
public void addSessionMessage(WebServerMessage message) {
|
||||
public void addSessionMessage(@NotNull WebServerMessage message) {
|
||||
synchronized (sessionMessages) {
|
||||
sessionMessages.add(message);
|
||||
}
|
||||
@@ -657,14 +647,15 @@ public class WebSession extends BaseWebSession
|
||||
message.getMessage()));
|
||||
}
|
||||
|
||||
public void addInfoMessage(String message) {
|
||||
public void addInfoMessage(@NotNull String message) {
|
||||
addSessionMessage(new WebServerMessage(MessageType.INFO, message));
|
||||
}
|
||||
|
||||
public void addWarningMessage(String message) {
|
||||
public void addWarningMessage(@NotNull String message) {
|
||||
addSessionMessage(new WebServerMessage(MessageType.WARNING, message));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<WebServerMessage> readLog(Integer maxEntries, Boolean clearLog) {
|
||||
synchronized (sessionMessages) {
|
||||
List<WebServerMessage> messages = new ArrayList<>();
|
||||
@@ -684,46 +675,6 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getAttribute(String name) {
|
||||
synchronized (attributes) {
|
||||
Object value = attributes.get(name);
|
||||
if (value instanceof PersistentAttribute persistentAttribute) {
|
||||
value = persistentAttribute.value();
|
||||
}
|
||||
return (T) value;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAttribute(String name, Object value, boolean persistent) {
|
||||
synchronized (attributes) {
|
||||
attributes.put(name, persistent ? new PersistentAttribute(value) : value);
|
||||
}
|
||||
}
|
||||
|
||||
public <T, E extends Exception> T getAttribute(
|
||||
String name,
|
||||
ThrowableFunction<String, T, E> creator,
|
||||
ThrowableConsumer<T, E> disposer
|
||||
) throws E {
|
||||
synchronized (attributes) {
|
||||
Object value = attributes.get(name);
|
||||
if (value instanceof PersistentAttribute persistentAttribute) {
|
||||
value = persistentAttribute.value();
|
||||
}
|
||||
if (value == null) {
|
||||
value = creator.apply(null);
|
||||
if (value != null) {
|
||||
attributes.put(name, value);
|
||||
if (disposer != null) {
|
||||
attributeDisposers.put(name, (ThrowableConsumer<Object, Exception>) disposer);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (T) value;
|
||||
}
|
||||
}
|
||||
|
||||
@Property
|
||||
public Map<String, Object> getActionParameters() {
|
||||
WebActionParameters action = WebActionParameters.fromSession(this, true);
|
||||
@@ -752,7 +703,7 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
public List<WebAuthInfo> getAllAuthInfo() {
|
||||
synchronized (authTokens) {
|
||||
return new ArrayList<>(authTokens);
|
||||
@@ -804,7 +755,7 @@ public class WebSession extends BaseWebSession
|
||||
});
|
||||
}
|
||||
|
||||
private void removeAuthInfo(WebAuthInfo oldAuthInfo) {
|
||||
private void removeAuthInfo(@NotNull WebAuthInfo oldAuthInfo) {
|
||||
oldAuthInfo.closeAuth();
|
||||
synchronized (authTokens) {
|
||||
authTokens.remove(oldAuthInfo);
|
||||
@@ -830,6 +781,7 @@ public class WebSession extends BaseWebSession
|
||||
return oldInfo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<DBACredentialsProvider> getContextCredentialsProviders() {
|
||||
return getAdapters(DBACredentialsProvider.class);
|
||||
}
|
||||
@@ -917,11 +869,11 @@ public class WebSession extends BaseWebSession
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public synchronized void resetAuthToken() throws DBException {
|
||||
public void resetAuthToken() throws DBException {
|
||||
this.userContext.reset();
|
||||
}
|
||||
|
||||
public synchronized boolean updateSMSession(SMAuthInfo smAuthInfo) throws DBException {
|
||||
public boolean updateSMSession(SMAuthInfo smAuthInfo) throws DBException {
|
||||
boolean contextChanged = super.updateSMSession(smAuthInfo);
|
||||
if (contextChanged) {
|
||||
refreshUserData();
|
||||
@@ -940,7 +892,7 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WebSessionProjectImpl getProjectById(@Nullable String projectId) {
|
||||
public WebSessionProjectImpl getProjectById(@NotNull String projectId) {
|
||||
return getWorkspace().getProjectById(projectId);
|
||||
}
|
||||
|
||||
@@ -949,6 +901,7 @@ public class WebSession extends BaseWebSession
|
||||
*
|
||||
* @throws DBWebException if project with provided id is not found.
|
||||
*/
|
||||
@NotNull
|
||||
public WebSessionProjectImpl getAccessibleProjectById(@Nullable String projectId) throws DBWebException {
|
||||
WebSessionProjectImpl project = null;
|
||||
if (projectId != null) {
|
||||
@@ -960,6 +913,7 @@ public class WebSession extends BaseWebSession
|
||||
return project;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<WebSessionProjectImpl> getAccessibleProjects() {
|
||||
return getWorkspace().getProjects();
|
||||
}
|
||||
@@ -977,15 +931,14 @@ public class WebSession extends BaseWebSession
|
||||
/**
|
||||
* Removes project from session cache and navigator tree.
|
||||
*/
|
||||
public void deleteSessionProject(@Nullable WebSessionProjectImpl project) {
|
||||
if (project != null) {
|
||||
RMProject rmProject = project.getRMProject();
|
||||
log.info(String.format(
|
||||
"Project deleted: [ID=%s, Name=%s, Type=%s, Creator=%s]",
|
||||
rmProject.getId(), rmProject.getName(), rmProject.getType(), rmProject.getCreator()
|
||||
));
|
||||
project.dispose();
|
||||
}
|
||||
public void deleteSessionProject(@NotNull WebSessionProjectImpl project) {
|
||||
RMProject rmProject = project.getRMProject();
|
||||
log.info(String.format(
|
||||
"Project deleted: [ID=%s, Name=%s, Type=%s, Creator=%s]",
|
||||
rmProject.getId(), rmProject.getName(), rmProject.getType(), rmProject.getCreator()
|
||||
));
|
||||
project.dispose();
|
||||
|
||||
getWorkspace().removeProject(project);
|
||||
if (navigatorModel != null) {
|
||||
navigatorModel.getRoot().removeProject(project);
|
||||
@@ -996,6 +949,10 @@ public class WebSession extends BaseWebSession
|
||||
public void addSessionProject(@NotNull String projectId) throws DBException {
|
||||
super.addSessionProject(projectId);
|
||||
var rmProject = getRmController().getProject(projectId, false, false);
|
||||
if (rmProject == null) {
|
||||
log.error("RM project '" + projectId + "' not found");
|
||||
return;
|
||||
}
|
||||
createWebProject(rmProject);
|
||||
}
|
||||
|
||||
@@ -1010,7 +967,7 @@ public class WebSession extends BaseWebSession
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSessionProject(@Nullable String projectId) throws DBException {
|
||||
public void removeSessionProject(@NotNull String projectId) throws DBException {
|
||||
super.removeSessionProject(projectId);
|
||||
var project = getProjectById(projectId);
|
||||
if (project == null) {
|
||||
@@ -1081,6 +1038,4 @@ public class WebSession extends BaseWebSession
|
||||
return true;
|
||||
}
|
||||
|
||||
private record PersistentAttribute(Object value) {
|
||||
}
|
||||
}
|
||||
|
||||
+54
-22
@@ -19,9 +19,12 @@ package io.cloudbeaver.model.session;
|
||||
import io.cloudbeaver.WebSessionProjectImpl;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBPAdaptable;
|
||||
import org.jkiss.dbeaver.model.DBPImage;
|
||||
import org.jkiss.dbeaver.model.app.DBPPlatform;
|
||||
import org.jkiss.dbeaver.model.app.DBPProject;
|
||||
import org.jkiss.dbeaver.model.app.DBPWorkspace;
|
||||
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
|
||||
import org.jkiss.dbeaver.model.rm.RMUtils;
|
||||
@@ -36,6 +39,7 @@ import java.util.List;
|
||||
* Web workspace
|
||||
*/
|
||||
public class WebSessionWorkspace implements DBPWorkspace {
|
||||
private static final Log log = Log.getLog(WebSessionWorkspace.class);
|
||||
|
||||
private final BaseWebSession session;
|
||||
private final SessionContextImpl workspaceAuthContext;
|
||||
@@ -87,7 +91,9 @@ public class WebSessionWorkspace implements DBPWorkspace {
|
||||
@NotNull
|
||||
@Override
|
||||
public List<WebSessionProjectImpl> getProjects() {
|
||||
return accessibleProjects;
|
||||
synchronized (accessibleProjects) {
|
||||
return new ArrayList<>(accessibleProjects);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -99,26 +105,30 @@ public class WebSessionWorkspace implements DBPWorkspace {
|
||||
@Nullable
|
||||
@Override
|
||||
public WebSessionProjectImpl getProject(@NotNull String projectName) {
|
||||
for (WebSessionProjectImpl project : accessibleProjects) {
|
||||
if (project.getName().equals(projectName)) {
|
||||
return project;
|
||||
synchronized (accessibleProjects) {
|
||||
for (WebSessionProjectImpl project : accessibleProjects) {
|
||||
if (project.getName().equals(projectName)) {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
}
|
||||
log.error("Project name '" + projectName + "' not found in session workspace");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public WebSessionProjectImpl getProjectById(@Nullable String projectId) {
|
||||
if (projectId == null) {
|
||||
return activeProject;
|
||||
}
|
||||
for (WebSessionProjectImpl project : accessibleProjects) {
|
||||
if (project.getId().equals(projectId)) {
|
||||
return project;
|
||||
public WebSessionProjectImpl getProjectById(@NotNull String projectId) {
|
||||
synchronized (accessibleProjects) {
|
||||
for (WebSessionProjectImpl project : accessibleProjects) {
|
||||
if (project.getId().equals(projectId)) {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
log.error("Project ID '" + projectId + "' not found in session workspace");
|
||||
// FIXME: return null here
|
||||
return activeProject;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -143,25 +153,47 @@ public class WebSessionWorkspace implements DBPWorkspace {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setActiveProject(WebSessionProjectImpl activeProject) {
|
||||
@NotNull
|
||||
@Override
|
||||
public WebSessionProjectImpl createProject(@NotNull String name, @Nullable String description) throws DBException {
|
||||
throw new DBException("Project creation is not supported in web session workspace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteProject(@NotNull DBPProject project) throws DBException {
|
||||
throw new DBException("Project removing is not supported in web session workspace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renameProject(@NotNull DBPProject project, @NotNull String newName) throws DBException {
|
||||
throw new DBException("Project renaming is not supported in web session workspace");
|
||||
}
|
||||
|
||||
public void setActiveProject(@NotNull WebSessionProjectImpl activeProject) {
|
||||
this.activeProject = activeProject;
|
||||
}
|
||||
|
||||
void addProject(WebSessionProjectImpl project) {
|
||||
accessibleProjects.add(project);
|
||||
void addProject(@NotNull WebSessionProjectImpl project) {
|
||||
synchronized (accessibleProjects) {
|
||||
accessibleProjects.add(project);
|
||||
}
|
||||
}
|
||||
|
||||
void removeProject(WebSessionProjectImpl project) {
|
||||
accessibleProjects.remove(project);
|
||||
void removeProject(@NotNull WebSessionProjectImpl project) {
|
||||
synchronized (accessibleProjects) {
|
||||
accessibleProjects.remove(project);
|
||||
}
|
||||
}
|
||||
|
||||
void clearProjects() {
|
||||
if (!this.accessibleProjects.isEmpty()) {
|
||||
for (WebSessionProjectImpl project : accessibleProjects) {
|
||||
project.dispose();
|
||||
synchronized (accessibleProjects) {
|
||||
if (!this.accessibleProjects.isEmpty()) {
|
||||
for (WebSessionProjectImpl project : accessibleProjects) {
|
||||
project.dispose();
|
||||
}
|
||||
this.activeProject = null;
|
||||
this.accessibleProjects.clear();
|
||||
}
|
||||
this.activeProject = null;
|
||||
this.accessibleProjects.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+23
-16
@@ -53,9 +53,9 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
private final ServletApplication application;
|
||||
private final DBPWorkspace workspace;
|
||||
|
||||
private WebUser user;
|
||||
private Set<String> userPermissions;
|
||||
private SMCredentials smCredentials = null;
|
||||
private volatile WebUser user;
|
||||
private volatile Set<String> userPermissions;
|
||||
private volatile SMCredentials smCredentials = null;
|
||||
private String smSessionId;
|
||||
private String refreshToken;
|
||||
|
||||
@@ -87,7 +87,7 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
* @return - true if context changed
|
||||
* @throws DBException - if user already authorized and new token come from another user
|
||||
*/
|
||||
public synchronized boolean refresh(@NotNull SMAuthInfo smAuthInfo) throws DBException {
|
||||
public boolean refresh(@NotNull SMAuthInfo smAuthInfo) throws DBException {
|
||||
if (smAuthInfo.getAuthPermissions() == null && !isAuthorizedInSecurityManager()) {
|
||||
throw new DBCException("Required information about session permissions is missing");
|
||||
}
|
||||
@@ -175,53 +175,56 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public synchronized SMController getSecurityController() {
|
||||
public SMController getSecurityController() {
|
||||
return securityController;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized SMCredentials getActiveUserCredentials() {
|
||||
public SMCredentials getActiveUserCredentials() {
|
||||
return smCredentials;
|
||||
}
|
||||
|
||||
public synchronized boolean isAuthorizedInSecurityManager() {
|
||||
public boolean isAuthorizedInSecurityManager() {
|
||||
return smCredentials != null;
|
||||
}
|
||||
|
||||
public synchronized boolean isNonAnonymousUserAuthorizedInSM() {
|
||||
public boolean isNonAnonymousUserAuthorizedInSM() {
|
||||
return isAuthorizedInSecurityManager() && getUser() != null;
|
||||
}
|
||||
|
||||
public synchronized boolean isAnonymousUserAuthorizedInSM() {
|
||||
public boolean isAnonymousUserAuthorizedInSM() {
|
||||
return isAuthorizedInSecurityManager() && getUser() == null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public synchronized WebUser getUser() {
|
||||
public WebUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public synchronized String getUserId() {
|
||||
@Nullable
|
||||
public String getUserId() {
|
||||
return user == null ? null : user.getUserId();
|
||||
}
|
||||
|
||||
protected synchronized void setUser(@Nullable WebUser user) {
|
||||
protected void setUser(@Nullable WebUser user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public synchronized SMAdminController getAdminSecurityController() {
|
||||
@NotNull
|
||||
public SMAdminController getAdminSecurityController() {
|
||||
return adminSecurityController;
|
||||
}
|
||||
|
||||
public synchronized Set<String> getUserPermissions() {
|
||||
@Nullable
|
||||
public Set<String> getUserPermissions() {
|
||||
return userPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* reread the current user's permissions
|
||||
*/
|
||||
public synchronized void refreshPermissions() throws DBException {
|
||||
public void refreshPermissions() throws DBException {
|
||||
if (isAuthorizedInSecurityManager()) {
|
||||
log.debug("refresh permissions " + getUserId() + " " + getSmSessionId());
|
||||
setUserPermissions(securityController.getTokenPermissions().getPermissions());
|
||||
@@ -234,6 +237,7 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
this.userPermissions = permissions;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DBSSecretController getSecretController() throws DBException {
|
||||
if (this.securityController == null) {
|
||||
this.secretController = application.getSecretController(this, workspace.getAuthContext());
|
||||
@@ -241,7 +245,8 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
return secretController;
|
||||
}
|
||||
|
||||
public synchronized String getSmSessionId() {
|
||||
@NotNull
|
||||
public String getSmSessionId() {
|
||||
return smSessionId;
|
||||
}
|
||||
|
||||
@@ -255,6 +260,7 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
return rmController;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DBFileController getFileController() {
|
||||
return fileController;
|
||||
}
|
||||
@@ -268,6 +274,7 @@ public class WebUserContext implements SMCredentialsProvider {
|
||||
this.refreshToken = refreshToken;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WebSessionPreferenceStore getPreferenceStore() {
|
||||
return preferenceStore;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -37,7 +37,6 @@ public class CBConstants {
|
||||
public static final String PARAM_SUPPORTED_HOSTS = "supportedHosts";
|
||||
public static final String PARAM_SSL_CONFIGURATION_PATH = "sslConfigurationPath";
|
||||
public static final String PARAM_CONTENT_ROOT = "contentRoot";
|
||||
public static final String PARAM_SERVER_URL = "serverURL";
|
||||
public static final String PARAM_ROOT_URI = "rootURI";
|
||||
public static final String PARAM_SERVICES_URI = "serviceURI";
|
||||
public static final String PARAM_DRIVERS_LOCATION = "driversLocation";
|
||||
@@ -99,4 +98,6 @@ public class CBConstants {
|
||||
public static final String BIND_SESSION_ENABLE = "enable";
|
||||
public static final String BIND_SESSION_DISABLE = "disable";
|
||||
public static final String DEFAULT_CLOUD_PROJECT_NAME = "GlobalConfiguration";
|
||||
|
||||
public static final String SECURED_VALUE = "******";
|
||||
}
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver.service.sql;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
|
||||
public record WebSQLQueryParameterRecord(@NotNull String name, @Nullable String value) {
|
||||
}
|
||||
@@ -112,6 +112,16 @@ public class WebGQLClient {
|
||||
@NotNull String query,
|
||||
@Nullable Map<String, Object> variables,
|
||||
@NotNull Map<String, String> requestHeaders
|
||||
) throws Exception {
|
||||
return executeGQLRequest(query, variables, requestHeaders, "result");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, Object> executeGQLRequest(
|
||||
@NotNull String query,
|
||||
@Nullable Map<String, Object> variables,
|
||||
@NotNull Map<String, String> requestHeaders,
|
||||
@NotNull String resultName
|
||||
) throws Exception {
|
||||
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
|
||||
.uri(URI.create(apiUrl))
|
||||
@@ -132,7 +142,7 @@ public class WebGQLClient {
|
||||
throw new DBException(message);
|
||||
}
|
||||
Map<String, Object> parsed = new LinkedHashMap<>();
|
||||
parsed.put("data", JSONUtils.getObject(body, "data").get("result"));
|
||||
parsed.put("data", JSONUtils.getObject(body, "data").get(resultName));
|
||||
parsed.put("headers", response.headers().map());
|
||||
return parsed;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -47,6 +47,8 @@ public class ServletAppUtils {
|
||||
private static final String HEADER_REFERER = "Referer";
|
||||
|
||||
private static final String HEADER_FORWARDED_SCHEME = "X-Forwarded-Scheme";
|
||||
private static final String HEADER_FORWARDED_PROTO = "X-Forwarded-Proto";
|
||||
private static final String HEADER_FORWARDED_PORT = "X-Forwarded-Port";
|
||||
private static final String HEADER_FORWARDED_HOST = "X-Forwarded-Host";
|
||||
private static final Set<Integer> DEFAULT_PORTS = Set.of(
|
||||
80,
|
||||
@@ -294,19 +296,37 @@ public class ServletAppUtils {
|
||||
@NotNull
|
||||
public static String getOriginFromRequest(@NotNull HttpServletRequest request) {
|
||||
String origin = request.getHeader(HEADER_ORIGIN);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Origin header: " + origin);
|
||||
}
|
||||
if (CommonUtils.isEmpty(origin)) {
|
||||
origin = request.getHeader(HEADER_X_ORIGIN);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("X-Origin header: " + origin);
|
||||
}
|
||||
}
|
||||
if (CommonUtils.isEmpty(origin)) {
|
||||
origin = request.getHeader(HEADER_REFERER);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Referer header: " + origin);
|
||||
}
|
||||
}
|
||||
String forwardedScheme = request.getHeader(HEADER_FORWARDED_SCHEME);
|
||||
if (CommonUtils.isEmpty(forwardedScheme)) {
|
||||
forwardedScheme = request.getHeader(HEADER_FORWARDED_PROTO);
|
||||
}
|
||||
String forwardedHost = request.getHeader(HEADER_FORWARDED_HOST);
|
||||
if (CommonUtils.isNotEmpty(forwardedScheme) && CommonUtils.isNotEmpty(forwardedHost)) {
|
||||
origin = forwardedScheme + "://" + forwardedHost;
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("forwarded origin: " + origin);
|
||||
}
|
||||
}
|
||||
if (CommonUtils.isEmpty(origin)) {
|
||||
URI requestUrl = URI.create(request.getRequestURL().toString());
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Request URL: " + requestUrl);
|
||||
}
|
||||
origin = getRootUrlFromUri(requestUrl) + "/";
|
||||
}
|
||||
origin = removeSideSlashes(origin);
|
||||
@@ -318,7 +338,15 @@ public class ServletAppUtils {
|
||||
|
||||
origin = removeSideSlashes(origin);
|
||||
URI uri = URI.create(origin);
|
||||
if (DEFAULT_PORTS.contains(uri.getPort())) {
|
||||
int port = uri.getPort();
|
||||
if (CommonUtils.isNotEmpty(request.getHeader(HEADER_FORWARDED_PORT))) {
|
||||
try {
|
||||
port = Integer.parseInt(request.getHeader(HEADER_FORWARDED_PORT));
|
||||
} catch (NumberFormatException e) {
|
||||
log.error("Failed to parse port from header: " + request.getHeader(HEADER_FORWARDED_PORT), e);
|
||||
}
|
||||
}
|
||||
if (DEFAULT_PORTS.contains(port)) {
|
||||
try {
|
||||
origin = new URI(
|
||||
uri.getScheme(),
|
||||
@@ -333,6 +361,9 @@ public class ServletAppUtils {
|
||||
log.error("Failed to create URI without port", e);
|
||||
}
|
||||
}
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Origin URI: " + origin);
|
||||
}
|
||||
|
||||
return origin;
|
||||
}
|
||||
|
||||
+5
-4
@@ -16,23 +16,24 @@
|
||||
*/
|
||||
package io.cloudbeaver.websocket.event.task;
|
||||
|
||||
import io.cloudbeaver.service.sql.WebSQLQueryParameterRecord;
|
||||
import org.jkiss.code.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
public class WSSessionTaskQueryParamsConfirmationEvent extends WSAbstractSessionTaskEvent {
|
||||
private static final String ID = "cb_session_task_query_params_confirmation_request";
|
||||
@NotNull
|
||||
private final String query;
|
||||
@NotNull
|
||||
private final Map<String, Object> parameters;
|
||||
private final List<WebSQLQueryParameterRecord> parameters;
|
||||
|
||||
public WSSessionTaskQueryParamsConfirmationEvent(
|
||||
@NotNull String taskId,
|
||||
@NotNull String title,
|
||||
@NotNull String message,
|
||||
@NotNull String query,
|
||||
@NotNull Map<String, Object> parameters
|
||||
@NotNull List<WebSQLQueryParameterRecord> parameters
|
||||
) {
|
||||
super(ID, taskId, title, message);
|
||||
this.query = query;
|
||||
@@ -45,7 +46,7 @@ public class WSSessionTaskQueryParamsConfirmationEvent extends WSAbstractSession
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, Object> getParameters() {
|
||||
public List<WebSQLQueryParameterRecord> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Community Product
|
||||
Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true
|
||||
Bundle-Version: 25.3.4.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 26.0.0.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce
|
||||
|
||||
@@ -10,9 +10,8 @@
|
||||
</extension>
|
||||
|
||||
<extension point="org.eclipse.core.runtime.products" id="product">
|
||||
<product application="io.cloudbeaver.product.ce.application" description="CloudBeaver CE Web UI Application"
|
||||
name="CloudBeaver CE Server">
|
||||
<property name="appName" value="CloudBeaver CE Server"/>
|
||||
<product application="io.cloudbeaver.product.ce.application" name="CloudBeaver Community">
|
||||
<property name="appName" value="CloudBeaver Community"/>
|
||||
<property name="versionUpdateURL" value="https://dbeaver.com/product/cloudbeaver-ce-version.json"/>
|
||||
</product>
|
||||
</extension>
|
||||
@@ -21,8 +20,7 @@
|
||||
<application
|
||||
id="cloudbeaver-ce"
|
||||
family="CB"
|
||||
name="CloudBeaver CE Server"
|
||||
description="CloudBeaver CE Web UI"
|
||||
name="CloudBeaver Community"
|
||||
server="true"/>
|
||||
</extension>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.product.ce</artifactId>
|
||||
<version>25.3.4-SNAPSHOT</version>
|
||||
<version>26.0.0-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Cloudbeaver Base JDBC drivers
|
||||
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
|
||||
Bundle-Version: 1.0.139.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.141.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.resources.drivers.base</artifactId>
|
||||
<version>1.0.139-SNAPSHOT</version>
|
||||
<version>1.0.141-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver CE Server
|
||||
Bundle-Name: CloudBeaver Community
|
||||
Bundle-SymbolicName: io.cloudbeaver.server.ce;singleton:=true
|
||||
Bundle-Version: 25.3.4.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 26.0.0.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.server.ce</artifactId>
|
||||
<version>25.3.4-SNAPSHOT</version>
|
||||
<version>26.0.0-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ public class CBWebServerConfig extends WebServerConfig {
|
||||
|
||||
@Property
|
||||
public String getServerURL() {
|
||||
return CommonUtils.notEmpty(cbApp.getServerConfiguration().getServerURL());
|
||||
return ""; // backward compatibility
|
||||
}
|
||||
|
||||
@Property
|
||||
|
||||
-9
@@ -31,7 +31,6 @@ public class CBServerConfig implements WebServerConfiguration {
|
||||
|
||||
private static final Log log = Log.getLog(CBServerConfig.class);
|
||||
|
||||
protected String serverURL;
|
||||
@NotNull
|
||||
protected List<String> supportedHosts = new ArrayList<>();
|
||||
protected boolean forceHttps;
|
||||
@@ -62,10 +61,6 @@ public class CBServerConfig implements WebServerConfiguration {
|
||||
this.securityManagerConfiguration = createSecurityManagerConfiguration();
|
||||
}
|
||||
|
||||
public String getServerURL() {
|
||||
return serverURL;
|
||||
}
|
||||
|
||||
public int getServerPort() {
|
||||
return serverPort;
|
||||
}
|
||||
@@ -108,10 +103,6 @@ public class CBServerConfig implements WebServerConfiguration {
|
||||
return staticContent;
|
||||
}
|
||||
|
||||
public void setServerURL(String serverURL) {
|
||||
this.serverURL = serverURL;
|
||||
}
|
||||
|
||||
public void setServerPort(int serverPort) {
|
||||
this.serverPort = serverPort;
|
||||
}
|
||||
|
||||
@@ -119,11 +119,6 @@ public abstract class CBApplication<T extends CBServerConfig>
|
||||
this.homeDirectory = new File(initHomeFolder());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getServerURL() {
|
||||
return getServerConfiguration().getServerURL();
|
||||
}
|
||||
|
||||
// Port this server listens on. If set the 0 a random port is assigned which may be obtained with getLocalPort()
|
||||
@Override
|
||||
public int getServerPort() {
|
||||
@@ -259,9 +254,6 @@ public abstract class CBApplication<T extends CBServerConfig>
|
||||
//log.debug("\tProduct details: " + application.getInfoDetails());
|
||||
log.debug("\tListen port: " + getServerPort() + (CommonUtils.isEmpty(getServerHost()) ? " on all interfaces" : " on " + getServerHost()));
|
||||
log.debug("\tBase URI: " + getServicesURI());
|
||||
if (!isConfigurationMode()) {
|
||||
log.debug("\tGlobal access server URL: " + getServerConfiguration().getServerURL());
|
||||
}
|
||||
if (isDevelMode()) {
|
||||
log.debug("\tDevelopment mode");
|
||||
} else {
|
||||
@@ -356,7 +348,6 @@ public abstract class CBApplication<T extends CBServerConfig>
|
||||
*/
|
||||
protected void performAutoConfiguration(Path configPath) {
|
||||
String autoServerName = System.getenv(CBConstants.VAR_AUTO_CB_SERVER_NAME);
|
||||
String autoServerURL = System.getenv(CBConstants.VAR_AUTO_CB_SERVER_URL);
|
||||
String autoAdminName = System.getenv(CBConstants.VAR_AUTO_CB_ADMIN_NAME);
|
||||
String autoAdminPassword = System.getenv(CBConstants.VAR_AUTO_CB_ADMIN_PASSWORD);
|
||||
|
||||
@@ -371,7 +362,6 @@ public abstract class CBApplication<T extends CBServerConfig>
|
||||
autoProps.load(is);
|
||||
|
||||
autoServerName = autoProps.getProperty(CBConstants.VAR_AUTO_CB_SERVER_NAME);
|
||||
autoServerURL = autoProps.getProperty(CBConstants.VAR_AUTO_CB_SERVER_URL);
|
||||
autoAdminName = autoProps.getProperty(CBConstants.VAR_AUTO_CB_ADMIN_NAME);
|
||||
autoAdminPassword = autoProps.getProperty(CBConstants.VAR_AUTO_CB_ADMIN_PASSWORD);
|
||||
} catch (IOException e) {
|
||||
@@ -389,7 +379,6 @@ public abstract class CBApplication<T extends CBServerConfig>
|
||||
}
|
||||
CBServerConfig serverConfig = new CBServerConfig();
|
||||
serverConfig.setServerName(autoServerName);
|
||||
serverConfig.setServerURL(autoServerURL);
|
||||
serverConfig.setMaxSessionIdleTime(getMaxSessionIdleTime());
|
||||
try {
|
||||
finishConfiguration(
|
||||
|
||||
@@ -104,4 +104,9 @@ public class CBApplicationCE extends CBApplication<CBServerConfig> {
|
||||
embeddedSecurityController.finishConfiguration(adminName, adminPassword, authInfoList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunity() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-16
@@ -56,6 +56,9 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
|
||||
private static final Log log = Log.getLog(CBServerConfigurationController.class);
|
||||
|
||||
private static final String NETWORK_MODE_ENV = "NETWORK_MODE";
|
||||
private static final String NETWORK_MODE_VALUE_HOST = "host";
|
||||
|
||||
// Configurations
|
||||
@NotNull
|
||||
private final T serverConfiguration;
|
||||
@@ -167,12 +170,9 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
|
||||
public T parseServerConfiguration() {
|
||||
var config = getServerConfiguration();
|
||||
if (config.getServerURL() == null) {
|
||||
String hostName = config.getServerHost();
|
||||
if (CommonUtils.isEmpty(hostName)) {
|
||||
hostName = getLocalHostAddress();
|
||||
}
|
||||
config.setServerURL("http://" + hostName + ":" + config.getServerPort());
|
||||
if (NETWORK_MODE_VALUE_HOST.equalsIgnoreCase(System.getenv(NETWORK_MODE_ENV))) {
|
||||
String hostName = getLocalHostAddress();
|
||||
config.setServerHost(hostName);
|
||||
}
|
||||
|
||||
config.setContentRoot(ServletAppUtils.getRelativePath(config.getContentRoot(), homeDirectory));
|
||||
@@ -383,12 +383,6 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized void updateServerUrl(@NotNull SMCredentialsProvider credentialsProvider,
|
||||
@Nullable String newPublicUrl) throws DBException {
|
||||
getServerConfiguration().setServerURL(newPublicUrl);
|
||||
}
|
||||
|
||||
protected Map<String, Object> collectConfigurationProperties(
|
||||
@NotNull CBServerConfig serverConfig,
|
||||
@NotNull CBAppConfig appConfig
|
||||
@@ -523,10 +517,6 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
CBConstants.PARAM_SERVER_NAME,
|
||||
serverConfig.getServerName());
|
||||
}
|
||||
if (!CommonUtils.isEmpty(serverConfig.getServerURL())) {
|
||||
copyConfigValue(
|
||||
originServerConfig, serverConfigProperties, CBConstants.PARAM_SERVER_URL, serverConfig.getServerURL());
|
||||
}
|
||||
if (serverConfig.getMaxSessionIdleTime() > 0) {
|
||||
copyConfigValue(
|
||||
originServerConfig,
|
||||
|
||||
+2
-2
@@ -32,8 +32,8 @@ import io.cloudbeaver.server.websockets.CBWebSocketServerConfigurator;
|
||||
import io.cloudbeaver.service.DBWServiceBindingServlet;
|
||||
import io.cloudbeaver.service.DBWServiceBindingWebSocket;
|
||||
import jakarta.websocket.server.ServerEndpointConfig;
|
||||
import org.eclipse.jetty.ee10.servlet.*;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.ee11.servlet.*;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.server.*;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
|
||||
-1
@@ -39,7 +39,6 @@ public class CBServerContextListener implements ServletContextListener {
|
||||
//scf.setDomain(domain);
|
||||
//scf.setMaxAge(CB_SESSION_LIFE_TIME);
|
||||
cookieConfig.setPath(CBApplication.getInstance().getRootURI());
|
||||
// cookieConfig.setSecure(application.getServerURL().startsWith("https"));
|
||||
cookieConfig.setHttpOnly(true);
|
||||
cookieConfig.setName(CBConstants.CB_SESSION_COOKIE_NAME);
|
||||
}
|
||||
|
||||
+14
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -33,6 +33,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class RequestHostFilter implements Filter {
|
||||
private static final Log log = Log.getLog(RequestHostFilter.class);
|
||||
|
||||
@@ -74,9 +75,19 @@ public class RequestHostFilter implements Filter {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
boolean isIpAddress = InetAddresses.isInetAddress(originUri.getHost());
|
||||
|
||||
if (CommonUtils.isNotEmpty(originUri.getHost())) {
|
||||
requestAllowed = InetAddresses.isInetAddress(originUri.getHost());
|
||||
} else {
|
||||
log.debug(
|
||||
"Request origin host is null, request URI - " + originUri +
|
||||
", request path - " + httpRequest.getServletPath() +
|
||||
", request url - " + httpRequest.getRequestURL()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
String servletPath = httpRequest.getServletPath();
|
||||
requestAllowed = isIpAddress;
|
||||
if (!requestAllowed) {
|
||||
if (CommonUtils.isNotEmpty(servletPath)) {
|
||||
for (String excludedPath : excludedPaths) {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.WebServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee10.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.ee11.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-Name: Cloudbeaver Web Server
|
||||
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
|
||||
Bundle-Version: 25.3.4.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 26.0.0.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.eclipse.core.runtime;visibility:=reexport,
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</extension>
|
||||
|
||||
<extension point="org.jkiss.dbeaver.ws.event.handler">
|
||||
<eventHandler class="io.cloudbeaver.server.events.WSDefaultEventHandler">
|
||||
<eventHandler class="io.cloudbeaver.server.events.WSServerConfigurationChangedEventHandler">
|
||||
<topic id="cb_config"/>
|
||||
</eventHandler>
|
||||
<eventHandler class="io.cloudbeaver.server.events.WSDataSourceUpdatedEventHandlerImpl">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.server</artifactId>
|
||||
<version>25.3.4-SNAPSHOT</version>
|
||||
<version>26.0.0-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -296,6 +296,13 @@ enum WSServerNotificationEventType {
|
||||
LOADING
|
||||
CUSTOM
|
||||
}
|
||||
|
||||
"Query parameter information"
|
||||
type WSQueryParameterInfo {
|
||||
name: String!
|
||||
value: String
|
||||
}
|
||||
|
||||
"General event for showing user notification"
|
||||
type WSServerNotificationEvent implements CBServerEvent @since(version: "25.2.1") {
|
||||
id: CBServerEventId!
|
||||
@@ -338,14 +345,14 @@ type WSSessionTaskConfirmationEvent implements CBClientEvent @since(version: "25
|
||||
skipConfirmations: Boolean!
|
||||
}
|
||||
|
||||
type WSSessionTaskQueryParamsConfirmationEvent implements CBServerEvent @since(version: "25.2.5") {
|
||||
type WSSessionTaskQueryParamsConfirmationEvent implements CBServerEvent @since(version: "26.0.0") {
|
||||
id: CBServerEventId!
|
||||
topicId: CBEventTopic!
|
||||
taskId: ID!
|
||||
title: String!
|
||||
message: String!
|
||||
query: String!
|
||||
parameters: Object!
|
||||
parameters: [WSQueryParameterInfo]!
|
||||
}
|
||||
|
||||
type WSSessionTaskWithParametersConfirmationEvent implements CBClientEvent @since(version: "25.2.5") {
|
||||
|
||||
@@ -150,6 +150,19 @@ enum SQLRowIdentifierState {
|
||||
VIRTUAL_KEY
|
||||
}
|
||||
|
||||
enum SQLResultSetGeneratorId {
|
||||
"SELECT .. WHERE .. ="
|
||||
dataSelect,
|
||||
"SELECT .. WHERE .. IN"
|
||||
dataSelectMany,
|
||||
"INSERT"
|
||||
dataInsert,
|
||||
"UPDATE"
|
||||
dataUpdate,
|
||||
"DELETE by Unique Key"
|
||||
dataDeleteByUniqueKey,
|
||||
}
|
||||
|
||||
type SQLRowIdentifier {
|
||||
"Single or multiple attributes acting as a row identifier"
|
||||
attributes: [SQLRowIdentifierAttribute!]!
|
||||
@@ -183,6 +196,8 @@ type SQLExecuteInfo {
|
||||
filterText: String
|
||||
# Full query that was executed, contains all used filters
|
||||
fullQuery: String
|
||||
# Original query that was executed, without modifications
|
||||
originalQuery: String
|
||||
# Results
|
||||
results: [ SQLQueryResults! ]!
|
||||
}
|
||||
@@ -336,6 +351,19 @@ extend type Query {
|
||||
nodePathList: [String!]!
|
||||
): String!
|
||||
|
||||
"""
|
||||
Returns an auto-generated SQL query based on provided rows data.
|
||||
Uses generatorId value to establish the type of query (e.g. SELECT or INSERT)
|
||||
"""
|
||||
sqlGenerateResultSetQuery(
|
||||
projectId: ID,
|
||||
connectionId: ID!,
|
||||
contextId: ID!,
|
||||
generatorId: SQLResultSetGeneratorId!,
|
||||
resultsId: ID!,
|
||||
selectedRows: [SQLResultRow!]!,
|
||||
): String!
|
||||
|
||||
"Parses SQL script and returns script info with queries start and end positions"
|
||||
sqlParseScript(
|
||||
projectId: ID,
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -82,6 +82,7 @@ public class WebDatabaseAuthModel {
|
||||
|
||||
return Arrays.stream(credentialsSource.getProperties())
|
||||
.filter(predicate)
|
||||
.filter(p -> !p.isDesktop())
|
||||
.map(p -> new WebPropertyInfo(webSession, p, credentialsSource)).toArray(WebPropertyInfo[]::new);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -61,6 +61,7 @@ public class WebNetworkHandlerDescriptor {
|
||||
|
||||
public WebPropertyInfo[] getProperties() {
|
||||
return Arrays.stream(descriptor.getHandlerProperties())
|
||||
.filter(p -> !p.isDesktop() && !p.isHidden())
|
||||
.map(p -> new WebPropertyInfo(session, p, null)).toArray(WebPropertyInfo[]::new);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ public abstract class BaseWebPlatform extends BaseServletPlatform {
|
||||
this.queryManager.registerMetaListener(qmLogWriter);
|
||||
|
||||
this.certificateStorage = new DefaultCertificateStorage(
|
||||
this,
|
||||
WebPlatformActivator.getInstance()
|
||||
.getStateLocation()
|
||||
.toFile()
|
||||
|
||||
@@ -16,13 +16,21 @@
|
||||
*/
|
||||
package io.cloudbeaver.server;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
|
||||
public class WebAppUtils {
|
||||
|
||||
public static boolean isWebApplication() {
|
||||
return DBWorkbench.getPlatform().getApplication() instanceof WebApplication;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static WebApplication getWebApplication() {
|
||||
return (WebApplication) DBWorkbench.getPlatform().getApplication();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static BaseWebPlatform getWebPlatform() {
|
||||
return (BaseWebPlatform) DBWorkbench.getPlatform();
|
||||
}
|
||||
|
||||
+3
@@ -31,6 +31,9 @@ public class WSDefaultEventHandler<EVENT extends WSEvent> implements WSEventHand
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NotNull EVENT event) {
|
||||
if (!WebAppUtils.isWebApplication()) {
|
||||
return;
|
||||
}
|
||||
log.debug(event.getTopicId() + " event handled");
|
||||
Collection<BaseWebSession> allSessions = WebAppUtils.getWebApplication()
|
||||
.getSessionManager()
|
||||
|
||||
+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.server.events;
|
||||
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSServerConfigurationChangedEvent;
|
||||
|
||||
public class WSServerConfigurationChangedEventHandler extends WSDefaultEventHandler<WSServerConfigurationChangedEvent> {
|
||||
|
||||
@Override
|
||||
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSServerConfigurationChangedEvent event) {
|
||||
activeUserSession.refreshUserData();
|
||||
super.updateSessionData(activeUserSession, event);
|
||||
}
|
||||
}
|
||||
+10
-4
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -37,6 +37,7 @@ import io.cloudbeaver.service.DBWBindingContext;
|
||||
import io.cloudbeaver.service.DBWServiceBindingGraphQL;
|
||||
import io.cloudbeaver.service.WebServiceBindingBase;
|
||||
import io.cloudbeaver.utils.ServletAppUtils;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -202,16 +203,21 @@ public class GraphQLEndpoint extends HttpServlet {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
String path = request.getPathInfo();
|
||||
if (path == null) {
|
||||
path = request.getServletPath();
|
||||
}
|
||||
boolean develMode = ServletAppUtils.getServletApplication().getServerConfiguration().isDevelMode();
|
||||
|
||||
if (path.contentEquals("/schema.json") && develMode) {
|
||||
if (!develMode) {
|
||||
super.doGet(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (path.contentEquals("/schema.json")) {
|
||||
executeQuery(request, response, GraphQLConstants.SCHEMA_READ_QUERY, null, null);
|
||||
} else if (path.contentEquals("/console") && develMode) {
|
||||
} else if (path.contentEquals("/console")) {
|
||||
response.setContentType(MimeTypes.TEXT_HTML);
|
||||
try (InputStream consolePageStream = WebServiceUtils.openStaticResource("static/graphiql/index.html")) {
|
||||
IOUtils.copyStream(consolePageStream, response.getOutputStream());
|
||||
|
||||
+2
-2
@@ -19,8 +19,8 @@ package io.cloudbeaver.server.jetty;
|
||||
|
||||
import io.cloudbeaver.service.DBWServletContext;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.ee11.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee11.servlet.ServletHolder;
|
||||
|
||||
public class CBJettyServletContext implements DBWServletContext {
|
||||
private final ServletContextHandler contextHandler;
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ package io.cloudbeaver.server.jetty;
|
||||
|
||||
import io.cloudbeaver.service.DBWWebSocketContext;
|
||||
import jakarta.websocket.server.ServerEndpointConfig;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.ee11.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.jkiss.code.NotNull;
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
package io.cloudbeaver.server.jetty;
|
||||
|
||||
import io.cloudbeaver.server.WebApplication;
|
||||
import org.eclipse.jetty.ee10.servlet.SessionHandler;
|
||||
import org.eclipse.jetty.ee11.servlet.SessionHandler;
|
||||
import org.jkiss.code.NotNull;
|
||||
|
||||
public class CBSessionHandler extends SessionHandler {
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
package io.cloudbeaver.server.jetty;
|
||||
|
||||
import io.cloudbeaver.server.WebApplication;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee11.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.session.DefaultSessionCache;
|
||||
import org.eclipse.jetty.session.DefaultSessionIdManager;
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.WebServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee10.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.ee11.servlet.DefaultServlet;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
import org.jkiss.dbeaver.utils.GeneralUtils;
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.websocket.HandshakeResponse;
|
||||
import jakarta.websocket.server.HandshakeRequest;
|
||||
import jakarta.websocket.server.ServerEndpointConfig;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.server.internal.JakartaWebSocketCreator;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.server.internal.JakartaWebSocketCreator;
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
|
||||
+13
-2
@@ -398,7 +398,9 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
dataSourceContainer,
|
||||
dataSourceContainer.getConnectionConfiguration()
|
||||
);
|
||||
saveConfig[0] = true;
|
||||
// don't understand why whe need to set this flag here
|
||||
// need to discover it, maybe we can avoid it at all
|
||||
saveConfig[0] = sharedCredentials;
|
||||
}
|
||||
if (WebServiceUtils.isGlobalProject(dataSourceContainer.getProject())) {
|
||||
// Do not flush config for global project (only admin can do it - CB-2415)
|
||||
@@ -462,12 +464,21 @@ public class WebServiceCore implements DBWServiceCore {
|
||||
throw new DBException("Node '" + nodePath + "' is not a datasource node");
|
||||
}
|
||||
DBPDataSourceContainer dataSourceTemplate = dbnDataSource.getDataSourceContainer();
|
||||
if (!dataSourceTemplate.isExternallyProvided()) {
|
||||
if (!CommonUtils.equalObjects(dataSourceTemplate.getProject(), project)) {
|
||||
throw new DBException("Copying connection to another project is not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
DataSourceDescriptor newDataSource = dataSourceRegistry.createDataSource(dataSourceTemplate);
|
||||
|
||||
ServletApplication app = ServletAppUtils.getServletApplication();
|
||||
if (app instanceof WebApplication webApplication) {
|
||||
newDataSource.setNavigatorSettings(webApplication.getAppConfiguration().getDefaultNavigatorSettings());
|
||||
newDataSource.setNavigatorSettings(
|
||||
dataSourceTemplate.isExternallyProvided() ?
|
||||
webApplication.getAppConfiguration().getDefaultNavigatorSettings() :
|
||||
dataSourceTemplate.getNavigatorSettings().getOriginalSettings()
|
||||
);
|
||||
}
|
||||
|
||||
WebConnectionConfig config = project.getConnectionConfigInput(connectionConfig);
|
||||
|
||||
+9
-9
@@ -145,11 +145,6 @@ public class WebDefaultFeatureProvider implements DBWFeatureProvider {
|
||||
return features;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getProjectId(@NotNull DBNNode node) {
|
||||
return node.getOwnerProject().getId();
|
||||
}
|
||||
|
||||
private boolean canCreateConnectionFromFileName(String fileName) {
|
||||
String fileExtension = IOUtils.getFileExtension(fileName);
|
||||
if (CommonUtils.isEmpty(fileExtension)) {
|
||||
@@ -169,11 +164,16 @@ public class WebDefaultFeatureProvider implements DBWFeatureProvider {
|
||||
}
|
||||
|
||||
private boolean hasNodePermission(@NotNull WebSession webSession, @NotNull DBNNode node, @NotNull RMProjectPermission permission) {
|
||||
WebProjectImpl project = webSession.getProjectById(node.getOwnerProject().getId());
|
||||
if (project == null) {
|
||||
return false;
|
||||
RMProject rmProject;
|
||||
if (node instanceof DBNResourceManagerResource rmr) {
|
||||
rmProject = rmr.getRmProject();
|
||||
} else {
|
||||
WebProjectImpl project = webSession.getProjectById(node.getOwnerProject().getId());
|
||||
if (project == null) {
|
||||
return false;
|
||||
}
|
||||
rmProject = project.getRMProject();
|
||||
}
|
||||
RMProject rmProject = project.getRMProject();
|
||||
return SMUtils.hasProjectPermission(webSession, rmProject, permission);
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -79,6 +79,15 @@ public interface DBWServiceSQL extends DBWService {
|
||||
@NotNull Map<String, Object> options,
|
||||
@NotNull List<String> nodePathList) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
String sqlGenerateResultSetQuery(
|
||||
@NotNull WebSession session,
|
||||
@NotNull WebSQLContextInfo sqlContext,
|
||||
@NotNull String generatorId,
|
||||
@NotNull String resultsId,
|
||||
@NotNull List<WebSQLResultsRow> selectedRows
|
||||
) throws DBWebException;
|
||||
|
||||
@WebAction
|
||||
WebSQLContextInfo createContext(
|
||||
@NotNull WebSQLProcessor processor,
|
||||
|
||||
+7
-2
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.sql;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.meta.Property;
|
||||
|
||||
@@ -30,6 +31,7 @@ public class WebSQLExecuteInfo {
|
||||
private long duration;
|
||||
private String filterText;
|
||||
private String fullQuery;
|
||||
private String originalQuery;
|
||||
private WebSQLQueryResults[] results;
|
||||
|
||||
@Property
|
||||
@@ -70,8 +72,11 @@ public class WebSQLExecuteInfo {
|
||||
|
||||
@Property
|
||||
public String getOriginalQuery() {
|
||||
//TODO implement
|
||||
return null; // should return the original query without data filters
|
||||
return originalQuery;
|
||||
}
|
||||
|
||||
public void setOriginalQuery(@NotNull String originalQuery) {
|
||||
this.originalQuery = originalQuery;
|
||||
}
|
||||
|
||||
@Property
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.MultipartConfig;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
|
||||
import org.eclipse.jetty.ee11.servlet.ServletContextRequest;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
|
||||
+3
-3
@@ -32,7 +32,7 @@ import org.jkiss.dbeaver.model.sql.SQLQueryParameter;
|
||||
import org.jkiss.dbeaver.model.sql.SQLScriptContext;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -58,11 +58,11 @@ public class WebSQLParametersProvider extends SQLParametersProviderBase {
|
||||
@NotNull List<SQLQueryParameter> parameters,
|
||||
@NotNull Supplier<DBDDataReceiver> dataReceiverSupplier
|
||||
) {
|
||||
Map<String, Object> unsetParams = new LinkedHashMap<>();
|
||||
List<WebSQLQueryParameterRecord> unsetParams = new ArrayList<>();
|
||||
for (SQLQueryParameter param : parameters) {
|
||||
if (!param.isVariableSet()) {
|
||||
// Empty value for now, maybe in future we can set some defaults here
|
||||
unsetParams.put(param.getName(), "");
|
||||
unsetParams.add(new WebSQLQueryParameterRecord(param.getName(), param.getValue()));
|
||||
}
|
||||
}
|
||||
if (unsetParams.isEmpty()) {
|
||||
|
||||
+15
-2
@@ -296,7 +296,17 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
if (sqlOutputLogReaderJob != null) {
|
||||
sqlOutputLogReaderJob.join();
|
||||
}
|
||||
fillQueryResults(contextInfo, dataContainer, dbStat, hasResultSet, executeInfo, webDataFilter, dataFilter, dataFormat);
|
||||
fillQueryResults(
|
||||
contextInfo,
|
||||
dataContainer,
|
||||
dbStat,
|
||||
hasResultSet,
|
||||
executeInfo,
|
||||
webDataFilter,
|
||||
dataFilter,
|
||||
dataFormat,
|
||||
sqlElement.getOriginalText()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1066,7 +1076,9 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
@NotNull WebSQLExecuteInfo executeInfo,
|
||||
@NotNull WebSQLDataFilter webDataFilter,
|
||||
@NotNull DBDDataFilter dataFilter,
|
||||
@Nullable WebDataFormat dataFormat) throws DBException {
|
||||
@Nullable WebDataFormat dataFormat,
|
||||
@NotNull String originalQuery
|
||||
) throws DBException {
|
||||
|
||||
List<WebSQLQueryResults> resultList = new ArrayList<>();
|
||||
int maxResultsCount = resolveMaxResultsCount(dataContainer.getDataSource());
|
||||
@@ -1110,6 +1122,7 @@ public class WebSQLProcessor implements WebSessionProvider {
|
||||
|
||||
setResultFilterText(dbStat.getSession().getDataSource(), executeInfo, dataFilter);
|
||||
executeInfo.setFullQuery(dbStat.getQueryString());
|
||||
executeInfo.setOriginalQuery(originalQuery);
|
||||
}
|
||||
|
||||
private void setResultFilterText(
|
||||
|
||||
+1
-6
@@ -34,7 +34,6 @@ import org.jkiss.dbeaver.model.meta.MetaData;
|
||||
import org.jkiss.dbeaver.model.sql.DBQuotaException;
|
||||
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
|
||||
import org.jkiss.dbeaver.model.struct.DBSEntity;
|
||||
import org.jkiss.dbeaver.model.struct.DBSEntityConstraintType;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -190,15 +189,11 @@ class WebSQLQueryDataReceiver implements DBDDataReceiver {
|
||||
DBDRowIdentifier rowIdentifier = resultsInfo.getDefaultRowIdentifier();
|
||||
if (rowIdentifier == null) {
|
||||
webResultSet.setRowIdentifierState(WebSQLResultSetRowIdentifierState.METADATA_NOT_FOUND);
|
||||
} else if (rowIdentifier.getUniqueKey().getConstraintType().equals(DBSEntityConstraintType.VIRTUAL_KEY)) {
|
||||
webResultSet.setRowIdentifierState(WebSQLResultSetRowIdentifierState.VIRTUAL_KEY);
|
||||
} else if (!rowIdentifier.isIncomplete() && rowIdentifier.isValidIdentifier()) {
|
||||
webResultSet.setHasRowIdentifier(true);
|
||||
webResultSet.setRowIdentifierState(WebSQLResultSetRowIdentifierState.PRIMARY_KEY);
|
||||
List<WebSQLResultSetRowIdentifierAttribute> attributes = rowIdentifier.getAttributes().stream()
|
||||
.map(a -> new WebSQLResultSetRowIdentifierAttribute(
|
||||
a.getName(), a.getOrdinalPosition(), a.getLabel(), a.getDescription()
|
||||
))
|
||||
.map(a -> new WebSQLResultSetRowIdentifierAttribute(a.getName(), a.getOrdinalPosition()))
|
||||
.toList();
|
||||
String constraintTypeName = rowIdentifier.getUniqueKey().getConstraintType().getName();
|
||||
webResultSet.setRowIdentifier(
|
||||
|
||||
+1
-2
@@ -48,8 +48,7 @@ public class WebSQLResultSetRowIdentifier {
|
||||
public enum WebSQLResultSetRowIdentifierState {
|
||||
METADATA_NOT_FOUND,
|
||||
NONE,
|
||||
PRIMARY_KEY,
|
||||
VIRTUAL_KEY
|
||||
PRIMARY_KEY
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-4
@@ -1,7 +1,6 @@
|
||||
package io.cloudbeaver.service.sql;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
|
||||
public class WebSQLResultSetRowIdentifierAttribute {
|
||||
|
||||
@@ -11,9 +10,7 @@ public class WebSQLResultSetRowIdentifierAttribute {
|
||||
|
||||
public WebSQLResultSetRowIdentifierAttribute(
|
||||
@NotNull String name,
|
||||
int ordinalPosition,
|
||||
@NotNull String label,
|
||||
@Nullable String description
|
||||
int ordinalPosition
|
||||
) {
|
||||
this.name = name;
|
||||
this.ordinalPosition = ordinalPosition;
|
||||
|
||||
+24
-11
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -27,10 +27,12 @@ import io.cloudbeaver.service.DBWServletContext;
|
||||
import io.cloudbeaver.service.WebServiceBindingBase;
|
||||
import io.cloudbeaver.service.sql.impl.WebServiceSQL;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.NotNullWhen;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -90,7 +92,17 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
|
||||
getArgumentVal(env, "generatorId"),
|
||||
getArgumentVal(env, "options"),
|
||||
getArgumentVal(env, "nodePathList"))
|
||||
).dataFetcher("sqlParseScript", env ->
|
||||
)
|
||||
.dataFetcher("sqlGenerateResultSetQuery", env ->
|
||||
getService(env).sqlGenerateResultSetQuery(
|
||||
getWebSession(env),
|
||||
getSQLContext(env),
|
||||
getArgumentVal(env, "generatorId"),
|
||||
getArgumentVal(env, "resultsId"),
|
||||
getResultsRow(env, "selectedRows")
|
||||
)
|
||||
)
|
||||
.dataFetcher("sqlParseScript", env ->
|
||||
getService(env).parseSqlScript(getWebConnection(env), getArgumentVal(env, "script"))
|
||||
).dataFetcher("sqlParseQuery", env ->
|
||||
getService(env).parseSqlQuery(
|
||||
@@ -152,7 +164,7 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
|
||||
getSQLContext(env),
|
||||
getArgumentVal(env, "resultsId"),
|
||||
getArgumentVal(env, "lobColumnIndex"),
|
||||
getResultsRow(env, "row").get(0)))
|
||||
getResultsRow(env, "row").getFirst()))
|
||||
.dataFetcher("sqlReadLobValue", env ->
|
||||
getService(env).readLobValue(
|
||||
getSQLContext(env),
|
||||
@@ -291,10 +303,10 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
|
||||
|
||||
@NotNull
|
||||
public static WebSQLProcessor getSQLProcessor(WebConnectionInfo connectionInfo) throws DBWebException {
|
||||
return getSQLConfiguration(connectionInfo.getSession()).getSQLProcessor(connectionInfo);
|
||||
return getSQLProcessor(connectionInfo, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNullWhen("connect")
|
||||
public static WebSQLProcessor getSQLProcessor(WebConnectionInfo connectionInfo, boolean connect) throws DBWebException {
|
||||
return getSQLConfiguration(connectionInfo.getSession()).getSQLProcessor(connectionInfo, connect);
|
||||
}
|
||||
@@ -346,16 +358,13 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
|
||||
return application.isMultiuser();
|
||||
}
|
||||
|
||||
private static class WebSQLConfiguration {
|
||||
public static class WebSQLConfiguration {
|
||||
private final Map<WebConnectionInfo, WebSQLProcessor> processors = new HashMap<>();
|
||||
|
||||
public WebSQLConfiguration() {
|
||||
}
|
||||
|
||||
WebSQLProcessor getSQLProcessor(WebConnectionInfo connectionInfo) throws DBWebException {
|
||||
return WebServiceBindingSQL.getSQLProcessor(connectionInfo, true);
|
||||
}
|
||||
|
||||
@NotNullWhen("connect")
|
||||
WebSQLProcessor getSQLProcessor(WebConnectionInfo connectionInfo, boolean connect) throws DBWebException {
|
||||
if (connectionInfo.getDataSource() == null) {
|
||||
if (!connect) {
|
||||
@@ -378,6 +387,7 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WebSQLConfiguration dispose() {
|
||||
synchronized (processors) {
|
||||
processors.forEach((connectionInfo, processor) -> processor.dispose());
|
||||
@@ -389,15 +399,18 @@ public class WebServiceBindingSQL extends WebServiceBindingBase<DBWServiceSQL>
|
||||
|
||||
///////////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
@Nullable
|
||||
public static WebSQLDataFilter getDataFilter(DataFetchingEnvironment env) {
|
||||
Map<String, Object> filterProps = getArgument(env, "filter");
|
||||
return filterProps == null ? null : new WebSQLDataFilter(filterProps);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<WebSQLResultsRow> getResultsRow(DataFetchingEnvironment env, String param) {
|
||||
List<Map<String, Object>> mapList = getArgument(env, param);
|
||||
if (CommonUtils.isEmpty(mapList)) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return mapList.stream().map(WebSQLResultsRow::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 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.sql.impl;
|
||||
|
||||
import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.service.sql.WebSQLContextInfo;
|
||||
import io.cloudbeaver.service.sql.WebSQLResultsRow;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.DBPDataSource;
|
||||
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
|
||||
import org.jkiss.dbeaver.model.DBUtils;
|
||||
import org.jkiss.dbeaver.model.data.DBDAttributeBinding;
|
||||
import org.jkiss.dbeaver.model.data.DBDResultSetDataProvider;
|
||||
import org.jkiss.dbeaver.model.data.DBDRowIdentifier;
|
||||
import org.jkiss.dbeaver.model.data.DBDValueRow;
|
||||
import org.jkiss.dbeaver.model.data.hints.DBDValueHintContext;
|
||||
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
|
||||
import org.jkiss.dbeaver.model.struct.DBSEntity;
|
||||
import org.jkiss.dbeaver.model.struct.DBSObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class WebDBDResultSetDataProvider implements DBDResultSetDataProvider, DBSObject {
|
||||
|
||||
private final String resultsId;
|
||||
private final WebSQLContextInfo contextInfo;
|
||||
private final List<WebSQLResultsRow> selectedRows;
|
||||
|
||||
WebDBDResultSetDataProvider(
|
||||
@NotNull String resultsId,
|
||||
@NotNull WebSQLContextInfo contextInfo,
|
||||
@NotNull List<WebSQLResultsRow> selectedRows
|
||||
) {
|
||||
this.resultsId = resultsId;
|
||||
this.contextInfo = contextInfo;
|
||||
this.selectedRows = selectedRows;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DBDAttributeBinding[] getAttributes() throws DBWebException {
|
||||
return contextInfo.getResults(resultsId).getAttributes();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<DBDAttributeBinding> getVisibleAttributes() throws DBException {
|
||||
return Arrays.asList(getAttributes());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends DBDValueRow> getAllRows() {
|
||||
return getSelectedRows();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<? extends DBDValueRow> getSelectedRows() {
|
||||
if (selectedRows.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<WebDBDValueRow> rows = new ArrayList<>();
|
||||
for (int rowNumber = 0; rowNumber < selectedRows.size(); rowNumber++) {
|
||||
WebSQLResultsRow row = selectedRows.get(rowNumber);
|
||||
if (row != null && row.getData() != null) {
|
||||
rows.add(new WebDBDValueRow(rowNumber, row.getData()));
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DBSEntity getSingleSource() throws DBWebException {
|
||||
DBDRowIdentifier rowIdentifier = contextInfo.getResults(resultsId).getDefaultRowIdentifier();
|
||||
if (rowIdentifier == null) {
|
||||
return null;
|
||||
} else {
|
||||
return rowIdentifier.getEntity();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DBDRowIdentifier getDefaultRowIdentifier() {
|
||||
try {
|
||||
return contextInfo.getResults(resultsId).getDefaultRowIdentifier();
|
||||
} catch (DBWebException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getCellValue(@NotNull DBDAttributeBinding attribute, @NotNull DBDValueRow row) throws DBException {
|
||||
return DBUtils.getAttributeValue(attribute, getAttributes(), row.getValues());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getCellValue(
|
||||
@NotNull DBDAttributeBinding attribute,
|
||||
@NotNull DBDValueRow row,
|
||||
@Nullable int[] rowIndexes,
|
||||
boolean retrieveDeepestCollectionElement
|
||||
) throws DBWebException {
|
||||
return DBUtils.getAttributeValue(attribute, getAttributes(), row.getValues());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DBDValueHintContext getHintContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getReadOnlyStatus(@Nullable DBPDataSourceContainer dataSourceContainer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DBSObject getParentObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DBPDataSource getDataSource() {
|
||||
DBCExecutionContext executionContext = contextInfo.getProcessor().getExecutionContext();
|
||||
if (executionContext == null) {
|
||||
return null;
|
||||
} else {
|
||||
return executionContext.getDataSource();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return WebDBDResultSetDataProvider.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPersisted() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2026 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.sql.impl;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.data.DBDValueRow;
|
||||
|
||||
public class WebDBDValueRow implements DBDValueRow {
|
||||
private final int rowNumber;
|
||||
private final Object[] values;
|
||||
|
||||
public WebDBDValueRow(int rowNumber, @NotNull Object[] values) {
|
||||
this.rowNumber = rowNumber;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowNumber() {
|
||||
return rowNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getValues() {
|
||||
return values;
|
||||
}
|
||||
}
|
||||
+22
-5
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2026 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.
|
||||
@@ -66,10 +66,7 @@ import org.jkiss.dbeaver.utils.RuntimeUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -248,6 +245,26 @@ public class WebServiceSQL implements DBWServiceSQL {
|
||||
@Override
|
||||
public String generateEntityQuery(@NotNull WebSession session, @NotNull String generatorId, @NotNull Map<String, Object> options, @NotNull List<String> nodePathList) throws DBWebException {
|
||||
List<DBSObject> objectList = getObjectListFromNodeIds(session, nodePathList);
|
||||
return createAndRunGenerator(session, generatorId, objectList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String sqlGenerateResultSetQuery(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull WebSQLContextInfo sqlContext,
|
||||
@NotNull String generatorId,
|
||||
@NotNull String resultsId,
|
||||
@NotNull List<WebSQLResultsRow> selectedRows
|
||||
) throws DBWebException {
|
||||
WebDBDResultSetDataProvider dataProvider = new WebDBDResultSetDataProvider(resultsId, sqlContext, selectedRows);
|
||||
return createAndRunGenerator(webSession, generatorId, Collections.singletonList(dataProvider));
|
||||
}
|
||||
|
||||
private String createAndRunGenerator(
|
||||
@NotNull WebSession session,
|
||||
@NotNull String generatorId,
|
||||
@NotNull List<DBSObject> objectList
|
||||
) throws DBWebException {
|
||||
SQLGeneratorDescriptor generator = SQLGeneratorConfigurationRegistry.getInstance().getGenerator(generatorId);
|
||||
if (generator == null) {
|
||||
throw new DBWebException("Generator '" + generatorId + "' not found");
|
||||
|
||||
@@ -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.138.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.140.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.admin</artifactId>
|
||||
<version>1.0.138-SNAPSHOT</version>
|
||||
<version>1.0.140-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
-10
@@ -34,7 +34,6 @@ public class AdminServerConfig {
|
||||
private static final Log log = Log.getLog(AdminServerConfig.class);
|
||||
|
||||
private String serverName;
|
||||
private String serverURL;
|
||||
|
||||
private String adminName;
|
||||
private String adminPassword;
|
||||
@@ -60,7 +59,6 @@ public class AdminServerConfig {
|
||||
|
||||
public AdminServerConfig(Map<String, Object> params) {
|
||||
this.serverName = JSONUtils.getString(params, "serverName");
|
||||
this.serverURL = JSONUtils.getString(params, "serverURL");
|
||||
this.adminName = JSONUtils.getString(params, "adminName");
|
||||
this.adminPassword = JSONUtils.getString(params, "adminPassword");
|
||||
|
||||
@@ -133,14 +131,6 @@ public class AdminServerConfig {
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
public String getServerURL() {
|
||||
return serverURL;
|
||||
}
|
||||
|
||||
public void setServerURL(String serverURL) {
|
||||
this.serverURL = serverURL;
|
||||
}
|
||||
|
||||
public String getAdminName() {
|
||||
return adminName;
|
||||
}
|
||||
|
||||
+10
-13
@@ -20,9 +20,11 @@ import io.cloudbeaver.model.config.CBAppConfig;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.model.utils.ConfigurationUtils;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBConstants;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.server.WebAppUtils;
|
||||
import io.cloudbeaver.service.admin.AdminConnectionSearchInfo;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.connection.DBPDriver;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress;
|
||||
@@ -46,7 +48,7 @@ public class ConnectionSearcher implements DBRRunnableWithProgress {
|
||||
private final String[] hostNames;
|
||||
private final List<AdminConnectionSearchInfo> foundConnections = new ArrayList<>();
|
||||
|
||||
public ConnectionSearcher(WebSession webSession, String[] hostNames) {
|
||||
public ConnectionSearcher(@NotNull WebSession webSession, @NotNull String[] hostNames) {
|
||||
this.webSession = webSession;
|
||||
this.hostNames = hostNames;
|
||||
}
|
||||
@@ -54,6 +56,7 @@ public class ConnectionSearcher implements DBRRunnableWithProgress {
|
||||
/**
|
||||
* Returns all found connections in a current machine.
|
||||
*/
|
||||
@NotNull
|
||||
public List<AdminConnectionSearchInfo> getFoundConnections() {
|
||||
synchronized (foundConnections) {
|
||||
return new ArrayList<>(foundConnections);
|
||||
@@ -66,7 +69,7 @@ public class ConnectionSearcher implements DBRRunnableWithProgress {
|
||||
Map<String, String> localHostNames = new HashMap<>();
|
||||
for (String hostName : hostNames) {
|
||||
monitor.subTask("Search connections on '" + hostName + "'");
|
||||
if (hostName.equals("localhost") || hostName.equals("local") || hostName.equals("127.0.0.1")) {
|
||||
if (hostName.equals("localhost") || hostName.equals("local") || hostName.equals(CBConstants.HOST_127_0_0_1)) {
|
||||
for (InetAddress addr : CBPlatform.getInstance().getApplication().getLocalInetAddresses()) {
|
||||
String localHostAddress = addr.getHostAddress();
|
||||
finalHostNames.add(localHostAddress);
|
||||
@@ -105,7 +108,7 @@ public class ConnectionSearcher implements DBRRunnableWithProgress {
|
||||
}
|
||||
}
|
||||
|
||||
private void searchConnections(DBRProgressMonitor monitor, String hostName, String displayName) {
|
||||
private void searchConnections(@NotNull DBRProgressMonitor monitor, String hostName, String displayName) {
|
||||
int checkTimeout = 150;
|
||||
Map<Integer, AdminConnectionSearchInfo> portCache = new HashMap<>();
|
||||
|
||||
@@ -164,16 +167,10 @@ public class ConnectionSearcher implements DBRRunnableWithProgress {
|
||||
|
||||
private static boolean isPortInBlockList(int portNumber) {
|
||||
// All http(s) and telnet ports are in block lists
|
||||
switch (portNumber) {
|
||||
case 0:
|
||||
case 22:
|
||||
case 80:
|
||||
case 443:
|
||||
case 8080:
|
||||
case 8443:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return switch (portNumber) {
|
||||
case 0, 22, 80, 443, 8080, 8443 -> true;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+57
-6
@@ -38,6 +38,7 @@ import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBConstants;
|
||||
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
|
||||
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
|
||||
import org.jkiss.dbeaver.model.app.DBPProject;
|
||||
@@ -51,6 +52,7 @@ import org.jkiss.dbeaver.model.security.*;
|
||||
import org.jkiss.dbeaver.model.security.user.SMTeam;
|
||||
import org.jkiss.dbeaver.model.security.user.SMUser;
|
||||
import org.jkiss.dbeaver.utils.GeneralUtils;
|
||||
import org.jkiss.utils.ArrayUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
@@ -496,7 +498,7 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
@NotNull HttpServletRequest request,
|
||||
@NotNull WebSession webSession,
|
||||
@Nullable String providerId
|
||||
) throws DBWebException {
|
||||
) {
|
||||
String origin = ServletAppUtils.getOriginFromRequest(request);
|
||||
List<WebAuthProviderConfiguration> result = new ArrayList<>();
|
||||
for (SMAuthProviderCustomConfiguration cfg : CBApplication.getInstance().getAppConfiguration().getAuthCustomConfigurations()) {
|
||||
@@ -505,7 +507,11 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
}
|
||||
WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(cfg.getProvider());
|
||||
if (authProvider != null) {
|
||||
result.add(new WebAuthProviderConfiguration(authProvider, cfg, origin));
|
||||
result.add(new WebAuthProviderConfiguration(
|
||||
authProvider,
|
||||
maskSecuredConfigParameters(authProvider.getConfigurationParameters(), cfg),
|
||||
origin
|
||||
));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -521,7 +527,8 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
boolean disabled,
|
||||
@Nullable String iconURL,
|
||||
@Nullable String description,
|
||||
@Nullable Map<String, Object> parameters) throws DBWebException {
|
||||
@Nullable Map<String, Object> parameters
|
||||
) throws DBWebException {
|
||||
WebAuthProviderDescriptor authProvider = WebAuthProviderRegistry.getInstance().getAuthProvider(providerId);
|
||||
if (authProvider == null) {
|
||||
throw new DBWebException("Auth provider '" + providerId + "' not found");
|
||||
@@ -534,6 +541,14 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
providerConfig.setDisabled(disabled);
|
||||
providerConfig.setIconURL(iconURL);
|
||||
providerConfig.setDescription(description);
|
||||
SMAuthProviderCustomConfiguration savedConfig = getProviderConfig(id);
|
||||
if (parameters != null && savedConfig != null) {
|
||||
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
|
||||
if (CBConstants.SECURED_VALUE.equals(entry.getValue())) {
|
||||
parameters.put(entry.getKey(), savedConfig.getParameter(entry.getKey()));
|
||||
}
|
||||
}
|
||||
}
|
||||
providerConfig.setParameters(parameters);
|
||||
CBApplication.getInstance().getAppConfiguration().addAuthProviderConfiguration(providerConfig);
|
||||
try {
|
||||
@@ -547,7 +562,11 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
providerConfig.getProvider(),
|
||||
webSession.getUserId()
|
||||
));
|
||||
return new WebAuthProviderConfiguration(authProvider, providerConfig, ServletAppUtils.getOriginFromRequest(request));
|
||||
return new WebAuthProviderConfiguration(
|
||||
authProvider,
|
||||
maskSecuredConfigParameters(authProvider.getConfigurationParameters(), providerConfig),
|
||||
ServletAppUtils.getOriginFromRequest(request)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -576,7 +595,6 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
CBAppConfig appConfig = new CBAppConfig(CBApplication.getInstance().getAppConfiguration());
|
||||
CBServerConfig serverConfig = new CBServerConfig();
|
||||
serverConfig.setServerName(CBApplication.getInstance().getServerName());
|
||||
serverConfig.setServerURL(CBApplication.getInstance().getServerURL());
|
||||
serverConfig.setMaxSessionIdleTime(CBApplication.getInstance().getMaxSessionIdleTime());
|
||||
String adminName = null;
|
||||
String adminPassword = null;
|
||||
@@ -606,7 +624,6 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
adminName = config.getAdminName();
|
||||
adminPassword = config.getAdminPassword();
|
||||
serverConfig.setServerName(config.getServerName());
|
||||
serverConfig.setServerURL(config.getServerURL());
|
||||
serverConfig.setMaxSessionIdleTime(config.getSessionExpireTime());
|
||||
if (config.getForceHttps() != null) {
|
||||
serverConfig.setForceHttps(config.getForceHttps());
|
||||
@@ -667,6 +684,11 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
// In config mode we always refresh because admin user doesn't exist yet
|
||||
webSession.resetUserState();
|
||||
}
|
||||
else {
|
||||
// Just reload session state
|
||||
webSession.refreshUserData();
|
||||
}
|
||||
|
||||
WebAppUtils.getWebApplication().getDriverRegistry().refreshApplicableDrivers();
|
||||
} catch (Throwable e) {
|
||||
throw new DBWebException("Error configuring server", e);
|
||||
@@ -954,4 +976,33 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private SMAuthProviderCustomConfiguration maskSecuredConfigParameters(
|
||||
@NotNull List<WebAuthProviderProperty> configProperties,
|
||||
@NotNull SMAuthProviderCustomConfiguration config
|
||||
) {
|
||||
SMAuthProviderCustomConfiguration securedConfig = new SMAuthProviderCustomConfiguration(config);
|
||||
for (WebAuthProviderProperty property : configProperties) {
|
||||
String[] features = property.getFeatures();
|
||||
if (features != null && ArrayUtils.contains(features, DBConstants.PROP_FEATURE_PASSWORD)) {
|
||||
String propertyId = property.getId();
|
||||
Object securedParameterValue = config.getParameter(propertyId);
|
||||
if (securedParameterValue != null && !securedParameterValue.toString().isEmpty()) {
|
||||
securedConfig.getParameters().put(propertyId, CBConstants.SECURED_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return securedConfig;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SMAuthProviderCustomConfiguration getProviderConfig(@NotNull String configId) {
|
||||
return CBApplication.getInstance().getAppConfiguration().getAuthCustomConfigurations().stream()
|
||||
.filter(cfg -> Objects.equals(cfg.getId(), configId))
|
||||
.filter(cfg ->
|
||||
WebAuthProviderRegistry.getInstance().getAuthProvider(cfg.getProvider()) != null
|
||||
).findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.138.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.140.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.auth</artifactId>
|
||||
<version>1.0.138-SNAPSHOT</version>
|
||||
<version>1.0.140-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -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.139.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.141.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.data.transfer</artifactId>
|
||||
<version>1.0.139-SNAPSHOT</version>
|
||||
<version>1.0.141-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -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.56.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.58.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server.ce,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.fs</artifactId>
|
||||
<version>1.0.56-SNAPSHOT</version>
|
||||
<version>1.0.58-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ import jakarta.servlet.annotation.MultipartConfig;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.Part;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextRequest;
|
||||
import org.eclipse.jetty.ee11.servlet.ServletContextRequest;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.data.json.JSONUtils;
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Cloudbeaver Web Service - LDAP
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.ldap.auth;singleton:=true
|
||||
Bundle-Version: 1.0.21.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.23.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.ldap.auth</artifactId>
|
||||
<version>1.0.21-SNAPSHOT</version>
|
||||
<version>1.0.23-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.142.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.144.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.metadata</artifactId>
|
||||
<version>1.0.142-SNAPSHOT</version>
|
||||
<version>1.0.144-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.56.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.58.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.model,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.rm.nio</artifactId>
|
||||
<version>1.0.56-SNAPSHOT</version>
|
||||
<version>1.0.58-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.91.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.93.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: io.cloudbeaver.server,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.rm</artifactId>
|
||||
<version>1.0.91-SNAPSHOT</version>
|
||||
<version>1.0.93-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Cloudbeaver Web Service - Security
|
||||
Bundle-Vendor: DBeaver Corp
|
||||
Bundle-SymbolicName: io.cloudbeaver.service.security;singleton:=true
|
||||
Bundle-Version: 1.0.94.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.96.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.service.security</artifactId>
|
||||
<version>1.0.94-SNAPSHOT</version>
|
||||
<version>1.0.96-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
+2
@@ -2333,6 +2333,7 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
invalidateUserTokens(currentUserCreds.getSmAccessToken());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SMTokens refreshSession(@NotNull String refreshToken) throws DBException {
|
||||
var currentUserCreds = getCurrentUserCreds();
|
||||
@@ -2995,6 +2996,7 @@ public class CBEmbeddedSecurityController<T extends ServletAuthApplication>
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public SMAuthPermissions getTokenPermissions() throws DBException {
|
||||
SMCredentials activeUserCredentials = credentialsProvider.getActiveUserCredentials();
|
||||
|
||||
+4
-1
@@ -184,7 +184,10 @@ public class CBDatabase extends InternalDB<WebDatabaseConfig> {
|
||||
return getDatabaseDriver(dataSourceProviderRegistry);
|
||||
}
|
||||
|
||||
private void setDefaultUserAndPassword(@NotNull DBPDriver driver) {
|
||||
private void setDefaultUserAndPassword(@NotNull DBPDriver driver) throws DBException {
|
||||
if (!driver.isEmbedded() && CommonUtils.isEmpty(databaseConfig.getPassword())) {
|
||||
throw new DBException("Password must be specified for non-embedded database");
|
||||
}
|
||||
if (!CommonUtils.isEmpty(databaseConfig.getUser()) || !driver.isEmbedded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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.54.qualifier
|
||||
Bundle-Release-Date: 20260202
|
||||
Bundle-Version: 1.0.56.qualifier
|
||||
Bundle-Release-Date: 20260302
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-21
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Fragment-Host: slf4j.api
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
<artifactId>io.cloudbeaver.slf4j</artifactId>
|
||||
<version>1.0.54-SNAPSHOT</version>
|
||||
<version>1.0.56-SNAPSHOT</version>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<dependency>
|
||||
<groupId>org.duckdb</groupId>
|
||||
<artifactId>duckdb_jdbc</artifactId>
|
||||
<version>1.3.2.0</version>
|
||||
<version>1.4.4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<feature
|
||||
id="io.cloudbeaver.ce.drivers.feature"
|
||||
label="Cloudbeaver CE 3rd Party Drivers"
|
||||
version="1.0.162.qualifier"
|
||||
version="1.0.164.qualifier"
|
||||
provider-name="DBeaver Corp">
|
||||
|
||||
<plugin id="io.cloudbeaver.resources.drivers.base" version="0.0.0"/>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user