diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java index 6490e677f7..fe70d479f1 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBAppConfig.java @@ -226,6 +226,11 @@ public class CBAppConfig { return plugins; } + public void setPlugins(@NotNull Map plugins) { + this.plugins.clear(); + this.plugins.putAll(plugins); + } + public Map getPluginConfig(@NotNull String pluginId) { return getPluginConfig(pluginId, false); } @@ -284,6 +289,13 @@ public class CBAppConfig { } } + public void setAuthProvidersConfiguration(@NotNull Map authProviders) { + synchronized (authConfiguration) { + authConfiguration.clear(); + authConfiguration.putAll(authProviders); + } + } + public boolean deleteAuthProviderConfiguration(@NotNull String id) { synchronized (authConfiguration) { return authConfiguration.remove(id) != null; 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 06839e7148..9bba030482 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 @@ -23,6 +23,7 @@ import com.google.gson.stream.JsonWriter; import io.cloudbeaver.DBWConnectionGrant; import io.cloudbeaver.DBWSecurityController; import io.cloudbeaver.WebServiceUtils; +import io.cloudbeaver.auth.provider.AuthProviderConfig; import io.cloudbeaver.model.session.WebAuthInfo; import io.cloudbeaver.registry.WebServiceRegistry; import io.cloudbeaver.server.jetty.CBJettyServer; @@ -173,7 +174,7 @@ public class CBApplication extends BaseApplicationImpl { String[] args = Platform.getCommandLineArgs(); for (int i = 0; i < args.length; i++) { - if (args[i].equals(CBConstants.CLI_PARAM_WEB_CONFIG) & args.length > i + 1) { + if (args[i].equals(CBConstants.CLI_PARAM_WEB_CONFIG) && args.length > i + 1) { configPath = args[i + 1]; break; } @@ -302,6 +303,7 @@ public class CBApplication extends BaseApplicationImpl { /** * Configures server automatically. * Called on startup + * * @param configPath */ protected void performAutoConfiguration(File configPath) { @@ -368,7 +370,7 @@ public class CBApplication extends BaseApplicationImpl { } boolean hasLoopbackAddress = false; - for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { + for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) { NetworkInterface intf = en.nextElement(); for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) { InetAddress localInetAddress = enumIpAddr.nextElement(); @@ -487,26 +489,40 @@ public class CBApplication extends BaseApplicationImpl { develMode = JSONUtils.getBoolean(serverConfig, CBConstants.PARAM_DEVEL_MODE, develMode); // App config - gson.fromJson( - gson.toJsonTree(JSONUtils.getObject(configProps, "app")), CBAppConfig.class); + Map appConfig = JSONUtils.getObject(configProps, "app"); + gson.fromJson(gson.toJsonTree(appConfig), CBAppConfig.class); // Database config - gson.fromJson( - gson.toJsonTree(JSONUtils.getObject(serverConfig, "database")), CBDatabaseConfig.class); + Map databaseConfig = JSONUtils.getObject(serverConfig, CBDatabase.PARAM_DB_CONFIGURATION); + gson.fromJson(gson.toJsonTree(databaseConfig), CBDatabaseConfig.class); productConfigPath = getRelativePath( - JSONUtils.getString(serverConfig, CBConstants.PARAM_PRODUCT_CONFIGURATION, CBConstants.DEFAULT_PRODUCT_CONFIGURATION), homeFolder); + JSONUtils.getString( + serverConfig, + CBConstants.PARAM_PRODUCT_CONFIGURATION, + CBConstants.DEFAULT_PRODUCT_CONFIGURATION + ), + homeFolder + ); } catch (IOException e) { log.error("Error parsing server configuration", e); } // Merge new config with old one { - Map mergedPlugins = Stream.concat(prevConfig.getPlugins().entrySet().stream(), - appConfiguration.getPlugins().entrySet().stream()).collect( - Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (o, o2) -> o2)); - appConfiguration.getPlugins().clear(); - appConfiguration.getPlugins().putAll(mergedPlugins); + Map mergedPlugins = Stream.concat( + prevConfig.getPlugins().entrySet().stream(), + appConfiguration.getPlugins().entrySet().stream() + ) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (o, o2) -> o2)); + appConfiguration.setPlugins(mergedPlugins); + + Map mergedAuthProviders = Stream.concat( + prevConfig.getAuthProviderConfigurations().entrySet().stream(), + appConfiguration.getAuthProviderConfigurations().entrySet().stream() + ) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (o, o2) -> o2)); + appConfiguration.setAuthProvidersConfiguration(mergedAuthProviders); } if (!CommonUtils.isEmpty(productConfigPath)) { @@ -605,8 +621,7 @@ public class CBApplication extends BaseApplicationImpl { @Nullable String adminPassword, @NotNull List authInfoList, long sessionExpireTime, - @NotNull CBAppConfig appConfig) throws DBException - { + @NotNull CBAppConfig appConfig) throws DBException { if (!RECONFIGURATION_ALLOWED && !isConfigurationMode()) { throw new DBException("Application must be in configuration mode"); } @@ -653,7 +668,7 @@ public class CBApplication extends BaseApplicationImpl { if (ArrayUtils.isEmpty(grants)) { securityController.setConnectionSubjectAccess( ds.getId(), - new String[] { anonymousRoleId }, + new String[]{anonymousRoleId}, adminName); } } @@ -662,8 +677,10 @@ public class CBApplication extends BaseApplicationImpl { } } - private void saveRuntimeConfig(String newServerName, String newServerURL, long sessionExpireTime, CBAppConfig appConfig) throws DBException { - + private void saveRuntimeConfig(String newServerName, + String newServerURL, + long sessionExpireTime, + CBAppConfig appConfig) throws DBException { File runtimeConfigFile = getRuntimeAppConfigFile(); try (Writer out = new OutputStreamWriter(new FileOutputStream(runtimeConfigFile), StandardCharsets.UTF_8)) { Gson gson = new GsonBuilder() @@ -673,71 +690,24 @@ public class CBApplication extends BaseApplicationImpl { try (JsonWriter json = gson.newJsonWriter(out)) { json.setLenient(true); json.beginObject(); - { - json.name("server"); - json.beginObject(); - if (!CommonUtils.isEmpty(newServerName)) { - JSONUtils.field(json, CBConstants.PARAM_SERVER_NAME, newServerName); - } - if (!CommonUtils.isEmpty(newServerURL)) { - JSONUtils.field(json, CBConstants.PARAM_SERVER_URL, newServerURL); - } - if (sessionExpireTime > 0) { - JSONUtils.field(json, CBConstants.PARAM_SESSION_EXPIRE_PERIOD, sessionExpireTime); - } - json.endObject(); + + Map serverMap = ConfigurationUtils.serverConfigToMap( + newServerName, + newServerURL, + sessionExpireTime, + databaseConfiguration + ); + if (!CommonUtils.isEmpty(serverMap)) { + JSONUtils.serializeProperties(json, "server", serverMap); } - { - json.name("app"); - json.beginObject(); - JSONUtils.field(json, "anonymousAccessEnabled", appConfig.isAnonymousAccessEnabled()); - JSONUtils.field(json, "supportsCustomConnections", appConfig.isSupportsCustomConnections()); - JSONUtils.field(json, "publicCredentialsSaveEnabled", appConfig.isPublicCredentialsSaveEnabled()); - JSONUtils.field(json, "adminCredentialsSaveEnabled", appConfig.isAdminCredentialsSaveEnabled()); - { - // Save only differences in def navigator settings - DBNBrowseSettings navSettings = appConfig.getDefaultNavigatorSettings(); - - json.name("defaultNavigatorSettings"); - json.beginObject(); - if (navSettings.isShowSystemObjects() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isShowSystemObjects()) - JSONUtils.field(json, "showSystemObjects", navSettings.isShowSystemObjects()); - if (navSettings.isShowUtilityObjects() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isShowUtilityObjects()) - JSONUtils.field(json, "showUtilityObjects", navSettings.isShowUtilityObjects()); - if (navSettings.isShowOnlyEntities() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isShowOnlyEntities()) - JSONUtils.field(json, "showOnlyEntities", navSettings.isShowOnlyEntities()); - if (navSettings.isMergeEntities() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isMergeEntities()) - JSONUtils.field(json, "mergeEntities", navSettings.isMergeEntities()); - if (navSettings.isHideFolders() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isHideFolders()) - JSONUtils.field(json, "hideFolders", navSettings.isHideFolders()); - if (navSettings.isHideSchemas() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isHideSchemas()) - JSONUtils.field(json, "hideSchemas", navSettings.isHideSchemas()); - if (navSettings.isHideVirtualModel() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isHideVirtualModel()) - JSONUtils.field(json, "hideVirtualModel", navSettings.isHideVirtualModel()); - - json.endObject(); - } - if (appConfig.getEnabledFeatures() != null) { - JSONUtils.serializeStringList(json, "enabledFeatures", Arrays.asList(appConfig.getEnabledFeatures()), true); - } - if (appConfig.getEnabledAuthProviders() != null) { - JSONUtils.serializeStringList(json, "enabledAuthProviders", Arrays.asList(appConfig.getEnabledAuthProviders()), true); - } - - if (!CommonUtils.isEmpty(appConfig.getPlugins())) { - JSONUtils.serializeProperties(json, "plugins", appConfig.getPlugins()); - } - if (!CommonUtils.isEmpty(appConfig.getAuthProviderConfigurations())) { - json.name("authConfiguration"); - gson.toJson(appConfig.getAuthProviderConfigurations(), Map.class, json); - } - - json.endObject(); + Map appMap = ConfigurationUtils.appConfigToMap(appConfig); + if (!CommonUtils.isEmpty(appMap)) { + JSONUtils.serializeProperties(json, "app", appMap); } + json.endObject(); } - } catch (IOException e) { throw new DBException("Error writing runtime configuration", e); } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBConstants.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBConstants.java index e175c22035..9f7968d277 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBConstants.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBConstants.java @@ -45,6 +45,8 @@ public class CBConstants { public static final String PARAM_DRIVERS_LOCATION = "driversLocation"; public static final String PARAM_WORKSPACE_LOCATION = "workspaceLocation"; public static final String PARAM_PRODUCT_CONFIGURATION = "productConfiguration"; + public static final String PARAM_RESOURCE_QUOTAS = "resourceQuotas"; + public static final String PARAM_AUTH_PROVIDERS = "authConfiguration"; public static final String PARAM_SESSION_EXPIRE_PERIOD = "expireSessionAfterPeriod"; @@ -82,5 +84,5 @@ public class CBConstants { public static final String CB_SESSION_COOKIE_NAME = "cb-session-id"; - public static final String APPLICATION_JSON = "application/json"; + public static final String APPLICATION_JSON = "application/json"; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabase.java index 4a8c7d73fe..e55c68c18e 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabase.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBDatabase.java @@ -72,6 +72,20 @@ public class CBDatabase { private static final String DEFAULT_DB_USER_NAME = "cb-data"; private static final String DEFAULT_DB_PWD_FILE = ".database-credentials.dat"; + static final String PARAM_DB_CONFIGURATION = "database"; + static final String PARAM_DB_DRIVER_CONFIGURATION = "driver"; + static final String PARAM_DB_URL_CONFIGURATION = "url"; + static final String PARAM_DB_USER_CONFIGURATION = "user"; + static final String PARAM_DB_PW_CONFIGURATION = "password"; + static final String PARAM_DB_CREATE_DATABASE_CONFIGURATION = "createDatabase"; + static final String PARAM_DB_ALLOW_PUBLIC_ACCESS_CONFIGURATION = "allowPublicAccess"; + static final String PARAM_DB_INITIAL_DATA_CONFIGURATION_CONFIGURATION = "initialDataConfiguration"; + static final String PARAM_DB_POOL_CONFIGURATION = "pool"; + static final String PARAM_DB_POOL_MIN_IDLE_CONNECTIONS_CONFIGURATION = "minIdleConnections"; + static final String PARAM_DB_POOL_MAX_IDLE_CONNECTIONS_CONFIGURATION = "maxIdleConnections"; + static final String PARAM_DB_POOL_MAX_CONNECTIONS_CONFIGURATION = "maxConnections"; + static final String PARAM_DB_POOL_VALIDATION_QUERY_CONFIGURATION = "validationQuery"; + private final CBApplication application; private final CBDatabaseConfig databaseConfiguration; private PoolingDataSource cbDataSource; diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/ConfigurationUtils.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/ConfigurationUtils.java new file mode 100644 index 0000000000..2396d05744 --- /dev/null +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/ConfigurationUtils.java @@ -0,0 +1,182 @@ +/* + * DBeaver - Universal Database Manager + * Copyright (C) 2010-2021 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.server; + +import io.cloudbeaver.auth.provider.AuthProviderConfig; +import org.jkiss.code.Nullable; +import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.model.data.json.JSONUtils; +import org.jkiss.dbeaver.model.navigator.DBNBrowseSettings; +import org.jkiss.utils.CommonUtils; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; + +public class ConfigurationUtils { + private static final Log log = Log.getLog(JSONUtils.class); + + private ConfigurationUtils() { + } + + public static Map appConfigToMap(@Nullable CBAppConfig appConfig) { + Map res = new LinkedHashMap<>(); + if (appConfig == null) { + return res; + } + res.put("anonymousAccessEnabled", appConfig.isAnonymousAccessEnabled()); + res.put("supportsCustomConnections", appConfig.isSupportsCustomConnections()); + res.put("publicCredentialsSaveEnabled", appConfig.isPublicCredentialsSaveEnabled()); + res.put("adminCredentialsSaveEnabled", appConfig.isAdminCredentialsSaveEnabled()); + + Map resourceQuotas = appConfig.getResourceQuotas(); + if (!CommonUtils.isEmpty(resourceQuotas)) { + res.put(CBConstants.PARAM_RESOURCE_QUOTAS, resourceQuotas); + } + + Map authProviders = appConfig.getAuthProviderConfigurations(); + if (!CommonUtils.isEmpty(authProviders)) { + res.put(CBConstants.PARAM_AUTH_PROVIDERS, authProviders); + } + + Map navSettingsMap = ConfigurationUtils.defaultNavigatorSettingsConfigToMap( + appConfig.getDefaultNavigatorSettings() + ); + if (!CommonUtils.isEmpty(navSettingsMap)) { + res.put("defaultNavigatorSettings", navSettingsMap); + } + + if (appConfig.getEnabledFeatures() != null) { + res.put("enabledFeatures", Arrays.asList(appConfig.getEnabledFeatures())); + } + if (appConfig.getEnabledAuthProviders() != null) { + res.put("enabledAuthProviders", Arrays.asList(appConfig.getEnabledAuthProviders())); + } + + if (!CommonUtils.isEmpty(appConfig.getPlugins())) { + res.put("plugins", appConfig.getPlugins()); + } + + return res; + } + + public static Map defaultNavigatorSettingsConfigToMap(@Nullable DBNBrowseSettings navSettings) { + Map res = new LinkedHashMap<>(); + if (navSettings == null) { + return res; + } + // Save only differences in def navigator settings + if (navSettings.isShowSystemObjects() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isShowSystemObjects()) { + res.put("showSystemObjects", navSettings.isShowSystemObjects()); + } + if (navSettings.isShowUtilityObjects() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isShowUtilityObjects()) { + res.put("showUtilityObjects", navSettings.isShowUtilityObjects()); + } + if (navSettings.isShowOnlyEntities() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isShowOnlyEntities()) { + res.put("showOnlyEntities", navSettings.isShowOnlyEntities()); + } + if (navSettings.isMergeEntities() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isMergeEntities()) { + res.put("mergeEntities", navSettings.isMergeEntities()); + } + if (navSettings.isHideFolders() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isHideFolders()) { + res.put("hideFolders", navSettings.isHideFolders()); + } + if (navSettings.isHideSchemas() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isHideSchemas()) { + res.put("hideSchemas", navSettings.isHideSchemas()); + } + if (navSettings.isHideVirtualModel() != CBAppConfig.DEFAULT_VIEW_SETTINGS.isHideVirtualModel()) { + res.put("hideVirtualModel", navSettings.isHideVirtualModel()); + } + return res; + } + + public static Map serverConfigToMap(String newServerName, + String newServerURL, + long sessionExpireTime, + CBDatabaseConfig databaseConfiguration) { + Map serverMap = new LinkedHashMap<>(); + if (!CommonUtils.isEmpty(newServerName)) { + serverMap.put(CBConstants.PARAM_SERVER_NAME, newServerName); + } + if (!CommonUtils.isEmpty(newServerURL)) { + serverMap.put(CBConstants.PARAM_SERVER_URL, newServerURL); + } + if (sessionExpireTime > 0) { + serverMap.put(CBConstants.PARAM_SESSION_EXPIRE_PERIOD, sessionExpireTime); + } + + Map dbMap = ConfigurationUtils.databaseConfigToMap(databaseConfiguration); + if (!CommonUtils.isEmpty(dbMap)) { + serverMap.put(CBDatabase.PARAM_DB_CONFIGURATION, dbMap); + } + return serverMap; + } + + public static Map databaseConfigToMap(@Nullable CBDatabaseConfig databaseConfiguration) { + Map res = new LinkedHashMap<>(); + if (databaseConfiguration == null) { + return res; + } + res.computeIfAbsent( + CBDatabase.PARAM_DB_DRIVER_CONFIGURATION, + v -> databaseConfiguration.getDriver() + ); + res.computeIfAbsent( + CBDatabase.PARAM_DB_URL_CONFIGURATION, + v -> databaseConfiguration.getUrl() + ); + res.computeIfAbsent( + CBDatabase.PARAM_DB_USER_CONFIGURATION, + v -> databaseConfiguration.getUser() + ); + res.computeIfAbsent( + CBDatabase.PARAM_DB_PW_CONFIGURATION, + v -> databaseConfiguration.getPassword() + ); + res.put(CBDatabase.PARAM_DB_CREATE_DATABASE_CONFIGURATION, databaseConfiguration.isCreateDatabase()); + res.put(CBDatabase.PARAM_DB_ALLOW_PUBLIC_ACCESS_CONFIGURATION, databaseConfiguration.isAllowPublicAccess()); + res.computeIfAbsent( + CBDatabase.PARAM_DB_INITIAL_DATA_CONFIGURATION_CONFIGURATION, + v -> databaseConfiguration.getInitialDataConfiguration() + ); + Map poolMap = ConfigurationUtils.poolDatabaseConfigToMap(databaseConfiguration); + if (!CommonUtils.isEmpty(poolMap)) { + res.put(CBDatabase.PARAM_DB_POOL_CONFIGURATION, poolMap); + } + return res; + } + + public static Map poolDatabaseConfigToMap(@Nullable CBDatabaseConfig databaseConfiguration) { + Map res = new LinkedHashMap<>(); + if (databaseConfiguration == null) { + return res; + } + CBDatabaseConfig.Pool pool = databaseConfiguration.getPool(); + if (pool == null) { + return res; + } else { + res.put(CBDatabase.PARAM_DB_POOL_MIN_IDLE_CONNECTIONS_CONFIGURATION, pool.getMinIdleConnections()); + res.put(CBDatabase.PARAM_DB_POOL_MAX_IDLE_CONNECTIONS_CONFIGURATION, pool.getMaxIdleConnections()); + res.put(CBDatabase.PARAM_DB_POOL_MAX_CONNECTIONS_CONFIGURATION, pool.getMaxConnections()); + res.computeIfAbsent( + CBDatabase.PARAM_DB_POOL_VALIDATION_QUERY_CONFIGURATION, + v -> pool.getValidationQuery() + ); + } + return res; + } +}