Skip to content

Commit

Permalink
Merge branch 'devel' into CB-5123-license-status-insufficient-amount-…
Browse files Browse the repository at this point in the history
…users
  • Loading branch information
DenisSinelnikov authored Aug 8, 2024
2 parents ee049ad + 36c089e commit 03b06f1
Show file tree
Hide file tree
Showing 21 changed files with 210 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
public interface WebApplication extends DBPApplication {
boolean isConfigurationMode();

default boolean isInitializationMode() {
return false;
}

WebAppConfiguration getAppConfiguration();

WebServerConfiguration getServerConfiguration();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ type ServerConfig {
localHostAddress: String

configurationMode: Boolean!
# initializationMode: Boolean! @since(version: "24.1.5")
developmentMode: Boolean!
redirectOnFederatedAuth: Boolean!
distributed: Boolean!
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@

boolean authRequired() default true;

boolean initializationRequired() default true;

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
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
Expand Down Expand Up @@ -108,6 +109,8 @@ public static CBApplication getInstance() {

private WebSessionManager sessionManager;

private final Map<String, String> initActions = new ConcurrentHashMap<>();

public CBApplication() {
this.homeDirectory = new File(initHomeFolder());
}
Expand Down Expand Up @@ -552,7 +555,8 @@ public synchronized void finishConfiguration(
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();
Expand Down Expand Up @@ -717,7 +721,10 @@ public Class<? extends DBPPlatformUI> getPlatformUIClass() {
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);
Expand Down Expand Up @@ -750,4 +757,21 @@ private void refreshDisabledDriversConfig() {
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -330,15 +330,15 @@ protected GsonBuilder getGsonBuilder() {
.registerTypeAdapter(PasswordPolicyConfiguration.class, smPasswordPoliceConfigCreator);
}

protected void saveRuntimeConfig(SMCredentialsProvider credentialsProvider) throws DBException {
public synchronized void saveRuntimeConfig(SMCredentialsProvider credentialsProvider) throws DBException {
saveRuntimeConfig(
serverConfiguration,
appConfiguration,
credentialsProvider
);
}

protected void saveRuntimeConfig(
protected synchronized void saveRuntimeConfig(
@NotNull CBServerConfig serverConfig,
@NotNull CBAppConfig appConfig,
SMCredentialsProvider credentialsProvider
Expand All @@ -350,7 +350,7 @@ protected void saveRuntimeConfig(
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);
Expand All @@ -370,7 +370,8 @@ private void writeRuntimeConfig(Path runtimeConfigPath, Map<String, Object> conf
}


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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ private void checkServicePermissions(Method method, WebActionSet actionSet) thro
}

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;
Expand All @@ -258,7 +264,6 @@ private void checkActionPermissions(@NotNull Method method, @NotNull WebAction w
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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*/
public interface DBWServiceCore extends DBWService {

@WebAction(authRequired = false)
@WebAction(authRequired = false, initializationRequired = false)
WebServerConfig getServerConfig() throws DBWebException;

@WebAction(authRequired = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,12 @@ public int deleteNodes(
DBCExecutionContext executionContext = getCommandExecutionContext(object);
DBECommandContext commandContext = new WebCommandContext(executionContext, false);
ne.getValue().deleteObject(commandContext, object, options);
commandContext.saveChanges(session.getProgressMonitor(), options);
try {
commandContext.saveChanges(session.getProgressMonitor(), options);
} catch (DBException e) {
commandContext.resetChanges(true);
throw e;
}
} else if (node instanceof DBNLocalFolder) {
var nodePath = node.getNodeItemPath();
node.getOwnerProject().getDataSourceRegistry().removeFolder(((DBNLocalFolder) node).getFolder(), false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -36,7 +38,7 @@ public static CBDatabase getDbInstance() {
/**
* Create new security controller instance with custom configuration
*/
public CBEmbeddedSecurityController createSecurityService(
public CBEmbeddedSecurityController<T> createSecurityService(
T application,
WebDatabaseConfig databaseConfig,
SMCredentialsProvider credentialsProvider,
Expand All @@ -45,32 +47,53 @@ public CBEmbeddedSecurityController createSecurityService(
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ public void close() throws SQLException {
// 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();
Expand Down Expand Up @@ -587,10 +587,24 @@ public SQLDialect getDialect() {
}

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public String getUser() {
return user;
}


@Override
public String getPassword() {
return password;
Expand All @@ -85,15 +86,15 @@ public String getSchema() {
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,10 @@ public void createTableWithAutoincrement() throws DBException {
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(
Expand Down
2 changes: 2 additions & 0 deletions webapp/packages/core-authentication/src/UserInfoResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
return authInfo as AuthInfo;
},
1000,
undefined,
5 * 60 * 1000,
);

const authInfo = await activeTask;
Expand Down
Loading

0 comments on commit 03b06f1

Please sign in to comment.