From a7d90b311a2ef6dc5012ce5672bf4d6c2a0240d8 Mon Sep 17 00:00:00 2001 From: Ainur Date: Wed, 2 Sep 2026 15:29:48 +0200 Subject: [PATCH 1/6] dbeaver/pro#10451 Restrict configuration mode actions --- .../src/io/cloudbeaver/WebAction.java | 4 +- .../service/WebServiceBindingBase.java | 22 +++- .../service/core/DBWServiceCore.java | 16 +-- .../service/admin/DBWServiceAdmin.java | 8 +- .../service/auth/DBWServiceAuth.java | 4 +- .../test/platform/CEServerTestSuite.java | 3 + .../platform/ConfigurationModeAccessTest.java | 102 ++++++++++++++++++ 7 files changed, 140 insertions(+), 19 deletions(-) create mode 100644 server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebAction.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebAction.java index 24bcaa85b60..91620980a34 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebAction.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebAction.java @@ -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,4 +37,6 @@ String[] requireGlobalPermissions() default {}; + boolean configurationModeAllowed() default false; + } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java index 2fd72b53280..9dc56ab8da7 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java @@ -26,6 +26,7 @@ import io.cloudbeaver.model.cli.CloudbeaverCliConstants; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.model.session.WebSessionProvider; +import io.cloudbeaver.server.WebApplication; import io.cloudbeaver.server.WebAppUtils; import io.cloudbeaver.server.graphql.GraphQLEndpoint; import io.cloudbeaver.server.graphql.GraphQLLoggerUtil; @@ -83,6 +84,11 @@ protected API_TYPE getService(DataFetchingEnvironment env) { return apiInterface.cast(proxyImpl); } + @NotNull + protected WebApplication getApplication() { + return WebAppUtils.getWebPlatform().getApplication(); + } + @Nullable public static TypeDefinitionRegistry loadSchemaDefinition(@NotNull Class theClass, @Nullable String schemaPath) { if (schemaPath == null) { @@ -198,13 +204,18 @@ private class ServiceInvocationHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { try { + WebAction webAction = method.getAnnotation(WebAction.class); + WebApplication application = getApplication(); + if (application.isConfigurationMode() && + (webAction == null || !webAction.configurationModeAllowed())) { + throw new DBWebExceptionAccessDenied("Action is not available in server configuration mode"); + } WebActionSet actionSet = method.getDeclaringClass().getAnnotation(WebActionSet.class); if (actionSet != null) { checkServicePermissions(actionSet); } - WebAction webAction = method.getAnnotation(WebAction.class); if (webAction != null) { - checkActionPermissions(method, webAction); + checkActionPermissions(method, webAction, application); } WebProjectAction projectAction = method.getAnnotation(WebProjectAction.class); if (projectAction != null) { @@ -302,8 +313,11 @@ private void checkServicePermissions(WebActionSet actionSet) throws DBWebExcepti } } - private void checkActionPermissions(@NotNull Method method, @NotNull WebAction webAction) throws DBWebException { - var application = WebAppUtils.getWebPlatform().getApplication(); + private void checkActionPermissions( + @NotNull Method method, + @NotNull WebAction webAction, + @NotNull WebApplication application + ) throws DBWebException { if (application.isInitializationMode() && webAction.initializationRequired()) { String message = "Server initialization in progress: " + String.join(",", application.getInitActions().values()) + ".\nDo not restart the server."; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java index 58a0b50afff..cd788ee9f1e 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java @@ -38,7 +38,7 @@ */ public interface DBWServiceCore extends DBWService { - @WebAction(authRequired = false, initializationRequired = false) + @WebAction(authRequired = false, initializationRequired = false, configurationModeAllowed = true) WebServerConfig getServerConfig(@Nullable WebSession webSession) throws DBWebException; /** @@ -50,7 +50,7 @@ public interface DBWServiceCore extends DBWService { @WebAction WebGroupPropertiesInfo getProductSettings(@NotNull WebSession webSession); - @WebAction + @WebAction(configurationModeAllowed = true) List getDriverList(@NotNull WebSession webSession, String driverId) throws DBWebException; @WebAction @@ -70,20 +70,20 @@ List getUserConnections( List getConnectionFolders( @NotNull WebSession webSession, @Nullable String projectId, @Nullable String id) throws DBWebException; - @WebAction(authRequired = false) + @WebAction(authRequired = false, configurationModeAllowed = true) String[] getSessionPermissions(@NotNull WebSession webSession) throws DBWebException; /////////////////////////////////////////// // Session - @WebAction(authRequired = false) + @WebAction(authRequired = false, configurationModeAllowed = true) WebSession openSession( @NotNull WebSession webSession, @Nullable String defaultLocale, @NotNull HttpServletRequest servletRequest, @NotNull HttpServletResponse servletResponse) throws DBWebException; - @WebAction(authRequired = false) + @WebAction(authRequired = false, configurationModeAllowed = true) WebSession getSessionState(@NotNull WebSession webSession) throws DBWebException; @WebAction @@ -104,7 +104,7 @@ WebSession updateSession(@NotNull HttpServletRequest request, @NotNull HttpServl @WebAction(authRequired = false) boolean refreshSessionConnections(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws DBWebException; - @WebAction + @WebAction(configurationModeAllowed = true) boolean changeSessionLanguage(@NotNull WebSession webSession, String locale) throws DBWebException; /////////////////////////////////////////// @@ -240,10 +240,10 @@ Map setObjectSettingsForDatasource( /////////////////////////////////////////// // Async tasks - @WebAction(authRequired = false) + @WebAction(authRequired = false, configurationModeAllowed = true) WebAsyncTaskInfo getAsyncTaskInfo(WebSession webSession, String taskId, Boolean removeOnFinish) throws DBWebException; - @WebAction(authRequired = false) + @WebAction(authRequired = false, configurationModeAllowed = true) boolean cancelAsyncTask(WebSession webSession, String taskId) throws DBWebException; } diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java index 9ed058045e4..aad239f4cc4 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java @@ -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. @@ -132,7 +132,7 @@ boolean deleteUserCredentials( //////////////////////////////////////////////////////////////////// // Features - @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) + @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN, configurationModeAllowed = true) List listFeatureSets(@NotNull WebSession webSession) throws DBWebException; //////////////////////////////////////////////////////////////////// @@ -160,9 +160,9 @@ WebAuthProviderConfiguration saveAuthProviderConfiguration( //////////////////////////////////////////////////////////////////// // Server configuration - @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) + @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN, configurationModeAllowed = true) boolean configureServer(@NotNull WebSession webSession, @NotNull Map params) throws DBWebException; - @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) + @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN, configurationModeAllowed = true) boolean setDefaultNavigatorSettings(@NotNull WebSession webSession, @NotNull DBNBrowseSettings settings) throws DBWebException; @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN) diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java index 67a9df0d602..e61bc5a15d6 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java @@ -72,10 +72,10 @@ WebLogoutInfo authLogout( @Nullable String configurationId ) throws DBWebException; - @WebAction(authRequired = false) + @WebAction(authRequired = false, configurationModeAllowed = true) WebUserInfo activeUser(@NotNull WebSession webSession) throws DBWebException; - @WebAction(authRequired = false) + @WebAction(authRequired = false, configurationModeAllowed = true) WebAuthProviderInfo[] getAuthProviders(@NotNull HttpServletRequest request) throws DBWebException; @WebAction() 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 0f9379d9577..647251f06f1 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 @@ -28,6 +28,7 @@ import io.cloudbeaver.test.platform.admin.AdminLastLoginTimeTest; import io.cloudbeaver.test.platform.sql.*; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.platform.suite.api.SelectClasses; import org.junit.platform.suite.api.Suite; @@ -42,6 +43,7 @@ RMLockTest.class, RMNIOTest.class, NoSessionTest.class, + ConfigurationModeAccessTest.class, WebSessionTest.class, WebSessionProjectTest.class, WebNavigatorNodeInfoTest.class, @@ -60,6 +62,7 @@ public class CEServerTestSuite { @BeforeAll public static void startServer() throws Exception { CEAppStarter.startServerIfNotStarted(); + Assertions.assertFalse(CEAppStarter.getTestApp().isConfigurationMode()); } @AfterAll diff --git a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java new file mode 100644 index 00000000000..bfe2301b154 --- /dev/null +++ b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java @@ -0,0 +1,102 @@ +/* + * 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.test.platform; + +import graphql.GraphQLContext; +import graphql.schema.DataFetchingEnvironment; +import io.cloudbeaver.DBWebException; +import io.cloudbeaver.DBWebExceptionAccessDenied; +import io.cloudbeaver.DBWebExceptionServerNotInitialized; +import io.cloudbeaver.server.WebApplication; +import io.cloudbeaver.service.DBWBindingContext; +import io.cloudbeaver.service.WebServiceBindingBase; +import io.cloudbeaver.service.core.DBWServiceCore; +import org.jkiss.code.NotNull; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Map; + +public class ConfigurationModeAccessTest { + + @Test + public void configurationModeAccessIsDeniedByDefault() { + DBWServiceCore service = createService(false); + DBWebExceptionAccessDenied exception = Assertions.assertThrows( + DBWebExceptionAccessDenied.class, + () -> service.getUserConnections(null, null, null, null) + ); + Assertions.assertEquals("Action is not available in server configuration mode", exception.getMessage()); + Assertions.assertThrows( + DBWebExceptionAccessDenied.class, + () -> service.createConnection(null, null, Map.of()) + ); + } + + @Test + public void explicitlyAllowedActionIsAvailableInConfigurationMode() { + DBWServiceCore service = createService(false); + Assertions.assertDoesNotThrow(() -> service.getServerConfig(null)); + } + + @Test + public void initializationCheckIsAppliedToConfigurationModeActions() { + DBWServiceCore service = createService(true); + Assertions.assertThrows( + DBWebExceptionServerNotInitialized.class, + () -> service.getDriverList(null, null) + ); + } + + @NotNull + private static DBWServiceCore createService(boolean initializationMode) { + DataFetchingEnvironment environment = Mockito.mock(DataFetchingEnvironment.class); + Mockito.when(environment.getGraphQlContext()).thenReturn(GraphQLContext.newContext().build()); + + WebApplication application = Mockito.mock(WebApplication.class); + Mockito.when(application.isConfigurationMode()).thenReturn(true); + Mockito.when(application.isInitializationMode()).thenReturn(initializationMode); + Mockito.when(application.getInitActions()).thenReturn(Map.of()); + + return new TestBinding(Mockito.mock(DBWServiceCore.class), application).getServiceProxy(environment); + } + + private static class TestBinding extends WebServiceBindingBase { + private final WebApplication application; + + private TestBinding(@NotNull DBWServiceCore service, @NotNull WebApplication application) { + super(DBWServiceCore.class, service, null); + this.application = application; + } + + @NotNull + @Override + protected WebApplication getApplication() { + return application; + } + + @NotNull + private DBWServiceCore getServiceProxy(@NotNull DataFetchingEnvironment environment) { + return getService(environment); + } + + @Override + public void bindWiring(@NotNull DBWBindingContext model) throws DBWebException { + } + } +} From f54a52800665aa0f74630745e1e4ae2cd6bc7f0c Mon Sep 17 00:00:00 2001 From: Ainur Date: Wed, 2 Sep 2026 16:39:21 +0200 Subject: [PATCH 2/6] dbeaver/pro#10451 Fix configuration mode checks --- .../io.cloudbeaver.server/META-INF/MANIFEST.MF | 1 + .../service/WebServiceBindingBase.java | 5 +++-- .../service/core/DBWServiceCore.java | 18 ++++++++++++++---- .../service/admin/DBWServiceAdmin.java | 2 ++ .../service/auth/DBWServiceAuth.java | 2 ++ 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF index 5ed2f951a4c..fe3649da0c6 100644 --- a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF +++ b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF @@ -25,6 +25,7 @@ Export-Package: io.cloudbeaver, io.cloudbeaver.server.servlets, io.cloudbeaver.server.websockets, io.cloudbeaver.service, + io.cloudbeaver.service.core, io.cloudbeaver.service.navigator, io.cloudbeaver.service.sql Import-Package: org.slf4j diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java index 9dc56ab8da7..05203f7e5ea 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java @@ -26,8 +26,8 @@ import io.cloudbeaver.model.cli.CloudbeaverCliConstants; import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.model.session.WebSessionProvider; -import io.cloudbeaver.server.WebApplication; import io.cloudbeaver.server.WebAppUtils; +import io.cloudbeaver.server.WebApplication; import io.cloudbeaver.server.graphql.GraphQLEndpoint; import io.cloudbeaver.server.graphql.GraphQLLoggerUtil; import io.cloudbeaver.service.security.SMUtils; @@ -200,8 +200,9 @@ private class ServiceInvocationHandler implements InvocationHandler { this.env = env; } + @Nullable @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + public Object invoke(@NotNull Object proxy, @NotNull Method method, @Nullable Object[] args) throws Throwable { try { try { WebAction webAction = method.getAnnotation(WebAction.class); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java index cd788ee9f1e..4c105fc7aaa 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java @@ -38,6 +38,7 @@ */ public interface DBWServiceCore extends DBWService { + @NotNull @WebAction(authRequired = false, initializationRequired = false, configurationModeAllowed = true) WebServerConfig getServerConfig(@Nullable WebSession webSession) throws DBWebException; @@ -50,8 +51,9 @@ public interface DBWServiceCore extends DBWService { @WebAction WebGroupPropertiesInfo getProductSettings(@NotNull WebSession webSession); + @NotNull @WebAction(configurationModeAllowed = true) - List getDriverList(@NotNull WebSession webSession, String driverId) throws DBWebException; + List getDriverList(@NotNull WebSession webSession, @Nullable String driverId) throws DBWebException; @WebAction List getAuthModels(@NotNull WebSession webSession); @@ -70,12 +72,14 @@ List getUserConnections( List getConnectionFolders( @NotNull WebSession webSession, @Nullable String projectId, @Nullable String id) throws DBWebException; + @NotNull @WebAction(authRequired = false, configurationModeAllowed = true) String[] getSessionPermissions(@NotNull WebSession webSession) throws DBWebException; /////////////////////////////////////////// // Session + @NotNull @WebAction(authRequired = false, configurationModeAllowed = true) WebSession openSession( @NotNull WebSession webSession, @@ -83,6 +87,7 @@ WebSession openSession( @NotNull HttpServletRequest servletRequest, @NotNull HttpServletResponse servletResponse) throws DBWebException; + @NotNull @WebAction(authRequired = false, configurationModeAllowed = true) WebSession getSessionState(@NotNull WebSession webSession) throws DBWebException; @@ -105,7 +110,7 @@ WebSession updateSession(@NotNull HttpServletRequest request, @NotNull HttpServl boolean refreshSessionConnections(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws DBWebException; @WebAction(configurationModeAllowed = true) - boolean changeSessionLanguage(@NotNull WebSession webSession, String locale) throws DBWebException; + boolean changeSessionLanguage(@NotNull WebSession webSession, @Nullable String locale) throws DBWebException; /////////////////////////////////////////// // Connections @@ -240,10 +245,15 @@ Map setObjectSettingsForDatasource( /////////////////////////////////////////// // Async tasks + @NotNull @WebAction(authRequired = false, configurationModeAllowed = true) - WebAsyncTaskInfo getAsyncTaskInfo(WebSession webSession, String taskId, Boolean removeOnFinish) throws DBWebException; + WebAsyncTaskInfo getAsyncTaskInfo( + @NotNull WebSession webSession, + @NotNull String taskId, + @Nullable Boolean removeOnFinish + ) throws DBWebException; @WebAction(authRequired = false, configurationModeAllowed = true) - boolean cancelAsyncTask(WebSession webSession, String taskId) throws DBWebException; + boolean cancelAsyncTask(@NotNull WebSession webSession, @NotNull String taskId) throws DBWebException; } diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java index aad239f4cc4..0b2b2e8e6d2 100644 --- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java +++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/DBWServiceAdmin.java @@ -132,6 +132,7 @@ boolean deleteUserCredentials( //////////////////////////////////////////////////////////////////// // Features + @NotNull @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN, configurationModeAllowed = true) List listFeatureSets(@NotNull WebSession webSession) throws DBWebException; @@ -162,6 +163,7 @@ WebAuthProviderConfiguration saveAuthProviderConfiguration( @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN, configurationModeAllowed = true) boolean configureServer(@NotNull WebSession webSession, @NotNull Map params) throws DBWebException; + @WebAction(requirePermissions = DBWConstants.PERMISSION_ADMIN, configurationModeAllowed = true) boolean setDefaultNavigatorSettings(@NotNull WebSession webSession, @NotNull DBNBrowseSettings settings) throws DBWebException; diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java index e61bc5a15d6..5b87aeae613 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java @@ -72,9 +72,11 @@ WebLogoutInfo authLogout( @Nullable String configurationId ) throws DBWebException; + @Nullable @WebAction(authRequired = false, configurationModeAllowed = true) WebUserInfo activeUser(@NotNull WebSession webSession) throws DBWebException; + @NotNull @WebAction(authRequired = false, configurationModeAllowed = true) WebAuthProviderInfo[] getAuthProviders(@NotNull HttpServletRequest request) throws DBWebException; From 27ad447499646ea646750e3a28aed0a5c8ab6000 Mon Sep 17 00:00:00 2001 From: Ainur Date: Wed, 2 Sep 2026 16:50:52 +0200 Subject: [PATCH 3/6] dbeaver/pro#10451 Address static analysis findings --- .../src/io/cloudbeaver/WebAction.java | 3 +++ .../service/WebServiceBindingBase.java | 15 +++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebAction.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebAction.java index 91620980a34..214c140272f 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebAction.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/WebAction.java @@ -37,6 +37,9 @@ String[] requireGlobalPermissions() default {}; + /** + * Whether this action may be invoked while the server is being configured. + */ boolean configurationModeAllowed() default false; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java index 05203f7e5ea..8241acfd06c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java @@ -207,10 +207,7 @@ public Object invoke(@NotNull Object proxy, @NotNull Method method, @Nullable Ob try { WebAction webAction = method.getAnnotation(WebAction.class); WebApplication application = getApplication(); - if (application.isConfigurationMode() && - (webAction == null || !webAction.configurationModeAllowed())) { - throw new DBWebExceptionAccessDenied("Action is not available in server configuration mode"); - } + checkConfigurationModeAccess(webAction, application); WebActionSet actionSet = method.getDeclaringClass().getAnnotation(WebActionSet.class); if (actionSet != null) { checkServicePermissions(actionSet); @@ -303,6 +300,16 @@ private void checkObjectActionPermissions(Method method, WebProjectAction object } } + private void checkConfigurationModeAccess( + @Nullable WebAction webAction, + @NotNull WebApplication application + ) throws DBWebExceptionAccessDenied { + if (application.isConfigurationMode() && + (webAction == null || !webAction.configurationModeAllowed())) { + throw new DBWebExceptionAccessDenied("Action is not available in server configuration mode"); + } + } + private void checkServicePermissions(WebActionSet actionSet) throws DBWebException { String[] features = actionSet.requireFeatures(); ServletApplication servletApplication = ServletAppUtils.getServletApplication(); From 262eb710a87817b50c2a205a0c7a36d17e6470df Mon Sep 17 00:00:00 2001 From: Ainur Date: Wed, 2 Sep 2026 16:58:56 +0200 Subject: [PATCH 4/6] dbeaver/pro#10451 Fix Codacy findings --- .../io/cloudbeaver/service/WebServiceBindingBase.java | 9 +++------ .../test/platform/ConfigurationModeAccessTest.java | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java index 8241acfd06c..7c11c06699d 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java @@ -213,7 +213,7 @@ public Object invoke(@NotNull Object proxy, @NotNull Method method, @Nullable Ob checkServicePermissions(actionSet); } if (webAction != null) { - checkActionPermissions(method, webAction, application); + checkActionPermissions(method, webAction); } WebProjectAction projectAction = method.getAnnotation(WebProjectAction.class); if (projectAction != null) { @@ -321,11 +321,8 @@ private void checkServicePermissions(WebActionSet actionSet) throws DBWebExcepti } } - private void checkActionPermissions( - @NotNull Method method, - @NotNull WebAction webAction, - @NotNull WebApplication application - ) throws DBWebException { + private void checkActionPermissions(@NotNull Method method, @NotNull WebAction webAction) throws DBWebException { + var application = WebAppUtils.getWebPlatform().getApplication(); if (application.isInitializationMode() && webAction.initializationRequired()) { String message = "Server initialization in progress: " + String.join(",", application.getInitActions().values()) + ".\nDo not restart the server."; diff --git a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java index bfe2301b154..3a5e3428889 100644 --- a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java +++ b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java @@ -97,6 +97,7 @@ private DBWServiceCore getServiceProxy(@NotNull DataFetchingEnvironment environm @Override public void bindWiring(@NotNull DBWBindingContext model) throws DBWebException { + // No GraphQL wiring is needed to exercise the service proxy. } } } From ed7104223f086a939488693097af5bfae5ff4c64 Mon Sep 17 00:00:00 2001 From: Ainur Date: Wed, 2 Sep 2026 17:16:24 +0200 Subject: [PATCH 5/6] dbeaver/pro#10451 Use binding application for checks --- .../src/io/cloudbeaver/service/WebServiceBindingBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java index 7c11c06699d..9053ef2c978 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java @@ -322,7 +322,7 @@ private void checkServicePermissions(WebActionSet actionSet) throws DBWebExcepti } private void checkActionPermissions(@NotNull Method method, @NotNull WebAction webAction) throws DBWebException { - var application = WebAppUtils.getWebPlatform().getApplication(); + var application = getApplication(); if (application.isInitializationMode() && webAction.initializationRequired()) { String message = "Server initialization in progress: " + String.join(",", application.getInitActions().values()) + ".\nDo not restart the server."; From 26cdf6a6b433e61c474f467a48df38e89646c681 Mon Sep 17 00:00:00 2001 From: Ainur Date: Tue, 8 Sep 2026 12:36:29 +0200 Subject: [PATCH 6/6] dbeaver/pro#10451 Preserve proxy object methods --- .../io/cloudbeaver/service/WebServiceBindingBase.java | 3 +++ .../test/platform/ConfigurationModeAccessTest.java | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java index 9053ef2c978..f66ac67c89f 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java @@ -205,6 +205,9 @@ private class ServiceInvocationHandler implements InvocationHandler { public Object invoke(@NotNull Object proxy, @NotNull Method method, @Nullable Object[] args) throws Throwable { try { try { + if (method.getDeclaringClass() == Object.class) { + return method.invoke(impl, args); + } WebAction webAction = method.getAnnotation(WebAction.class); WebApplication application = getApplication(); checkConfigurationModeAccess(webAction, application); diff --git a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java index 3a5e3428889..6a1173dbf8f 100644 --- a/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java +++ b/server/test/io.cloudbeaver.test.platform/src/io/cloudbeaver/test/platform/ConfigurationModeAccessTest.java @@ -54,6 +54,16 @@ public void explicitlyAllowedActionIsAvailableInConfigurationMode() { Assertions.assertDoesNotThrow(() -> service.getServerConfig(null)); } + @Test + public void objectMethodsAreAvailableInConfigurationMode() { + DBWServiceCore service = createService(false); + Assertions.assertAll( + () -> Assertions.assertDoesNotThrow(service::toString), + () -> Assertions.assertDoesNotThrow(service::hashCode), + () -> Assertions.assertDoesNotThrow(() -> service.equals(service)) + ); + } + @Test public void initializationCheckIsAppliedToConfigurationModeActions() { DBWServiceCore service = createService(true);