diff --git a/README.md b/README.md
index a656ab0327..be604f1cdb 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,10 @@ You can see a live demo of CloudBeaver here: https://demo.cloudbeaver.io
## Changelog
+### 24.2.5. 2024-11-18
+- Updated user storage mechanism: New user logins are now stored in lowercase to prevent duplicate entries (e.g., "ADMIN" and "admin"). Note: This update does not affect previously created user logins;
+- A new setting in Global Preferences was added to restrict data import for non-admin users.
+
### 24.2.4. 2024-11-04
- General:
- Data export: Added the ability to export JSON values as embedded JSON;
diff --git a/config/core/cloudbeaver.conf b/config/core/cloudbeaver.conf
index 8f6ec86e77..9ebad0078f 100644
--- a/config/core/cloudbeaver.conf
+++ b/config/core/cloudbeaver.conf
@@ -1,6 +1,6 @@
{
server: {
- serverPort: "${CLOUDBEAVER_SERVICE_PORT:8978}",
+ serverPort: "${CLOUDBEAVER_WEB_SERVER_PORT:8978}",
workspaceLocation: "${CLOUDBEAVER_WORKSPACE_LOCATION:workspace}",
contentRoot: "web",
diff --git a/osgi-app.properties b/osgi-app.properties
index 423b98ad5f..1681d2bbb2 100644
--- a/osgi-app.properties
+++ b/osgi-app.properties
@@ -30,4 +30,6 @@ testBundlePaths=\
additionalModuleRoots=\
opt;
optionalFeatureRepositories=\
- dbeaver/product/repositories
\ No newline at end of file
+ dbeaver/product/repositories
+excludeOutputs=\
+ cloudbeaver/webapp/node_modules
\ No newline at end of file
diff --git a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF
index 66edf9bbb2..5f998bc37e 100644
--- a/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.model/META-INF/MANIFEST.MF
@@ -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.65.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.66.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.model/pom.xml b/server/bundles/io.cloudbeaver.model/pom.xml
index 0832142631..cd0f7854f8 100644
--- a/server/bundles/io.cloudbeaver.model/pom.xml
+++ b/server/bundles/io.cloudbeaver.model/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.model
- 1.0.65-SNAPSHOT
+ 1.0.66-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWebException.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWebException.java
index f4cc8e50ea..a06626ed51 100644
--- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWebException.java
+++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/DBWebException.java
@@ -22,7 +22,6 @@
import graphql.language.SourceLocation;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.sql.SQLState;
-import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.utils.CommonUtils;
import java.io.PrintWriter;
@@ -100,7 +99,7 @@ public ErrorClassification getErrorType() {
@Override
public Map getExtensions() {
StringWriter buf = new StringWriter();
- GeneralUtils.getRootCause(this).printStackTrace(new PrintWriter(buf, true));
+ CommonUtils.getRootCause(this).printStackTrace(new PrintWriter(buf, true));
Map extensions = new LinkedHashMap<>();
String stString = buf.toString();
diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java
index 85f9d249d3..c41c22e7fb 100644
--- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java
+++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/WebConnectionInfo.java
@@ -42,6 +42,8 @@
import org.jkiss.dbeaver.model.rm.RMConstants;
import org.jkiss.dbeaver.model.rm.RMProjectPermission;
import org.jkiss.dbeaver.model.runtime.DBRRunnableParametrized;
+import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
+import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.CommonUtils;
@@ -356,8 +358,16 @@ public WebPropertyInfo[] getAuthProperties() {
@Property
public List getNetworkHandlersConfig() {
- return dataSourceContainer.getConnectionConfiguration().getHandlers().stream()
- .map(WebNetworkHandlerConfig::new).collect(Collectors.toList());
+ var registry = NetworkHandlerRegistry.getInstance();
+ return dataSourceContainer.getConnectionConfiguration()
+ .getHandlers()
+ .stream()
+ .filter(handlerConf -> {
+ NetworkHandlerDescriptor descriptor = registry.getDescriptor(handlerConf.getId());
+ return descriptor != null && !descriptor.isDesktopHandler();
+ })
+ .map(WebNetworkHandlerConfig::new)
+ .collect(Collectors.toList());
}
@Property
diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java
index 16822ec600..78a87c8fcb 100644
--- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java
+++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/registry/WebAuthProviderDescriptor.java
@@ -55,6 +55,7 @@ public class WebAuthProviderDescriptor extends AbstractDescriptor {
private final boolean trusted;
private final boolean isPrivate;
private final boolean isAuthHidden;
+ private final boolean isCaseInsensitive;
private final String[] requiredFeatures;
private final boolean isRequired;
private final String[] types;
@@ -69,6 +70,7 @@ public WebAuthProviderDescriptor(IConfigurationElement cfg) {
this.isPrivate = CommonUtils.toBoolean(cfg.getAttribute("private"));
this.isRequired = CommonUtils.toBoolean(cfg.getAttribute("required"));
this.isAuthHidden = CommonUtils.toBoolean(cfg.getAttribute("authHidden"));
+ this.isCaseInsensitive = CommonUtils.toBoolean(cfg.getAttribute("caseInsensitive"));
for (IConfigurationElement cfgElement : cfg.getChildren("configuration")) {
List properties = WebAuthProviderRegistry.readProperties(cfgElement);
@@ -132,6 +134,10 @@ public boolean isAuthHidden() {
return isAuthHidden;
}
+ public boolean isCaseInsensitive() {
+ return isCaseInsensitive;
+ }
+
public List getConfigurationParameters() {
return new ArrayList<>(configurationParameters.values());
}
diff --git a/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF
index eab0fb4e5a..3cc02705d6 100644
--- a/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Community Product
Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true
-Bundle-Version: 24.2.5.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 24.3.0.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.product.ce/pom.xml b/server/bundles/io.cloudbeaver.product.ce/pom.xml
index 2f72ef816c..19029a80e4 100644
--- a/server/bundles/io.cloudbeaver.product.ce/pom.xml
+++ b/server/bundles/io.cloudbeaver.product.ce/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.product.ce
- 24.2.5-SNAPSHOT
+ 24.3.0-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF
index d543d9254a..31f399616b 100644
--- a/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Base JDBC drivers
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
-Bundle-Version: 1.0.110.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.111.qualifier
+Bundle-Release-Date: 20241202
Bundle-Vendor: DBeaver Corp
Bundle-ActivationPolicy: lazy
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
diff --git a/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml b/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml
index da070a045f..d327cd569d 100644
--- a/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml
+++ b/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml
@@ -9,6 +9,6 @@
../
io.cloudbeaver.resources.drivers.base
- 1.0.110-SNAPSHOT
+ 1.0.111-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF
index 609e4ccc38..76578bc27f 100644
--- a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Server
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
-Bundle-Version: 24.2.5.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 24.3.0.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
diff --git a/server/bundles/io.cloudbeaver.server/pom.xml b/server/bundles/io.cloudbeaver.server/pom.xml
index c1df15d32f..e674aef409 100644
--- a/server/bundles/io.cloudbeaver.server/pom.xml
+++ b/server/bundles/io.cloudbeaver.server/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.server
- 24.2.5-SNAPSHOT
+ 24.3.0-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls
index db942decd4..a1d12c3dd5 100644
--- a/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls
+++ b/server/bundles/io.cloudbeaver.server/schema/service.sql.graphqls
@@ -86,6 +86,7 @@ type SQLResultColumn {
precision: Int
required: Boolean!
+ autoGenerated: Boolean!
readOnly: Boolean!
readOnlyStatus: String
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java
index 18fde20361..de0f13c5cc 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java
@@ -529,7 +529,7 @@ public synchronized void finishConfiguration(
}
if (isConfigurationMode()) {
- finishSecurityServiceConfiguration(adminName, adminPassword, authInfoList);
+ finishSecurityServiceConfiguration(adminName.toLowerCase(), adminPassword, authInfoList);
}
// Save runtime configuration
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java
index 2dac868a86..7af0f380c4 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBAbstractWebSocket.java
@@ -25,7 +25,7 @@
public class CBAbstractWebSocket extends Session.Listener.AbstractAutoDemanding {
private static final Log log = Log.getLog(CBAbstractWebSocket.class);
- protected static final Gson gson = WSUtils.gson;
+ protected static final Gson gson = WSUtils.clientGson;
public void handleEvent(WSEvent event) {
if (!isOpen()) {
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java
index bb9617728e..d2751c20e7 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java
@@ -99,6 +99,7 @@ public List getAuthModels(@NotNull WebSession webSession)
@Override
public List getNetworkHandlers(@NotNull WebSession webSession) {
return NetworkHandlerRegistry.getInstance().getDescriptors().stream()
+ .filter(d -> !d.isDesktopHandler())
.map(d -> new WebNetworkHandlerDescriptor(webSession, d)).collect(Collectors.toList());
}
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultColumn.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultColumn.java
index 9dfdc218c8..1f03d70e0b 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultColumn.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLQueryResultColumn.java
@@ -105,6 +105,11 @@ public boolean isRequired() {
return attrMeta.isRequired();
}
+ @Property
+ public boolean isAutoGenerated() {
+ return attrMeta.isAutoGenerated();
+ }
+
@Property
public boolean isReadOnly() {
return DBExecUtils.isAttributeReadOnly(attrMeta);
diff --git a/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF
index e1bf687cda..f753b33cdc 100644
--- a/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF
@@ -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.109.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.110.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.admin/pom.xml b/server/bundles/io.cloudbeaver.service.admin/pom.xml
index 7b69a7997d..71acee8ddf 100644
--- a/server/bundles/io.cloudbeaver.service.admin/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.admin/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.admin
- 1.0.109-SNAPSHOT
+ 1.0.110-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java
index 48e78992a3..51c959e209 100644
--- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java
+++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebServiceAdmin.java
@@ -161,12 +161,13 @@ public AdminUserInfo createUser(
if (userName.isEmpty()) {
throw new DBWebException("Empty user name");
}
- webSession.addInfoMessage("Create new user - " + userName);
+ String userId = userName.toLowerCase();
+ webSession.addInfoMessage("Create new user - " + userId);
try {
var securityController = webSession.getAdminSecurityController();
- securityController.createUser(userName, Map.of(), enabled, authRole);
- var smUser = securityController.getUserById(userName);
+ securityController.createUser(userId, Map.of(), enabled, authRole);
+ var smUser = securityController.getUserById(userId);
return new AdminUserInfo(webSession, new WebUser(smUser));
} catch (Exception e) {
throw new DBWebException("Error creating new user", e);
diff --git a/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF
index 62fff52e87..f54eb321f8 100644
--- a/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF
@@ -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.109.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.110.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.auth/pom.xml b/server/bundles/io.cloudbeaver.service.auth/pom.xml
index 943eb24778..972be7be9e 100644
--- a/server/bundles/io.cloudbeaver.service.auth/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.auth/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.auth
- 1.0.109-SNAPSHOT
+ 1.0.110-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF
index 4a317c4f3f..7c899f7153 100644
--- a/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF
@@ -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.110.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.111.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml b/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml
index ed68b1bc06..716f6f3734 100644
--- a/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.data.transfer
- 1.0.110-SNAPSHOT
+ 1.0.111-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF
index 12b77ec447..4c9a9b339a 100644
--- a/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.fs/META-INF/MANIFEST.MF
@@ -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.27.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.28.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.fs/pom.xml b/server/bundles/io.cloudbeaver.service.fs/pom.xml
index 016ae1e163..c1ae61238b 100644
--- a/server/bundles/io.cloudbeaver.service.fs/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.fs/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.fs
- 1.0.27-SNAPSHOT
+ 1.0.28-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/WebFSServlet.java b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/WebFSServlet.java
index fa2514c98f..9a39ba821d 100644
--- a/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/WebFSServlet.java
+++ b/server/bundles/io.cloudbeaver.service.fs/src/io/cloudbeaver/service/fs/model/WebFSServlet.java
@@ -31,7 +31,6 @@
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.navigator.fs.DBNPathBase;
-import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.IOUtils;
@@ -100,7 +99,7 @@ private void doPost(WebSession session, HttpServletRequest request, HttpServletR
}
} catch (Exception e) {
throw new DBWebException("File Upload Failed: Unable to Save File to the File System",
- GeneralUtils.getRootCause(e));
+ CommonUtils.getRootCause(e));
}
}
}
diff --git a/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF
index 6ba80756b2..5d88fe8e2d 100644
--- a/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF
@@ -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.113.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.114.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.metadata/pom.xml b/server/bundles/io.cloudbeaver.service.metadata/pom.xml
index 0a20df5524..1e1e2f3d33 100644
--- a/server/bundles/io.cloudbeaver.service.metadata/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.metadata/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.metadata
- 1.0.113-SNAPSHOT
+ 1.0.114-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF
index dbc5f5abb9..60f77cdf24 100644
--- a/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.rm.nio/META-INF/MANIFEST.MF
@@ -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.27.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.28.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml b/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml
index 97b4a6b2da..6457bd6f1e 100644
--- a/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.rm.nio/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.rm.nio
- 1.0.27-SNAPSHOT
+ 1.0.28-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF
index c2c7843837..8fc6de2a28 100644
--- a/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.rm/META-INF/MANIFEST.MF
@@ -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.62.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.63.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.rm/pom.xml b/server/bundles/io.cloudbeaver.service.rm/pom.xml
index 4ccace9c42..24653a9748 100644
--- a/server/bundles/io.cloudbeaver.service.rm/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.rm/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.rm
- 1.0.62-SNAPSHOT
+ 1.0.63-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF
index db16db1b1b..374682a3a2 100644
--- a/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.security/META-INF/MANIFEST.MF
@@ -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.65.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.66.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.security/plugin.xml b/server/bundles/io.cloudbeaver.service.security/plugin.xml
index e9ef310594..e4b77aab29 100644
--- a/server/bundles/io.cloudbeaver.service.security/plugin.xml
+++ b/server/bundles/io.cloudbeaver.service.security/plugin.xml
@@ -4,6 +4,7 @@
diff --git a/server/bundles/io.cloudbeaver.service.security/pom.xml b/server/bundles/io.cloudbeaver.service.security/pom.xml
index 18a205d5e0..b4567ab6b5 100644
--- a/server/bundles/io.cloudbeaver.service.security/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.security/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.security
- 1.0.65-SNAPSHOT
+ 1.0.66-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/local/LocalAuthProvider.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/local/LocalAuthProvider.java
index fce0269e82..60cf8809cc 100644
--- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/local/LocalAuthProvider.java
+++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/auth/provider/local/LocalAuthProvider.java
@@ -68,7 +68,9 @@ public String validateLocalAuth(@NotNull DBRProgressMonitor monitor,
throw new DBException("No user password provided");
}
String clientPasswordHash = AuthPropertyEncryption.hash.encrypt(userName, clientPassword);
- if (!storedPasswordHash.equals(clientPasswordHash)) {
+ // we also need to check a hash with lower case (CB-5833)
+ String clientPasswordHashLowerCase = AuthPropertyEncryption.hash.encrypt(userName.toLowerCase(), clientPassword);
+ if (!storedPasswordHash.equals(clientPasswordHash) && !clientPasswordHashLowerCase.equals(storedPasswordHash)) {
throw new DBException("Invalid user name or password");
}
diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java
index 3827bfa13a..68ba34ae9f 100644
--- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java
+++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java
@@ -116,6 +116,9 @@ private boolean isSubjectExists(String subjectId) throws DBCException {
///////////////////////////////////////////
// Users
+ /**
+ * Creates user. Saves user id in database in lower-case.
+ */
@Override
public void createUser(
@NotNull String userId,
@@ -126,6 +129,7 @@ public void createUser(
if (CommonUtils.isEmpty(userId)) {
throw new DBCException("Empty user name is not allowed");
}
+ userId = userId.toLowerCase(); // creating new users only with lowercase
if (isSubjectExists(userId)) {
throw new DBCException("User or team '" + userId + "' already exists");
}
@@ -140,6 +144,9 @@ public void createUser(
}
}
+ /**
+ * Creates user. Saves user id in database as it is.
+ */
public void createUser(
@NotNull Connection dbCon,
@NotNull String userId,
@@ -844,8 +851,13 @@ public void setUserCredentials(
}
List transformedCredentials;
WebAuthProviderDescriptor authProvider = getAuthProvider(authProviderId);
+ if (authProvider.isCaseInsensitive() && !isSubjectExists(userId) && isSubjectExists(userId.toLowerCase())) {
+ log.warn("User with id '" + userId + "' not found, credentials will be set for the user: " + userId.toLowerCase());
+ userId = userId.toLowerCase();
+ }
try {
SMAuthCredentialsProfile credProfile = getCredentialProfileByParameters(authProvider, credentials.keySet());
+ String finalUserId = userId;
transformedCredentials = credentials.entrySet().stream().map(cred -> {
String propertyName = cred.getKey();
AuthPropertyDescriptor property = credProfile.getCredentialParameter(propertyName);
@@ -853,7 +865,7 @@ public void setUserCredentials(
return null;
}
String encodedValue = CommonUtils.toString(cred.getValue());
- encodedValue = property.getEncryption().encrypt(userId, encodedValue);
+ encodedValue = property.getEncryption().encrypt(finalUserId, encodedValue);
return new String[]{propertyName, encodedValue};
}).toList();
} catch (Exception e) {
@@ -910,20 +922,38 @@ private String findUserByCredentials(
@NotNull WebAuthProviderDescriptor authProvider,
@NotNull Map authParameters,
boolean onlyActive // throws exception if user is inactive
+ ) throws DBException {
+ String userId = findUserByCredentials(authProvider, authParameters, onlyActive, false);
+ if (userId == null && authProvider.isCaseInsensitive()) {
+ // try to find user id with lower case is auth provider is case-insensitive
+ return findUserByCredentials(authProvider, authParameters, onlyActive, true);
+ }
+ return userId;
+ }
+
+ @Nullable
+ private String findUserByCredentials(
+ @NotNull WebAuthProviderDescriptor authProvider,
+ @NotNull Map authParameters,
+ boolean onlyActive,
+ boolean isCaseInsensitive
) throws DBCException {
- Map identCredentials = new LinkedHashMap<>();
+ Map identCredentials = new LinkedHashMap<>();
String[] propNames = authParameters.keySet().toArray(new String[0]);
for (AuthPropertyDescriptor prop : authProvider.getCredentialParameters(propNames)) {
if (prop.isIdentifying()) {
String propId = CommonUtils.toString(prop.getId());
- Object paramValue = authParameters.get(propId);
- if (paramValue == null) {
+ if (authParameters.get(propId) == null) {
throw new DBCException("Authentication parameter '" + prop.getId() + "' is missing");
}
if (prop.getEncryption() == AuthPropertyEncryption.hash) {
throw new DBCException("Hash encryption can't be used in identifying credentials");
}
- identCredentials.put(propId, paramValue);
+ String paramValue = CommonUtils.toString(authParameters.get(propId));
+ identCredentials.put(
+ propId,
+ isCaseInsensitive ? paramValue.toLowerCase() : paramValue
+ );
}
}
if (identCredentials.isEmpty()) {
@@ -947,9 +977,9 @@ private String findUserByCredentials(
try (PreparedStatement dbStat = dbCon.prepareStatement(database.normalizeTableNames(sql.toString()))) {
dbStat.setString(1, authProvider.getId());
int param = 2;
- for (Map.Entry credEntry : identCredentials.entrySet()) {
+ for (Map.Entry credEntry : identCredentials.entrySet()) {
dbStat.setString(param++, credEntry.getKey());
- dbStat.setString(param++, CommonUtils.toString(credEntry.getValue()));
+ dbStat.setString(param++, credEntry.getValue());
}
try (ResultSet dbResult = dbStat.executeQuery()) {
@@ -980,6 +1010,15 @@ private String findUserByCredentials(
@Override
public Map getUserCredentials(String userId, String authProviderId) throws DBCException {
WebAuthProviderDescriptor authProvider = getAuthProvider(authProviderId);
+ Map creds = getUserCredentials(authProvider, userId);
+ if (creds.isEmpty() && authProvider.isCaseInsensitive()) {
+ return getUserCredentials(authProvider, userId.toLowerCase());
+ }
+ return creds;
+ }
+
+ @NotNull
+ private Map getUserCredentials(WebAuthProviderDescriptor authProvider, String userId) throws DBCException {
try (Connection dbCon = database.openConnection()) {
try (PreparedStatement dbStat = dbCon.prepareStatement(
database.normalizeTableNames("SELECT CRED_ID,CRED_VALUE FROM {table_prefix}CB_USER_CREDENTIALS\n" +
@@ -990,7 +1029,6 @@ public Map getUserCredentials(String userId, String authProvider
try (ResultSet dbResult = dbStat.executeQuery()) {
Map credentials = new LinkedHashMap<>();
-
while (dbResult.next()) {
credentials.put(dbResult.getString(1), dbResult.getString(2));
}
@@ -1182,6 +1220,7 @@ public void createTeam(String teamId, String name, String description, String gr
if (CommonUtils.isEmpty(teamId)) {
throw new DBCException("Empty team name is not allowed");
}
+ teamId = teamId.toLowerCase();
if (isSubjectExists(teamId)) {
throw new DBCException("User or team '" + teamId + "' already exists");
}
@@ -2427,13 +2466,20 @@ private String findOrCreateExternalUserByCredentials(
return null;
}
- userId = userIdFromCredentials;
+ userId = authProvider.isCaseInsensitive() ? userIdFromCredentials.toLowerCase() : userIdFromCredentials;
if (!isSubjectExists(userId)) {
- createUser(userId,
- Map.of(),
- true,
- resolveUserAuthRole(null, authRole)
- );
+ log.debug("Create user: " + userId);
+ try (Connection dbCon = database.openConnection()) {
+ createUser(
+ dbCon,
+ userId,
+ Map.of(),
+ true,
+ resolveUserAuthRole(null, authRole)
+ );
+ } catch (SQLException e) {
+ throw new DBException("Error saving user in database", e);
+ }
}
setUserCredentials(userId, authProvider.getId(), userCredentials);
} else if (userId == null) {
diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java
index 17c42babb2..7f2879f4f6 100644
--- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java
+++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/db/CBDatabaseInitialData.java
@@ -17,6 +17,7 @@
package io.cloudbeaver.service.security.db;
import org.jkiss.dbeaver.model.security.user.SMTeam;
+import org.jkiss.utils.CommonUtils;
import java.util.List;
@@ -26,7 +27,7 @@ class CBDatabaseInitialData {
private List teams;
public String getAdminName() {
- return adminName;
+ return CommonUtils.isEmpty(adminName) ? null : adminName.toLowerCase();
}
public String getAdminPassword() {
diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/ClearAuthAttemptInfoJob.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/ClearAuthAttemptInfoJob.java
index 9c700dcca4..8eb28b5721 100644
--- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/ClearAuthAttemptInfoJob.java
+++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/ClearAuthAttemptInfoJob.java
@@ -23,7 +23,7 @@
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.runtime.AbstractJob;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
-import org.jkiss.dbeaver.utils.GeneralUtils;
+import org.jkiss.utils.CommonUtils;
public class ClearAuthAttemptInfoJob extends AbstractJob {
@@ -45,7 +45,7 @@ protected IStatus run(DBRProgressMonitor monitor) {
securityController.clearOldAuthAttemptInfo();
schedule(CHECK_PERIOD);
} catch (DBException e) {
- log.error("Error to clear the auth attempt info: " + GeneralUtils.getRootCause(e).getMessage());
+ log.error("Error to clear the auth attempt info: " + CommonUtils.getRootCause(e).getMessage());
// Check failed. Re-schedule after 5 seconds
schedule(RETRY_PERIOD);
}
diff --git a/server/bundles/io.cloudbeaver.slf4j/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.slf4j/META-INF/MANIFEST.MF
index 00ad68d5d8..7e877266d2 100644
--- a/server/bundles/io.cloudbeaver.slf4j/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.slf4j/META-INF/MANIFEST.MF
@@ -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.25.qualifier
-Bundle-Release-Date: 20241118
+Bundle-Version: 1.0.26.qualifier
+Bundle-Release-Date: 20241202
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.slf4j/pom.xml b/server/bundles/io.cloudbeaver.slf4j/pom.xml
index 96b8d8ab41..71d70e2ebd 100644
--- a/server/bundles/io.cloudbeaver.slf4j/pom.xml
+++ b/server/bundles/io.cloudbeaver.slf4j/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.slf4j
- 1.0.25-SNAPSHOT
+ 1.0.26-SNAPSHOT
eclipse-plugin
diff --git a/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml b/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml
index ec65c2a21a..16abcc7a31 100644
--- a/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml
+++ b/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml b/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml
index 6f1c5d6ca5..2b38e45be3 100644
--- a/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml
+++ b/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml
@@ -9,6 +9,6 @@
../
io.cloudbeaver.ce.drivers.feature
- 1.0.133-SNAPSHOT
+ 1.0.134-SNAPSHOT
eclipse-feature
diff --git a/server/features/io.cloudbeaver.product.ce.feature/feature.xml b/server/features/io.cloudbeaver.product.ce.feature/feature.xml
index 83817d2299..3c40e2869a 100644
--- a/server/features/io.cloudbeaver.product.ce.feature/feature.xml
+++ b/server/features/io.cloudbeaver.product.ce.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/server/features/io.cloudbeaver.product.ce.feature/pom.xml b/server/features/io.cloudbeaver.product.ce.feature/pom.xml
index 6e938928d4..5046d6a67a 100644
--- a/server/features/io.cloudbeaver.product.ce.feature/pom.xml
+++ b/server/features/io.cloudbeaver.product.ce.feature/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.product.ce.feature
- 24.2.5-SNAPSHOT
+ 24.3.0-SNAPSHOT
eclipse-feature
diff --git a/server/features/io.cloudbeaver.server.feature/feature.xml b/server/features/io.cloudbeaver.server.feature/feature.xml
index 9ed477595f..628631759f 100644
--- a/server/features/io.cloudbeaver.server.feature/feature.xml
+++ b/server/features/io.cloudbeaver.server.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/server/features/io.cloudbeaver.server.feature/pom.xml b/server/features/io.cloudbeaver.server.feature/pom.xml
index ca4d958756..cf2b93d852 100644
--- a/server/features/io.cloudbeaver.server.feature/pom.xml
+++ b/server/features/io.cloudbeaver.server.feature/pom.xml
@@ -10,6 +10,6 @@
../
io.cloudbeaver.server.feature
- 24.2.5-SNAPSHOT
+ 24.3.0-SNAPSHOT
eclipse-feature
diff --git a/server/features/io.cloudbeaver.ws.feature/feature.xml b/server/features/io.cloudbeaver.ws.feature/feature.xml
index 63f31ce8cb..ccbee9242a 100644
--- a/server/features/io.cloudbeaver.ws.feature/feature.xml
+++ b/server/features/io.cloudbeaver.ws.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/server/features/io.cloudbeaver.ws.feature/pom.xml b/server/features/io.cloudbeaver.ws.feature/pom.xml
index 6ae86adae8..03d179e748 100644
--- a/server/features/io.cloudbeaver.ws.feature/pom.xml
+++ b/server/features/io.cloudbeaver.ws.feature/pom.xml
@@ -10,6 +10,6 @@
../
io.cloudbeaver.ws.feature
- 1.0.63-SNAPSHOT
+ 1.0.64-SNAPSHOT
eclipse-feature
diff --git a/server/pom.xml b/server/pom.xml
index 43afd2610e..14cc87de26 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -19,7 +19,7 @@
CloudBeaver CE
- 24.2.5
+ 24.3.0
diff --git a/server/product/web-server/CloudbeaverServer.product b/server/product/web-server/CloudbeaverServer.product
index 03517f8893..abc42cf0ce 100644
--- a/server/product/web-server/CloudbeaverServer.product
+++ b/server/product/web-server/CloudbeaverServer.product
@@ -2,7 +2,7 @@
diff --git a/server/product/web-server/pom.xml b/server/product/web-server/pom.xml
index c508ad67b0..0218d3d2c9 100644
--- a/server/product/web-server/pom.xml
+++ b/server/product/web-server/pom.xml
@@ -9,7 +9,7 @@
1.0.0-SNAPSHOT
../../
- 24.2.5-SNAPSHOT
+ 24.3.0-SNAPSHOT
web-server
eclipse-repository
Cloudbeaver Server Product
diff --git a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/AuthenticationTest.java b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/AuthenticationTest.java
index d642b44e34..e2bebd4db8 100644
--- a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/AuthenticationTest.java
+++ b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/AuthenticationTest.java
@@ -16,15 +16,19 @@
*/
package io.cloudbeaver.test.platform;
+import io.cloudbeaver.auth.provider.local.LocalAuthProvider;
import io.cloudbeaver.auth.provider.rp.RPAuthProvider;
import io.cloudbeaver.test.WebGQLClient;
+import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.auth.SMAuthStatus;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
+import org.jkiss.utils.SecurityUtils;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
import java.util.Map;
+import java.util.Set;
public class AuthenticationTest {
private static final String GQL_OPEN_SESSION = """
@@ -39,6 +43,12 @@ mutation openSession($defaultLocale: String) {
userId
}
}""";
+ private static final String GQL_AUTH_LOGOUT = """
+ query authLogoutExtended($provider: ID, $configuration: ID) {
+ result: authLogoutExtended(provider: $provider, configuration: $configuration) {
+ redirectLinks
+ }
+ }""";
@Test
public void testLoginUser() throws Exception {
@@ -47,6 +57,34 @@ public void testLoginUser() throws Exception {
Assert.assertEquals(SMAuthStatus.SUCCESS.name(), JSONUtils.getString(authInfo, "authStatus"));
}
+
+ @Test
+ public void testLoginUserWithCamelCase() throws Exception {
+ WebGQLClient client = CEServerTestSuite.createClient();
+ for (String userId : Set.of("Test", "tESt", "tesT", "TEST")) {
+ Map credsWithCamelCase = getUserCredentials(userId);
+ // authenticating with user
+ Map authInfo = CEServerTestSuite.authenticateTestUser(client, credsWithCamelCase);
+ Assert.assertEquals(SMAuthStatus.SUCCESS.name(), JSONUtils.getString(authInfo, "authStatus"));
+ Map activeUser = client.sendQuery(GQL_ACTIVE_USER, null);
+ Assert.assertEquals(userId.toLowerCase(), JSONUtils.getString(activeUser, "userId"));
+ // making logout
+ client.sendQuery(GQL_AUTH_LOGOUT, Map.of("provider", "local"));
+
+ activeUser = client.sendQuery(GQL_ACTIVE_USER, null);
+ Assert.assertNotEquals(userId.toLowerCase(), JSONUtils.getString(activeUser, "userId"));
+ }
+ }
+
+ @NotNull
+ private Map getUserCredentials(@NotNull String userId) throws Exception {
+ return Map.of(
+ LocalAuthProvider.CRED_USER, userId,
+ LocalAuthProvider.CRED_PASSWORD, SecurityUtils.makeDigest("test")
+ );
+ }
+
+
@Test
public void testReverseProxyAnonymousModeLogin() throws Exception {
WebGQLClient client = CEServerTestSuite.createClient();
diff --git a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/CEServerTestSuite.java b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/CEServerTestSuite.java
index 3ca615b5ea..b133f1baa5 100644
--- a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/CEServerTestSuite.java
+++ b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/CEServerTestSuite.java
@@ -101,11 +101,18 @@ public static WebGQLClient createClient(@NotNull HttpClient httpClient) {
}
public static Map authenticateTestUser(@NotNull WebGQLClient client) throws Exception {
+ return authenticateTestUser(client, TEST_CREDENTIALS);
+ }
+
+ public static Map authenticateTestUser(
+ @NotNull WebGQLClient client,
+ @NotNull Map credentials
+ ) throws Exception {
return client.sendQuery(
WebGQLClient.GQL_AUTHENTICATE,
Map.of(
"provider", LocalAuthProvider.PROVIDER_ID,
- "credentials", TEST_CREDENTIALS
+ "credentials", credentials
)
);
}
diff --git a/webapp/packages/core-blocks/src/FormControls/FormContext.ts b/webapp/packages/core-blocks/src/FormControls/FormContext.ts
index a676cecee9..67b2fa5c05 100644
--- a/webapp/packages/core-blocks/src/FormControls/FormContext.ts
+++ b/webapp/packages/core-blocks/src/FormControls/FormContext.ts
@@ -11,7 +11,7 @@ import type { IExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
export type FormChangeValues = string | number | boolean | FileList | null | undefined;
export type FormChangeHandler = (value: FormChangeValues, name: string | undefined) => void;
-type KeyHandler = (event: React.KeyboardEvent) => void;
+type KeyHandler = (event: React.KeyboardEvent) => void;
export interface IChangeData {
value: FormChangeValues;
diff --git a/webapp/packages/core-blocks/src/FormControls/Textarea.tsx b/webapp/packages/core-blocks/src/FormControls/Textarea.tsx
index 929ddd47f5..68e8a71fe2 100644
--- a/webapp/packages/core-blocks/src/FormControls/Textarea.tsx
+++ b/webapp/packages/core-blocks/src/FormControls/Textarea.tsx
@@ -16,6 +16,7 @@ import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps.js';
import { useTranslate } from '../localization/useTranslate.js';
import { s } from '../s.js';
import { UploadArea } from '../UploadArea.js';
+import { useCombinedHandler } from '../useCombinedHandler.js';
import { useS } from '../useS.js';
import { Field } from './Field.js';
import { FieldDescription } from './FieldDescription.js';
@@ -63,6 +64,7 @@ export const Textarea: TextareaType = observer(function Textarea({
embedded,
cursorInitiallyAtEnd,
uploadable,
+ onKeyDown,
onChange = () => {},
...rest
}: ControlledProps | ObjectProps) {
@@ -72,6 +74,7 @@ export const Textarea: TextareaType = observer(function Textarea({
rest = filterLayoutFakeProps(rest);
const styles = useS(textareaStyle);
const context = useContext(FormContext);
+ const handleKeyDown = useCombinedHandler(onKeyDown, context?.keyDown);
const handleChange = useCallback(
(value: string) => {
@@ -110,6 +113,7 @@ export const Textarea: TextareaType = observer(function Textarea({
value={value ?? ''}
name={name}
data-embedded={embedded}
+ onKeyDown={handleKeyDown}
onChange={event => handleChange(event.target.value)}
/>
{description && {description}}
diff --git a/webapp/packages/core-blocks/src/FormControls/useForm.ts b/webapp/packages/core-blocks/src/FormControls/useForm.ts
index 50d67bb655..1ea664b631 100644
--- a/webapp/packages/core-blocks/src/FormControls/useForm.ts
+++ b/webapp/packages/core-blocks/src/FormControls/useForm.ts
@@ -78,10 +78,17 @@ export function useForm(options?: IOptions): IFormContext {
this.onChange.execute({ value, name });
}
},
- keyDown(event: React.KeyboardEvent) {
+ keyDown(event: React.KeyboardEvent) {
+ const isCtrlEnterSubmit =
+ event.key === 'Enter' &&
+ (event.ctrlKey || event.metaKey) &&
+ this.disableEnterSubmit === false &&
+ event.target instanceof HTMLTextAreaElement;
+ const isEnterSubmit = event.key === 'Enter' && this.disableEnterSubmit === false && event.target instanceof HTMLInputElement;
+
if (this.parent) {
this.parent.keyDown(event);
- } else if (event.key === 'Enter' && this.disableEnterSubmit === false) {
+ } else if (isCtrlEnterSubmit || isEnterSubmit) {
event.preventDefault();
if (this.ref) {
this.ref?.requestSubmit();
diff --git a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql
index 9b1ef04431..d0838d2eee 100644
--- a/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql
+++ b/webapp/packages/core-sdk/src/queries/grid/getSqlExecuteTaskResults.gql
@@ -22,6 +22,7 @@ mutation getSqlExecuteTaskResults($taskId: ID!) {
position
precision
required
+ autoGenerated
readOnly
readOnlyStatus
scale
diff --git a/webapp/packages/core-utils/src/index.ts b/webapp/packages/core-utils/src/index.ts
index 9344e0c195..e6da19c3d7 100644
--- a/webapp/packages/core-utils/src/index.ts
+++ b/webapp/packages/core-utils/src/index.ts
@@ -88,3 +88,4 @@ export * from './getProgressPercent.js';
export * from './types/UndefinedToNull.js';
export * from './bindFunctions.js';
export * from './getDomainFromUrl.js';
+export * from './isNumber.js';
diff --git a/webapp/packages/core-utils/src/isNumber.ts b/webapp/packages/core-utils/src/isNumber.ts
new file mode 100644
index 0000000000..df54dd65df
--- /dev/null
+++ b/webapp/packages/core-utils/src/isNumber.ts
@@ -0,0 +1,10 @@
+/*
+ * CloudBeaver - Cloud Database Manager
+ * Copyright (C) 2020-2024 DBeaver Corp and others
+ *
+ * Licensed under the Apache License, Version 2.0.
+ * you may not use this file except in compliance with the License.
+ */
+export function isNumber(value: any): boolean {
+ return !isNaN(parseFloat(value)) && isFinite(value);
+}
diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/Finish/FinishPage.module.css b/webapp/packages/plugin-administration/src/ConfigurationWizard/Finish/FinishPage.module.css
index b7372b3744..51ea02727a 100644
--- a/webapp/packages/plugin-administration/src/ConfigurationWizard/Finish/FinishPage.module.css
+++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/Finish/FinishPage.module.css
@@ -27,5 +27,5 @@
.message {
line-height: 2;
- white-space: pre;
+ white-space: pre-wrap;
}
diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.module.css b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.module.css
index 293ac777b5..fbccc496b0 100644
--- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.module.css
+++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.module.css
@@ -17,6 +17,10 @@
overflow: auto !important;
}
+.placeholder {
+ margin: 0 !important;
+}
+
.loader {
z-index: 2;
}
diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx
index 496c6fbf3b..122bff1dac 100644
--- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx
+++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/GrantedUsers/GrantedUsers.tsx
@@ -55,9 +55,11 @@ export const GrantedUsers: TabContainerPanelComponent = observer
if (isDefaultTeam) {
return (
-
-
- {translate('plugin_authentication_administration_team_default_users_tooltip')}
+
+
+
+ {translate('plugin_authentication_administration_team_default_users_tooltip')}
+
);
@@ -66,10 +68,12 @@ export const GrantedUsers: TabContainerPanelComponent = observer
return (
{() => (
-
+
{!users.resource.values.length ? (
-
- {translate('administration_teams_team_granted_users_empty')}
+
+
+ {translate('administration_teams_team_granted_users_empty')}
+
) : (
<>
diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx
index 23952f8c8a..3225b4f3d8 100644
--- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx
+++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/Teams/TeamsTable/TeamEdit.tsx
@@ -31,7 +31,7 @@ export const TeamEdit = observer(function TeamEdit({ item }) {
data.config.teamId = item;
return (
-
+
diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/AdministrationUserForm.tsx b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/AdministrationUserForm.tsx
index 89251c7f6e..19e56943b7 100644
--- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/AdministrationUserForm.tsx
+++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/AdministrationUserForm.tsx
@@ -77,7 +77,11 @@ export const AdministrationUserForm = observer(function AdministrationUse
{editing && (
-
+
)}