mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
Merge branch 'devel' into 8518-cb-add-tolltip-for-the-bind-parameters-dialog
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
+57
@@ -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
|
||||
*/
|
||||
|
||||
+3
-4
@@ -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<String> 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;
|
||||
}
|
||||
|
||||
+3
-2
@@ -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<T extends ServletAuthApplication>
|
||||
}
|
||||
}
|
||||
|
||||
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(
|
||||
"""
|
||||
|
||||
-84
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,6 @@
|
||||
|
||||
.rdg-search-panel {
|
||||
padding-bottom: 0 !important;
|
||||
.search-panel__inputs {
|
||||
max-width: var(--tw-container-lg);
|
||||
}
|
||||
}
|
||||
|
||||
.rdg-cell-search-match {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<string, boolean>();
|
||||
|
||||
@@ -78,7 +76,7 @@ export function useTreeFilter(
|
||||
settings,
|
||||
filter: '',
|
||||
get enabled() {
|
||||
return this.settings?.get<boolean>(TREE_SETTINGS_FILTER_ENABLED) ?? false;
|
||||
return this.settings?.get<boolean>(TREE_SETTINGS_FILTER_ENABLED) ?? options.isEnabled ?? false;
|
||||
},
|
||||
isNodeMatched(treeData: ITreeData, nodeId: string): boolean {
|
||||
const filter = this.filter.trim();
|
||||
|
||||
+4
-4
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user