mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
CB-262 Server configuration mode implementation
This commit is contained in:
@@ -42,10 +42,18 @@ public class CBAppConfig {
|
||||
return authenticationEnabled;
|
||||
}
|
||||
|
||||
public void setAuthenticationEnabled(boolean authenticationEnabled) {
|
||||
this.authenticationEnabled = authenticationEnabled;
|
||||
}
|
||||
|
||||
public boolean isAnonymousAccessEnabled() {
|
||||
return anonymousAccessEnabled;
|
||||
}
|
||||
|
||||
public void setAnonymousAccessEnabled(boolean anonymousAccessEnabled) {
|
||||
this.anonymousAccessEnabled = anonymousAccessEnabled;
|
||||
}
|
||||
|
||||
public String getAnonymousUserRole() {
|
||||
return anonymousUserRole;
|
||||
}
|
||||
@@ -58,6 +66,10 @@ public class CBAppConfig {
|
||||
return supportsCustomConnections;
|
||||
}
|
||||
|
||||
public void setSupportsCustomConnections(boolean supportsCustomConnections) {
|
||||
this.supportsCustomConnections = supportsCustomConnections;
|
||||
}
|
||||
|
||||
public boolean isSupportsConnectionBrowser() {
|
||||
return supportsConnectionBrowser;
|
||||
}
|
||||
|
||||
@@ -19,11 +19,13 @@ package io.cloudbeaver.server;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import io.cloudbeaver.DBWSecurityController;
|
||||
import io.cloudbeaver.server.jetty.CBJettyServer;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.equinox.app.IApplicationContext;
|
||||
import org.eclipse.osgi.service.datalocation.Location;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.ModelPreferences;
|
||||
@@ -36,6 +38,7 @@ import org.jkiss.dbeaver.runtime.DBWorkbench;
|
||||
import org.jkiss.dbeaver.utils.GeneralUtils;
|
||||
import org.jkiss.dbeaver.utils.PrefUtils;
|
||||
import org.jkiss.dbeaver.utils.SystemVariablesResolver;
|
||||
import org.jkiss.utils.Base64;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
import org.jkiss.utils.StandardConstants;
|
||||
|
||||
@@ -160,7 +163,7 @@ public class CBApplication extends BaseApplicationImpl {
|
||||
try {
|
||||
loadConfiguration(configPath);
|
||||
|
||||
File runtimeConfigFile = new File(new File(workspaceLocation, CBConstants.RUNTIME_DATA_DIR_NAME), CBConstants.RUNTIME_CONFIG_FILE_NAME);
|
||||
File runtimeConfigFile = getRuntimeConfigFile();
|
||||
if (runtimeConfigFile.exists()) {
|
||||
log.debug("Runtime configuration [" + runtimeConfigFile.getAbsolutePath() + "]");
|
||||
parseConfiguration(runtimeConfigFile);
|
||||
@@ -240,6 +243,11 @@ public class CBApplication extends BaseApplicationImpl {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private File getRuntimeConfigFile() {
|
||||
return new File(new File(workspaceLocation, CBConstants.RUNTIME_DATA_DIR_NAME), CBConstants.RUNTIME_CONFIG_FILE_NAME);
|
||||
}
|
||||
|
||||
private void initializeDatabase() throws DBException {
|
||||
if (databaseConfiguration == null) {
|
||||
throw new DBException("Database configuration missing");
|
||||
@@ -379,18 +387,24 @@ public class CBApplication extends BaseApplicationImpl {
|
||||
return configurationMode;
|
||||
}
|
||||
|
||||
public synchronized void finishConfiguration() throws DBException {
|
||||
public synchronized void finishConfiguration(
|
||||
String newServerName,
|
||||
String adminName,
|
||||
String adminPassword,
|
||||
CBAppConfig appConfig) throws DBException
|
||||
{
|
||||
if (!isConfigurationMode()) {
|
||||
throw new DBException("Application must be in configuration mode");
|
||||
}
|
||||
|
||||
// Save runtime configuration
|
||||
log.debug("Saving runtime configuration");
|
||||
saveRuntimeConfig(newServerName, adminPassword, appConfig);
|
||||
|
||||
// Re-load runtime configuration
|
||||
try {
|
||||
log.debug("Reloading application configuration");
|
||||
File runtimeConfigFile = new File(new File(workspaceLocation, CBConstants.RUNTIME_DATA_DIR_NAME), CBConstants.RUNTIME_CONFIG_FILE_NAME);
|
||||
File runtimeConfigFile = getRuntimeConfigFile();
|
||||
if (runtimeConfigFile.exists()) {
|
||||
log.debug("Runtime configuration [" + runtimeConfigFile.getAbsolutePath() + "]");
|
||||
parseConfiguration(runtimeConfigFile);
|
||||
@@ -399,11 +413,50 @@ public class CBApplication extends BaseApplicationImpl {
|
||||
throw new DBException("Error parsing configuration", e);
|
||||
}
|
||||
// Re-create database
|
||||
database.finishConfiguration();
|
||||
database.finishConfiguration(adminName, adminPassword);
|
||||
|
||||
configurationMode = CommonUtils.isEmpty(serverName);
|
||||
}
|
||||
|
||||
private void saveRuntimeConfig(String newServerName, String dbPassword, CBAppConfig appConfig) throws DBException {
|
||||
|
||||
File runtimeConfigFile = getRuntimeConfigFile();
|
||||
try (Writer out = new OutputStreamWriter(new FileOutputStream(runtimeConfigFile), StandardCharsets.UTF_8)) {
|
||||
Gson gson = new GsonBuilder()
|
||||
.setLenient()
|
||||
.create();
|
||||
try (JsonWriter json = gson.newJsonWriter(out)) {
|
||||
json.beginObject();
|
||||
{
|
||||
json.name("server");
|
||||
json.beginObject();
|
||||
if (!CommonUtils.isEmpty(newServerName)) {
|
||||
JSONUtils.field(json, "serverName", newServerName);
|
||||
}
|
||||
if (!CommonUtils.isEmpty(dbPassword)) {
|
||||
json.name("database");
|
||||
json.beginObject();
|
||||
JSONUtils.field(json, "password", Base64.encode(dbPassword.getBytes()));
|
||||
json.endObject();
|
||||
}
|
||||
json.endObject();
|
||||
}
|
||||
{
|
||||
json.name("app");
|
||||
json.beginObject();
|
||||
if (appConfig.isAnonymousAccessEnabled()) JSONUtils.field(json, "anonymousAccessEnabled", true);
|
||||
if (appConfig.isAuthenticationEnabled()) JSONUtils.field(json, "authenticationEnabled", true);
|
||||
if (appConfig.isSupportsCustomConnections()) JSONUtils.field(json, "supportsCustomConnections", true);
|
||||
json.endObject();
|
||||
}
|
||||
json.endObject();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new DBException("Error writing runtime configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
public DBNBrowseSettings getDefaultNavigatorSettings() {
|
||||
return defaultNavigatorSettings;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.apache.commons.dbcp2.PoolableConnectionFactory;
|
||||
import org.apache.commons.dbcp2.PoolingDataSource;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.DBConstants;
|
||||
@@ -129,17 +130,21 @@ public class CBDatabase {
|
||||
checkDatabaseStructure();
|
||||
}
|
||||
|
||||
void finishConfiguration() throws DBException {
|
||||
void finishConfiguration(String adminName, String adminPassword) throws DBException {
|
||||
if (!application.isConfigurationMode()) {
|
||||
throw new DBException("Database is already configured");
|
||||
}
|
||||
if (cbDataSource != null) {
|
||||
log.debug("Drop embedded datasource");
|
||||
log.debug("Alter admin settings embedded datasource");
|
||||
try {
|
||||
// Drop database
|
||||
// Alter admin password
|
||||
try (Connection connection = cbDataSource.getConnection()) {
|
||||
try (Statement dbStat = connection.createStatement()) {
|
||||
dbStat.execute("DROP ALL OBJECTS DELETE FILES");
|
||||
dbStat.execute("ALTER USER " + databaseConfiguration.getUser() +
|
||||
" SET PASSWORD '" + databaseConfiguration.getPassword() + "'");
|
||||
}
|
||||
if (!CommonUtils.isEmpty(adminName) && !CommonUtils.isEmpty(adminPassword)) {
|
||||
createAdminUser(adminName, adminPassword);
|
||||
}
|
||||
}
|
||||
cbDataSource.close();
|
||||
@@ -272,50 +277,58 @@ public class CBDatabase {
|
||||
Gson gson = new GsonBuilder().setLenient().create();
|
||||
CBDatabaseInitialData initialData = gson.fromJson(reader, CBDatabaseInitialData.class);
|
||||
|
||||
WebUser adminUser = null;
|
||||
if (!CommonUtils.isEmpty(initialData.getAdminName())) {
|
||||
// Create admin user
|
||||
adminUser = new WebUser(initialData.getAdminName());
|
||||
serverController.createUser(adminUser);
|
||||
|
||||
String userPassword = initialData.getAdminPassword();
|
||||
|
||||
// This is how client password will be transmitted from client
|
||||
String clientPassword = LocalAuthProvider.makeClientPasswordHash(adminUser.getUserId(), userPassword);
|
||||
|
||||
Map<String, Object> credentials = new LinkedHashMap<>();
|
||||
credentials.put(LocalAuthProvider.CRED_USER, adminUser.getUserId());
|
||||
credentials.put(LocalAuthProvider.CRED_PASSWORD, clientPassword);
|
||||
|
||||
WebAuthProviderDescriptor authProvider = WebServiceRegistry.getInstance().getAuthProvider(LocalAuthProvider.PROVIDER_ID);
|
||||
if (authProvider != null) {
|
||||
serverController.setUserCredentials(adminUser.getUserId(), authProvider, credentials);
|
||||
}
|
||||
}
|
||||
|
||||
if (!CommonUtils.isEmpty(initialData.getRoles())) {
|
||||
// Create roles
|
||||
for (WebRole role : initialData.getRoles()) {
|
||||
serverController.createRole(role);
|
||||
if (adminUser != null) {
|
||||
serverController.setSubjectPermissions(role.getRoleId(), role.getPermissions().toArray(new String[0]), adminUser.getUserId());
|
||||
}
|
||||
// if (adminUser != null) {
|
||||
// serverController.setSubjectPermissions(role.getRoleId(), role.getPermissions().toArray(new String[0]), adminUser.getUserId());
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
if (adminUser != null) {
|
||||
// Grant all roles
|
||||
WebRole[] allRoles = serverController.readAllRoles();
|
||||
serverController.setUserRoles(
|
||||
adminUser.getUserId(),
|
||||
Arrays.stream(allRoles).map(WebRole::getRoleId).toArray(String[]::new),
|
||||
adminUser.getUserId());
|
||||
String adminName = initialData.getAdminName();
|
||||
String adminPassword = initialData.getAdminPassword();
|
||||
|
||||
if (!CommonUtils.isEmpty(adminName)) {
|
||||
// Create admin user
|
||||
createAdminUser(adminName, adminPassword);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Error loading initial data configuration", e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private WebUser createAdminUser(String adminName, String adminPassword) throws DBCException {
|
||||
DBWSecurityController serverController = application.getSecurityController();
|
||||
WebUser adminUser;
|
||||
adminUser = new WebUser(adminName);
|
||||
serverController.createUser(adminUser);
|
||||
|
||||
// This is how client password will be transmitted from client
|
||||
String clientPassword = LocalAuthProvider.makeClientPasswordHash(adminUser.getUserId(), adminPassword);
|
||||
|
||||
Map<String, Object> credentials = new LinkedHashMap<>();
|
||||
credentials.put(LocalAuthProvider.CRED_USER, adminUser.getUserId());
|
||||
credentials.put(LocalAuthProvider.CRED_PASSWORD, clientPassword);
|
||||
|
||||
WebAuthProviderDescriptor authProvider = WebServiceRegistry.getInstance().getAuthProvider(LocalAuthProvider.PROVIDER_ID);
|
||||
if (authProvider != null) {
|
||||
serverController.setUserCredentials(adminUser.getUserId(), authProvider, credentials);
|
||||
}
|
||||
|
||||
// Grant all roles
|
||||
WebRole[] allRoles = serverController.readAllRoles();
|
||||
serverController.setUserRoles(
|
||||
adminUser.getUserId(),
|
||||
Arrays.stream(allRoles).map(WebRole::getRoleId).toArray(String[]::new),
|
||||
adminUser.getUserId());
|
||||
|
||||
return adminUser;
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
log.debug("Shutdown database");
|
||||
if (cbDataSource != null) {
|
||||
|
||||
+15
-1
@@ -29,6 +29,7 @@ import io.cloudbeaver.registry.WebAuthProviderDescriptor;
|
||||
import io.cloudbeaver.registry.WebPermissionDescriptor;
|
||||
import io.cloudbeaver.registry.WebServiceDescriptor;
|
||||
import io.cloudbeaver.registry.WebServiceRegistry;
|
||||
import io.cloudbeaver.server.CBAppConfig;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.service.admin.*;
|
||||
@@ -297,7 +298,20 @@ public class WebServiceAdmin implements DBWServiceAdmin {
|
||||
|
||||
@Override
|
||||
public boolean configureServer(WebSession webSession, AdminServerConfig config) throws DBWebException {
|
||||
throw new DBWebException("Not implemented");
|
||||
try {
|
||||
CBAppConfig appConfig = new CBAppConfig();
|
||||
appConfig.setAnonymousAccessEnabled(config.isAnonymousAccessEnabled());
|
||||
appConfig.setAuthenticationEnabled(config.isAuthenticationEnabled());
|
||||
appConfig.setSupportsCustomConnections(config.isCustomConnectionsEnabled());
|
||||
CBApplication.getInstance().finishConfiguration(
|
||||
config.getServerName(),
|
||||
config.getAdminName(),
|
||||
config.getAdminPassword(),
|
||||
appConfig);
|
||||
} catch (Throwable e) {
|
||||
throw new DBWebException("Error configuring server", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user