From 44077ad27a15f167d781d89eedbaef3ff4e7b2b7 Mon Sep 17 00:00:00 2001 From: Ivan Gagarkin Date: Tue, 24 Mar 2026 10:56:19 +0100 Subject: [PATCH 1/6] =?UTF-8?q?dbeaver/pro#8260=20Provide=20a=20method=20t?= =?UTF-8?q?o=20create=20or=20restore=20a=20`WebSession`=E2=80=A6=20(#4222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * dbeaver/pro#8260 Provide a method to create or restore a `WebSession` from `smAccessToken` * dbeaver/pro#8260 Annotations and constants --------- Co-authored-by: Ivan Gagarkin Co-authored-by: Serge Rider Co-authored-by: serge-rider --- .../service/session/CBSessionManager.java | 57 +++++++++++++ .../CBWebSocketServerConfigurator.java | 7 +- .../CBEmbeddedSecurityController.java | 5 +- .../security/internal/SMTokenInfo.java | 84 ------------------- 4 files changed, 63 insertions(+), 90 deletions(-) delete mode 100644 server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/SMTokenInfo.java diff --git a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/service/session/CBSessionManager.java b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/service/session/CBSessionManager.java index e23e4048d8..3f7cc84683 100644 --- a/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/service/session/CBSessionManager.java +++ b/server/bundles/io.cloudbeaver.server.ce/src/io/cloudbeaver/service/session/CBSessionManager.java @@ -379,6 +379,63 @@ public class CBSessionManager implements WebAppSessionManager { } } + @Nullable + public WebSession getWebSession( + @Nullable String smAccessToken, + @NotNull WebHttpRequestInfo requestInfo, + boolean create + ) throws DBException { + if (CommonUtils.isEmpty(smAccessToken)) { + return null; + } + synchronized (sessionMap) { + var tempCredProvider = new SMTokenCredentialProvider(smAccessToken); + SMAuthPermissions authPermissions = application.createSecurityController(tempCredProvider).getTokenPermissions(); + var sessionId = requestInfo.getId() != null ? requestInfo.getId() + : authPermissions.getSessionId(); + + var existSession = sessionMap.get(sessionId); + + if (existSession instanceof WebSession webSession) { + var creds = webSession.getUserContext().getActiveUserCredentials(); + if (creds == null || !smAccessToken.equals(creds.getSmAccessToken())) { + if (webSession.getUserContext().refresh( + smAccessToken, + null, + authPermissions + )) { + webSession.refreshUserData(); + } + } + return webSession; + } + if (existSession != null) { + //session exist but it not web session + return null; + } + if (!create) { + return null; + } + if (requestInfo.getId() == null) { + requestInfo = new WebHttpRequestInfo( + sessionId, + requestInfo.getLocale(), + requestInfo.getLastRemoteAddress(), + requestInfo.getLastRemoteUserAgent() + ); + } + var webSession = createWebSessionImpl(requestInfo); + webSession.getUserContext().refresh( + smAccessToken, + null, + authPermissions + ); + webSession.refreshUserData(); + sessionMap.put(sessionId, webSession); + return webSession; + } + } + /** * Send session state with remaining alive time to all cached session */ diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBWebSocketServerConfigurator.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBWebSocketServerConfigurator.java index d356fb4d2c..b427b9d73d 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBWebSocketServerConfigurator.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/websockets/CBWebSocketServerConfigurator.java @@ -24,7 +24,6 @@ import jakarta.websocket.HandshakeResponse; import jakarta.websocket.server.HandshakeRequest; import jakarta.websocket.server.ServerEndpointConfig; 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; import org.jkiss.dbeaver.DBException; @@ -89,7 +88,7 @@ public class CBWebSocketServerConfigurator extends ServerEndpointConfig.Configur throw new RuntimeException(e.getMessage(), e); } if (sec.getUserProperties().get(PROP_WEB_SESSION) == null) { - throw new BadMessageException("No web session found for websocket request"); + throw new RuntimeException("No web session found for websocket request"); } } @@ -97,8 +96,8 @@ public class CBWebSocketServerConfigurator extends ServerEndpointConfig.Configur private String getSessionId(@NotNull HandshakeRequest request) { // complex auth uses bearer authentication List authHeaders = WSClientUtils.getHeaders(request.getHeaders(), HttpConstants.HEADER_AUTHORIZATION); - if (!CommonUtils.isEmpty(authHeaders) && authHeaders.get(0).startsWith("Bearer ")) { - return authHeaders.get(0).substring(7); + if (!CommonUtils.isEmpty(authHeaders) && authHeaders.getFirst().startsWith(HttpConstants.BEARER_PREFIX)) { + return authHeaders.getFirst().substring(7); } return request.getHttpSession() instanceof HttpSession httpSession ? httpSession.getId() : null; } 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 b804cee4cf..bd7814e332 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 @@ -32,7 +32,6 @@ import io.cloudbeaver.service.security.bruteforce.UserLoginRecord; import io.cloudbeaver.service.security.db.CBDatabase; import io.cloudbeaver.service.security.internal.AuthAttemptSessionInfo; import io.cloudbeaver.service.security.internal.CBAuthSubjectRepo; -import io.cloudbeaver.service.security.internal.SMTokenInfo; import io.cloudbeaver.utils.WebEventUtils; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; @@ -2437,7 +2436,9 @@ public class CBEmbeddedSecurityController } } - private SMTokenInfo readAccessTokenInfo(String smAccessToken) throws DBException { + @NotNull + @Override + public SMTokenInfo readAccessTokenInfo(@NotNull String smAccessToken) throws DBException { try (Connection dbCon = database.openConnection(); PreparedStatement dbStat = dbCon.prepareStatement( """ diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/SMTokenInfo.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/SMTokenInfo.java deleted file mode 100644 index 50c06c18b3..0000000000 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/internal/SMTokenInfo.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2025 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.cloudbeaver.service.security.internal; - -import org.jkiss.code.NotNull; -import org.jkiss.code.Nullable; - -public class SMTokenInfo { - @NotNull - private final String accessToken; - - @NotNull - private final String refreshToken; - - @NotNull - private final String sessionId; - - @NotNull - private final String userId; - - @Nullable - private final String authRole; - private final boolean serviceToken; - - public SMTokenInfo( - @NotNull String accessToken, - @NotNull String refreshToken, - @NotNull String sessionId, - @NotNull String userId, - @Nullable String authRole, - boolean serviceToken - ) { - this.accessToken = accessToken; - this.refreshToken = refreshToken; - this.sessionId = sessionId; - this.userId = userId; - this.authRole = authRole; - this.serviceToken = serviceToken; - } - - @NotNull - public String getRefreshToken() { - return refreshToken; - } - - @NotNull - public String getSessionId() { - return sessionId; - } - - @NotNull - public String getUserId() { - return userId; - } - - @NotNull - public String getAccessToken() { - return accessToken; - } - - @Nullable - public String getAuthRole() { - return authRole; - } - - public boolean isServiceToken() { - return serviceToken; - } -} From a44ba89cd904d3d068463bad2aeefc4167df59b9 Mon Sep 17 00:00:00 2001 From: alex <48489896+devnaumov@users.noreply.github.com> Date: Tue, 24 Mar 2026 15:00:59 +0100 Subject: [PATCH 2/6] dbeaver/pro#8339 show array value as array (#4229) Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com> --- webapp/packages/core-sdk/src/getObjectPropertyValue.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/packages/core-sdk/src/getObjectPropertyValue.ts b/webapp/packages/core-sdk/src/getObjectPropertyValue.ts index b96e5652aa..761c796ced 100644 --- a/webapp/packages/core-sdk/src/getObjectPropertyValue.ts +++ b/webapp/packages/core-sdk/src/getObjectPropertyValue.ts @@ -24,7 +24,7 @@ export function getObjectPropertyDisplayValue(property: IObjectPropertyInfo) { return String(getValue(property.value, controlType)); } -function getValue(value: any, controlType: ObjectPropertyType) { +function getValue(value: any, controlType: ObjectPropertyType): any { const checkbox = controlType === 'checkbox'; if (value === null || value === undefined) { @@ -40,7 +40,7 @@ function getValue(value: any, controlType: ObjectPropertyType) { } if (Array.isArray(value)) { - return value.join(', '); + return `[${value.map(v => getValue(v, controlType)).join(', ')}]`; } return value.value || value.displayName || JSON.stringify(value); From 24a251cd5b5a39c665cf2750389fecbde9950c22 Mon Sep 17 00:00:00 2001 From: sergeyteleshev Date: Tue, 24 Mar 2026 16:43:43 +0100 Subject: [PATCH 3/6] [CB] Fix high CVE-2026-33228 in flatted (2) (#4228) --- webapp/package.json | 2 +- webapp/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index 74caa01911..2b49086829 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -24,7 +24,7 @@ "koa": ">=2.16.4", "immutable": ">=4.3.8", "serialize-javascript": ">=7.0.3", - "flatted": ">=3.4.0" + "flatted": ">=3.4.2" }, "scripts": { "test": "dbeaver-test", diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 1cedd0bb07..af485d524b 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -12693,10 +12693,10 @@ __metadata: languageName: node linkType: hard -"flatted@npm:>=3.4.0": - version: 3.4.1 - resolution: "flatted@npm:3.4.1" - checksum: 10c0/3987a7f1e39bc7215cece001354313b462cdb4fb2dde0df4f7acd9e5016fbae56ee6fb3f0870b2150145033be8bda4f01af6f87a00946049651131bbfca7dfa6 +"flatted@npm:>=3.4.2": + version: 3.4.2 + resolution: "flatted@npm:3.4.2" + checksum: 10c0/a65b67aae7172d6cdf63691be7de6c5cd5adbdfdfe2e9da1a09b617c9512ed794037741ee53d93114276bff3f93cd3b0d97d54f9b316e1e4885dde6e9ffdf7ed languageName: node linkType: hard From 9c36651aa070466105be4cf0fc61f48fe6fb2768 Mon Sep 17 00:00:00 2001 From: Sychev Andrey <44414066+SychevAndrey@users.noreply.github.com> Date: Tue, 24 Mar 2026 16:44:14 +0100 Subject: [PATCH 4/6] dbeaver/pro#8760 feat: set max width for search panel in SQL editor (#4231) Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com> --- webapp/common-react/@dbeaver/react-data-grid/src/DataGrid.css | 3 --- .../@dbeaver/ui-kit/src/SearchPanel/SearchPanel.css | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/webapp/common-react/@dbeaver/react-data-grid/src/DataGrid.css b/webapp/common-react/@dbeaver/react-data-grid/src/DataGrid.css index b1672cd663..25ca49bdf2 100644 --- a/webapp/common-react/@dbeaver/react-data-grid/src/DataGrid.css +++ b/webapp/common-react/@dbeaver/react-data-grid/src/DataGrid.css @@ -12,9 +12,6 @@ .rdg-search-panel { padding-bottom: 0 !important; - .search-panel__inputs { - max-width: var(--tw-container-lg); - } } .rdg-cell-search-match { diff --git a/webapp/common-react/@dbeaver/ui-kit/src/SearchPanel/SearchPanel.css b/webapp/common-react/@dbeaver/ui-kit/src/SearchPanel/SearchPanel.css index 902e714b60..6b293a2a78 100644 --- a/webapp/common-react/@dbeaver/ui-kit/src/SearchPanel/SearchPanel.css +++ b/webapp/common-react/@dbeaver/ui-kit/src/SearchPanel/SearchPanel.css @@ -52,6 +52,7 @@ flex-direction: column; flex: 1 1 420px; min-width: 120px; + max-width: var(--tw-container-lg); gap: calc(var(--tw-spacing) / 2); } From 9553c30ee520eebf046045c9e0ed1e6a17c85ddc Mon Sep 17 00:00:00 2001 From: Sychev Andrey <44414066+SychevAndrey@users.noreply.github.com> Date: Tue, 24 Mar 2026 19:26:36 +0100 Subject: [PATCH 5/6] =?UTF-8?q?dbeaver/pro#8739=20feat:=20add=20isEnabled?= =?UTF-8?q?=20option=20to=20tree=20filter=20for=20enhanc=E2=80=A6=20(#4236?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com> --- .../plugin-navigation-tree/src/TreeNew/useTreeFilter.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/webapp/packages/plugin-navigation-tree/src/TreeNew/useTreeFilter.ts b/webapp/packages/plugin-navigation-tree/src/TreeNew/useTreeFilter.ts index 7d6cc69fb2..2bf126dd49 100644 --- a/webapp/packages/plugin-navigation-tree/src/TreeNew/useTreeFilter.ts +++ b/webapp/packages/plugin-navigation-tree/src/TreeNew/useTreeFilter.ts @@ -16,6 +16,7 @@ import type { ITreeSettings } from './useTreeSettings.js'; export interface ITreeFilterOptions { isNodeMatched?: (nodeId: string, filter: string, isMatched: boolean) => boolean; + isEnabled?: boolean; } export interface ITreeFilter { @@ -38,10 +39,7 @@ interface ITreeFilterStateObject extends ITreeFilter, ITreeFilterState { settings?: ITreeSettings; } -export function useTreeFilter( - options: ITreeFilterOptions = {}, - settings?: ITreeSettings, -): ITreeFilterWithState { +export function useTreeFilter(options: ITreeFilterOptions = {}, settings?: ITreeSettings): ITreeFilterWithState { options = useObjectRef(options); const matchCache = new Map(); @@ -78,7 +76,7 @@ export function useTreeFilter( settings, filter: '', get enabled() { - return this.settings?.get(TREE_SETTINGS_FILTER_ENABLED) ?? false; + return this.settings?.get(TREE_SETTINGS_FILTER_ENABLED) ?? options.isEnabled ?? false; }, isNodeMatched(treeData: ITreeData, nodeId: string): boolean { const filter = this.filter.trim(); From 8b0a20cfd79a6b7e88799f52bcc59039d3fee667 Mon Sep 17 00:00:00 2001 From: Alexander Skoblikov Date: Wed, 25 Mar 2026 10:22:55 +0300 Subject: [PATCH 6/6] dbeaver/pro#8768 fix federated logout (#4230) Co-authored-by: kseniaguzeeva <112612526+kseniaguzeeva@users.noreply.github.com> --- .../src/io/cloudbeaver/utils/ServletAppUtils.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/ServletAppUtils.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/ServletAppUtils.java index e83ecaafcc..9edd4c98ac 100644 --- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/ServletAppUtils.java +++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/utils/ServletAppUtils.java @@ -193,8 +193,12 @@ public class ServletAppUtils { @NotNull String origin ) throws DBException { String finalOrigin = webAuthApplication.modifyOrigin(origin); - StringBuilder authUriBuilder = new StringBuilder(removeSideSlashes(finalOrigin)); String serviceUriSegment = removeSideSlashes(webAuthApplication.getAuthServiceUriSegment()); + String rootUri = removeSideSlashes(getServletApplication().getRootURI()); + if (finalOrigin.endsWith("/" + rootUri) && serviceUriSegment.startsWith(rootUri + "/")) { + finalOrigin = finalOrigin.substring(0, finalOrigin.length() - rootUri.length()); + } + StringBuilder authUriBuilder = new StringBuilder(removeSideSlashes(finalOrigin)); if (CommonUtils.isNotEmpty(serviceUriSegment)) { authUriBuilder.append("/").append(serviceUriSegment); }