From 44077ad27a15f167d781d89eedbaef3ff4e7b2b7 Mon Sep 17 00:00:00 2001 From: Ivan Gagarkin Date: Tue, 24 Mar 2026 10:56:19 +0100 Subject: [PATCH] =?UTF-8?q?dbeaver/pro#8260=20Provide=20a=20method=20to=20?= =?UTF-8?q?create=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; - } -}