mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
CB-5375 auto migration to postgres DB for default CB EE configuration (#2809)
* CB-5375 auto migration to postgres DB for default CB EE configuration * CB-5375 fix test * CB-5375 move legacy db * CB-5474 async qm data migration * CB-5375 comment unused field --------- Co-authored-by: Evgenia Bezborodova <139753579+EvgeniaBzzz@users.noreply.github.com>
This commit is contained in:
co-authored by
Evgenia Bezborodova
parent
62393937fc
commit
36c089ed06
@@ -38,6 +38,7 @@ public class DBWebException extends DBException implements GraphQLError {
|
||||
|
||||
public static final String ERROR_CODE_SESSION_EXPIRED = "sessionExpired";
|
||||
public static final String ERROR_CODE_ACCESS_DENIED = "accessDenied";
|
||||
public static final String ERROR_CODE_SERVER_NOT_INITIALIZED = "serverNotInitialized";
|
||||
public static final String ERROR_CODE_LICENSE_DENIED = "licenseRequired";
|
||||
public static final String ERROR_CODE_IDENT_REQUIRED = "identRequired";
|
||||
public static final String ERROR_CODE_AUTH_REQUIRED = "authRequired";
|
||||
|
||||
@@ -42,6 +42,10 @@ import java.util.Map;
|
||||
public interface WebApplication extends DBPApplication {
|
||||
boolean isConfigurationMode();
|
||||
|
||||
default boolean isInitializationMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
WebAppConfiguration getAppConfiguration();
|
||||
|
||||
WebServerConfiguration getServerConfiguration();
|
||||
|
||||
@@ -148,6 +148,7 @@ type ServerConfig {
|
||||
localHostAddress: String
|
||||
|
||||
configurationMode: Boolean!
|
||||
# initializationMode: Boolean! @since(version: "24.1.5")
|
||||
developmentMode: Boolean!
|
||||
redirectOnFederatedAuth: Boolean!
|
||||
distributed: Boolean!
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 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;
|
||||
|
||||
/**
|
||||
* "Access denied" exception
|
||||
*/
|
||||
public class DBWebExceptionServerNotInitialized extends DBWebException {
|
||||
|
||||
public DBWebExceptionServerNotInitialized(String message) {
|
||||
super(message, ERROR_CODE_SERVER_NOT_INITIALIZED);
|
||||
}
|
||||
}
|
||||
@@ -33,4 +33,6 @@ public @interface WebAction {
|
||||
|
||||
boolean authRequired() default true;
|
||||
|
||||
boolean initializationRequired() default true;
|
||||
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ import java.security.Permission;
|
||||
import java.security.Policy;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* This class controls all aspects of the application's execution
|
||||
@@ -108,6 +109,8 @@ public abstract class CBApplication<T extends CBServerConfig> extends BaseWebApp
|
||||
|
||||
private WebSessionManager sessionManager;
|
||||
|
||||
private final Map<String, String> initActions = new ConcurrentHashMap<>();
|
||||
|
||||
public CBApplication() {
|
||||
this.homeDirectory = new File(initHomeFolder());
|
||||
}
|
||||
@@ -552,7 +555,8 @@ public abstract class CBApplication<T extends CBServerConfig> extends BaseWebApp
|
||||
reloadConfiguration(credentialsProvider);
|
||||
}
|
||||
|
||||
public synchronized void reloadConfiguration(@Nullable SMCredentialsProvider credentialsProvider) throws DBException {
|
||||
public synchronized void reloadConfiguration(@Nullable SMCredentialsProvider credentialsProvider)
|
||||
throws DBException {
|
||||
// Re-load runtime configuration
|
||||
try {
|
||||
Path runtimeAppConfigPath = getServerConfigurationController().getRuntimeAppConfigPath();
|
||||
@@ -717,7 +721,10 @@ public abstract class CBApplication<T extends CBServerConfig> extends BaseWebApp
|
||||
return CBPlatformUI.class;
|
||||
}
|
||||
|
||||
public void saveProductConfiguration(SMCredentialsProvider credentialsProvider, Map<String, Object> productConfiguration) throws DBException {
|
||||
public void saveProductConfiguration(
|
||||
SMCredentialsProvider credentialsProvider,
|
||||
Map<String, Object> productConfiguration
|
||||
) throws DBException {
|
||||
getServerConfigurationController().saveProductConfiguration(productConfiguration);
|
||||
flushConfiguration(credentialsProvider);
|
||||
sendConfigChangedEvent(credentialsProvider);
|
||||
@@ -750,4 +757,21 @@ public abstract class CBApplication<T extends CBServerConfig> extends BaseWebApp
|
||||
public boolean isEnvironmentVariablesAccessible() {
|
||||
return getAppConfiguration().isSystemVariablesResolvingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitializationMode() {
|
||||
return !initActions.isEmpty();
|
||||
}
|
||||
|
||||
public void addInitAction(@NotNull String actionId, @NotNull String description) {
|
||||
initActions.put(actionId, description);
|
||||
}
|
||||
|
||||
public void removeInitAction(@NotNull String actionId) {
|
||||
initActions.remove(actionId);
|
||||
}
|
||||
|
||||
public Map<String, String> getInitActions() {
|
||||
return Map.copyOf(initActions);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -330,7 +330,7 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
.registerTypeAdapter(PasswordPolicyConfiguration.class, smPasswordPoliceConfigCreator);
|
||||
}
|
||||
|
||||
protected void saveRuntimeConfig(SMCredentialsProvider credentialsProvider) throws DBException {
|
||||
public synchronized void saveRuntimeConfig(SMCredentialsProvider credentialsProvider) throws DBException {
|
||||
saveRuntimeConfig(
|
||||
serverConfiguration,
|
||||
appConfiguration,
|
||||
@@ -338,7 +338,7 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
);
|
||||
}
|
||||
|
||||
protected void saveRuntimeConfig(
|
||||
protected synchronized void saveRuntimeConfig(
|
||||
@NotNull CBServerConfig serverConfig,
|
||||
@NotNull CBAppConfig appConfig,
|
||||
SMCredentialsProvider credentialsProvider
|
||||
@@ -350,7 +350,7 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
writeRuntimeConfig(getRuntimeAppConfigPath(), configurationProperties);
|
||||
}
|
||||
|
||||
private void writeRuntimeConfig(Path runtimeConfigPath, Map<String, Object> configurationProperties)
|
||||
private synchronized void writeRuntimeConfig(Path runtimeConfigPath, Map<String, Object> configurationProperties)
|
||||
throws DBException {
|
||||
if (Files.exists(runtimeConfigPath)) {
|
||||
ContentUtils.makeFileBackup(runtimeConfigPath);
|
||||
@@ -370,7 +370,8 @@ public abstract class CBServerConfigurationController<T extends CBServerConfig>
|
||||
}
|
||||
|
||||
|
||||
public void updateServerUrl(@NotNull SMCredentialsProvider credentialsProvider, @Nullable String newPublicUrl) throws DBException {
|
||||
public synchronized void updateServerUrl(@NotNull SMCredentialsProvider credentialsProvider,
|
||||
@Nullable String newPublicUrl) throws DBException {
|
||||
getServerConfiguration().setServerURL(newPublicUrl);
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -250,6 +250,12 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
}
|
||||
|
||||
private void checkActionPermissions(@NotNull Method method, @NotNull WebAction webAction) throws DBWebException {
|
||||
CBApplication<?> application = CBApplication.getInstance();
|
||||
if (application.isInitializationMode() && webAction.initializationRequired()) {
|
||||
String message = "Server initialization in progress: "
|
||||
+ String.join(",", application.getInitActions().values()) + ".\nDo not restart the server.";
|
||||
throw new DBWebExceptionServerNotInitialized(message);
|
||||
}
|
||||
String[] reqPermissions = webAction.requirePermissions();
|
||||
if (reqPermissions.length == 0 && !webAction.authRequired()) {
|
||||
return;
|
||||
@@ -258,7 +264,6 @@ public abstract class WebServiceBindingBase<API_TYPE extends DBWService> impleme
|
||||
if (session == null) {
|
||||
throw new DBWebExceptionAccessDenied("No open session - anonymous access restricted");
|
||||
}
|
||||
CBApplication<?> application = CBApplication.getInstance();
|
||||
if (!application.isConfigurationMode()) {
|
||||
if (webAction.authRequired() && !session.isAuthorizedInSecurityManager()) {
|
||||
log.debug("Anonymous access to " + method.getName() + " restricted");
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ import java.util.Map;
|
||||
*/
|
||||
public interface DBWServiceCore extends DBWService {
|
||||
|
||||
@WebAction(authRequired = false)
|
||||
@WebAction(authRequired = false, initializationRequired = false)
|
||||
WebServerConfig getServerConfig() throws DBWebException;
|
||||
|
||||
@WebAction(authRequired = false)
|
||||
|
||||
@@ -13,7 +13,7 @@ Require-Bundle: org.jkiss.dbeaver.model;visibility:=reexport,
|
||||
org.jkiss.dbeaver.model.sql,
|
||||
org.jkiss.dbeaver.model.sql.jdbc,
|
||||
org.jkiss.dbeaver.registry;visibility:=reexport,
|
||||
org.jkiss.bundle.apache.dbcp,
|
||||
org.jkiss.bundle.apache.dbcp;visibility:=reexport,
|
||||
io.cloudbeaver.model
|
||||
Export-Package: io.cloudbeaver.auth.provider.local,
|
||||
io.cloudbeaver.auth.provider.rp,
|
||||
|
||||
+35
-12
@@ -16,10 +16,12 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.security;
|
||||
|
||||
import io.cloudbeaver.auth.NoAuthCredentialsProvider;
|
||||
import io.cloudbeaver.model.app.WebAuthApplication;
|
||||
import io.cloudbeaver.service.security.db.CBDatabase;
|
||||
import io.cloudbeaver.service.security.db.WebDatabaseConfig;
|
||||
import io.cloudbeaver.service.security.internal.ClearAuthAttemptInfoJob;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
|
||||
|
||||
@@ -36,7 +38,7 @@ public class EmbeddedSecurityControllerFactory<T extends WebAuthApplication> {
|
||||
/**
|
||||
* Create new security controller instance with custom configuration
|
||||
*/
|
||||
public CBEmbeddedSecurityController createSecurityService(
|
||||
public CBEmbeddedSecurityController<T> createSecurityService(
|
||||
T application,
|
||||
WebDatabaseConfig databaseConfig,
|
||||
SMCredentialsProvider credentialsProvider,
|
||||
@@ -45,32 +47,53 @@ public class EmbeddedSecurityControllerFactory<T extends WebAuthApplication> {
|
||||
if (DB_INSTANCE == null) {
|
||||
synchronized (EmbeddedSecurityControllerFactory.class) {
|
||||
if (DB_INSTANCE == null) {
|
||||
DB_INSTANCE = new CBDatabase(application, databaseConfig);
|
||||
DB_INSTANCE = createAndInitDatabaseInstance(
|
||||
application,
|
||||
databaseConfig,
|
||||
smConfig
|
||||
);
|
||||
}
|
||||
}
|
||||
var securityController = createEmbeddedSecurityController(
|
||||
application, DB_INSTANCE, credentialsProvider, smConfig
|
||||
);
|
||||
//FIXME circular dependency
|
||||
DB_INSTANCE.setAdminSecurityController(securityController);
|
||||
DB_INSTANCE.initialize();
|
||||
|
||||
if (application.isLicenseRequired()) {
|
||||
// delete expired auth info job in enterprise products
|
||||
new ClearAuthAttemptInfoJob(securityController).schedule();
|
||||
new ClearAuthAttemptInfoJob(createEmbeddedSecurityController(
|
||||
application, DB_INSTANCE, new NoAuthCredentialsProvider(), smConfig
|
||||
)).schedule();
|
||||
}
|
||||
return securityController;
|
||||
}
|
||||
return createEmbeddedSecurityController(
|
||||
application, DB_INSTANCE, credentialsProvider, smConfig
|
||||
);
|
||||
}
|
||||
|
||||
protected CBEmbeddedSecurityController createEmbeddedSecurityController(
|
||||
protected @NotNull CBDatabase createAndInitDatabaseInstance(
|
||||
@NotNull T application,
|
||||
@NotNull WebDatabaseConfig databaseConfig,
|
||||
@NotNull SMControllerConfiguration smConfig
|
||||
) throws DBException {
|
||||
var database = new CBDatabase(application, databaseConfig);
|
||||
var securityController = createEmbeddedSecurityController(
|
||||
application, database, new NoAuthCredentialsProvider(), smConfig
|
||||
);
|
||||
//FIXME circular dependency
|
||||
database.setAdminSecurityController(securityController);
|
||||
try {
|
||||
database.initialize();
|
||||
} catch (DBException e) {
|
||||
database.shutdown();
|
||||
throw e;
|
||||
}
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
protected CBEmbeddedSecurityController<T> createEmbeddedSecurityController(
|
||||
T application,
|
||||
CBDatabase database,
|
||||
SMCredentialsProvider credentialsProvider,
|
||||
SMControllerConfiguration smConfig
|
||||
) {
|
||||
return new CBEmbeddedSecurityController(application, database, credentialsProvider, smConfig);
|
||||
return new CBEmbeddedSecurityController<T>(application, database, credentialsProvider, smConfig);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-3
@@ -475,7 +475,7 @@ public class CBDatabase {
|
||||
// Persistence
|
||||
|
||||
|
||||
private void validateInstancePersistentState(Connection connection) throws IOException, SQLException, DBException {
|
||||
protected void validateInstancePersistentState(Connection connection) throws IOException, SQLException, DBException {
|
||||
try (JDBCTransaction txn = new JDBCTransaction(connection)) {
|
||||
checkInstanceRecord(connection);
|
||||
var defaultTeamId = application.getAppConfiguration().getDefaultUserTeam();
|
||||
@@ -587,10 +587,24 @@ public class CBDatabase {
|
||||
}
|
||||
|
||||
public static boolean isDefaultH2Configuration(WebDatabaseConfig databaseConfiguration) {
|
||||
var v1DefaultUrl = "jdbc:h2:/opt/cloudbeaver/workspace/.data/" + V1_DB_NAME;
|
||||
var v2DefaultUrl = "jdbc:h2:/opt/cloudbeaver/workspace/.data/" + V2_DB_NAME;
|
||||
var workspace = WebAppUtils.getWebApplication().getWorkspaceDirectory();
|
||||
var v1Path = workspace.resolve(".data").resolve(V1_DB_NAME);
|
||||
var v2Path = workspace.resolve(".data").resolve(V2_DB_NAME);
|
||||
var v1DefaultUrl = "jdbc:h2:" + v1Path;
|
||||
var v2DefaultUrl = "jdbc:h2:" + v2Path;
|
||||
return v1DefaultUrl.equals(databaseConfiguration.getUrl())
|
||||
|| v2DefaultUrl.equals(databaseConfiguration.getUrl());
|
||||
}
|
||||
|
||||
protected WebDatabaseConfig getDatabaseConfiguration() {
|
||||
return databaseConfiguration;
|
||||
}
|
||||
|
||||
protected WebApplication getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
protected SMAdminController getAdminSecurityController() {
|
||||
return adminSecurityController;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -63,6 +63,7 @@ public class WebDatabaseConfig implements InternalDatabaseConfig {
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return password;
|
||||
@@ -85,15 +86,15 @@ public class WebDatabaseConfig implements InternalDatabaseConfig {
|
||||
return schema;
|
||||
}
|
||||
|
||||
void setPassword(String password) {
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
void setSchema(String schema) {
|
||||
public void setSchema(String schema) {
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
void setUser(String user) {
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -162,8 +162,10 @@ public class SQLQueryTranslatorTest {
|
||||
Map<SQLDialect, String> expectedSqlByDialect = new HashMap<>();
|
||||
expectedSqlByDialect.put(new H2SQLDialect(), basicSql);
|
||||
expectedSqlByDialect.put(new PostgreDialect(), "CREATE SEQUENCE CB_TEST_TYPES_AUTOINC_COLUMN;\n" +
|
||||
"CREATE TABLE CB_TEST_TYPES (AUTOINC_COLUMN BIGINT NOT NULL DEFAULT NEXTVAL('CB_TEST_TYPES_AUTOINC_COLUMN'));" +
|
||||
"\n");
|
||||
"CREATE TABLE CB_TEST_TYPES (AUTOINC_COLUMN BIGINT NOT NULL DEFAULT NEXTVAL" +
|
||||
"('CB_TEST_TYPES_AUTOINC_COLUMN'));\n" +
|
||||
"ALTER SEQUENCE CB_TEST_TYPES_AUTOINC_COLUMN OWNED BY CB_TEST_TYPES.AUTOINC_COLUMN;\n"
|
||||
);
|
||||
expectedSqlByDialect.put(new MySQLDialect(), basicSql);
|
||||
|
||||
expectedSqlByDialect.put(
|
||||
|
||||
Reference in New Issue
Block a user