Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CB-5774. Implemented bruteforce block logic, implemented user info block logic #3203

Open
wants to merge 35 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9157d1e
CB-5774. Create mock for front-end
DenisSinelnikov Jan 21, 2025
f7f4596
CB-5574 adds disabled user info
sergeyteleshev Jan 22, 2025
82e6d6d
CB-5574 cleanup
sergeyteleshev Jan 22, 2025
128ae05
CB-5574 build fix
sergeyteleshev Jan 22, 2025
482772d
CB-5574 build fix
sergeyteleshev Jan 22, 2025
73ce84f
Merge branch 'devel' into CB-5774-connection-brute-force-policy
DenisSinelnikov Jan 22, 2025
17e3f15
CB-5774. Implemented bruteforce block logic, implemented user info bl…
DenisSinelnikov Jan 22, 2025
1ad6237
Merge branch 'devel' into CB-5774-connection-brute-force-policy
DenisSinelnikov Jan 23, 2025
e560005
CB-5774. Added event, refactor get username query
DenisSinelnikov Jan 23, 2025
1240fd6
CB-5774. Fixed tests
DenisSinelnikov Jan 23, 2025
1e487d1
CB-5774. Fixed tests
DenisSinelnikov Jan 23, 2025
8c6675d
Update webapp/packages/plugin-authentication-administration/src/Admin…
sergeyteleshev Jan 23, 2025
50ae1da
CB-5774. Refactor after review
DenisSinelnikov Jan 23, 2025
22049e5
Merge remote-tracking branch 'origin/CB-5774-connection-brute-force-p…
DenisSinelnikov Jan 23, 2025
4eb39e8
Merge branch 'devel' into CB-5774-connection-brute-force-policy
DenisSinelnikov Jan 23, 2025
fbcf7aa
CB-5774. Refactor after review
DenisSinelnikov Jan 23, 2025
7307635
CB-6165. Refactor after review
DenisSinelnikov Jan 23, 2025
dc0e5d8
CB-5774. Refactor after review
DenisSinelnikov Jan 23, 2025
a92cf15
Merge branch 'devel' into CB-5774-connection-brute-force-policy
EvgeniaBzzz Jan 24, 2025
ec79554
CB-5774. Fixed log-in after enable user, rename column, added new par…
DenisSinelnikov Jan 24, 2025
717e907
Merge branch 'devel' into CB-5774-connection-brute-force-policy
EvgeniaBzzz Jan 27, 2025
142a772
Merge branch 'devel' into CB-5774-connection-brute-force-policy
DenisSinelnikov Jan 28, 2025
2af40fa
CB-5574. Fixed bruteforce protection for init connection
DenisSinelnikov Jan 30, 2025
ec29a48
CB-5774. Fixed count and throw exception for block
DenisSinelnikov Jan 30, 2025
a2a5264
CB-5774. Refactor after review
DenisSinelnikov Jan 31, 2025
e9076c9
Merge branch 'devel' into CB-5774-connection-brute-force-policy
DenisSinelnikov Jan 31, 2025
10fe8aa
CB-5774. Refactor after review
DenisSinelnikov Jan 31, 2025
01df914
CB-5774. Refactor after review
DenisSinelnikov Jan 31, 2025
93e60a3
CB-5774. Refactor after review
DenisSinelnikov Jan 31, 2025
9b1a3e3
CB-5774 wip
yagudin10 Feb 3, 2025
28250e5
Merge branch 'devel' into CB-5774-connection-brute-force-policy
EvgeniaBzzz Feb 4, 2025
42443db
CB-5774 create web qm embedded service wip
yagudin10 Feb 5, 2025
f919682
Merge branch 'devel' into CB-5774-connection-brute-force-policy
yagudin10 Feb 11, 2025
cb4ad88
Merge remote-tracking branch 'origin/CB-5774-connection-brute-force-p…
yagudin10 Feb 11, 2025
a8c7694
CB-5774 block user in qm side
yagudin10 Feb 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion config/core/cloudbeaver.conf
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@

sm: {
enableBruteForceProtection: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_ENABLED:true}",
maxFailedLogin: "${CLOUDBEAVER_MAX_FAILED_LOGINS:10}",
enableConnectionBruteForceProtection: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_CONNECTION_ENABLED:false}",
blockPeriodTime: "${CLOUDBEAVER_BRUTE_FORCE_PROTECTION_PERIOD_BLOCK_TIME:1440}",
maxFailedLoginConnection: "${CLOUDBEAVER_MAX_FAILED_LOGIN_CONNECTION:5}",
maxFailedLogin: "${CLOUDBEAVER_MAX_FAILED_LOGINS:5}",
minimumLoginTimeout: "${CLOUDBEAVER_MINIMUM_LOGIN_TIMEOUT:1}",
blockLoginPeriod: "${CLOUDBEAVER_BLOCK_PERIOD:300}",
passwordPolicy: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
* Copyright (C) 2010-2025 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.
Expand Down Expand Up @@ -28,12 +28,16 @@ public class SMControllerConfiguration {
private int expiredAuthAttemptInfoTtl = DEFAULT_EXPIRED_AUTH_ATTEMPT_INFO_TTL;

private boolean enableBruteForceProtection = true;
private boolean enableConnectionBruteForceProtection = false;
private int blockPeriodTimeBruteForceProtection = 1440;

//in seconds
public static final int DEFAULT_MAX_FAILED_LOGIN = 10;
public static final int DEFAULT_MAX_FAILED_LOGIN_CONNECTION = 5;

public static final int DEFAULT_MINIMUM_LOGIN_TIMEOUT = 1; //1sec
public static final int DEFAULT_BLOCK_LOGIN_PERIOD = 300; //5min
private int maxFailedLogin = DEFAULT_MAX_FAILED_LOGIN;
private int maxFailedConnectionLogin = DEFAULT_MAX_FAILED_LOGIN_CONNECTION;
private int minimumLoginTimeout = DEFAULT_MINIMUM_LOGIN_TIMEOUT;
private int blockLoginPeriod = DEFAULT_BLOCK_LOGIN_PERIOD;
private final PasswordPolicyConfiguration passwordPolicy = new PasswordPolicyConfiguration();
Expand Down Expand Up @@ -66,14 +70,34 @@ public void setCheckBruteforce(boolean checkBruteforce) {
this.enableBruteForceProtection = checkBruteforce;
}

public void setBlockPeriodTimeBruteForceProtection(int blockPeriodTimeBruteForceProtection) {
this.blockPeriodTimeBruteForceProtection = blockPeriodTimeBruteForceProtection;
}

public void setEnableConnectionBruteForceProtection(boolean enableConnectionBruteForceProtection) {
this.enableConnectionBruteForceProtection = enableConnectionBruteForceProtection;
}

public boolean isCheckBruteforce() {
return enableBruteForceProtection;
}

public int getBlockPeriodTimeBruteForceProtection() {
return blockPeriodTimeBruteForceProtection;
}

public boolean isEnableConnectionBruteForceProtection() {
return enableConnectionBruteForceProtection;
}

public int getMaxFailedLogin() {
return maxFailedLogin;
}

public int getMaxFailedConnectionLogin() {
return maxFailedConnectionLogin;
}

public int getMinimumLoginTimeout() {
return minimumLoginTimeout;
}
Expand All @@ -94,6 +118,10 @@ public void setBlockLoginPeriod(int blockPeriod) {
this.blockLoginPeriod = blockPeriod;
}

public void setEnableBruteForceProtection(boolean enableBruteForceProtection) {
this.enableBruteForceProtection = enableBruteForceProtection;
}

public PasswordPolicyConfiguration getPasswordPolicyConfiguration() {
return passwordPolicy;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
* Copyright (C) 2010-2025 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.
Expand All @@ -17,8 +17,10 @@
package io.cloudbeaver.model.user;

import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.security.user.SMUser;

import java.time.Instant;
import java.util.Collections;
import java.util.Map;

Expand Down Expand Up @@ -93,4 +95,20 @@ public String toString() {
public String getAuthRole() {
return user.getAuthRole();
}


@Nullable
public Instant getDisableDate() {
return user.getDisableDate();
}

@Nullable
public String getDisableByUserId() {
return user.getDisableByUserId();
}

@Nullable
public String getDisableReason() {
return user.getDisableReason();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -411,11 +411,19 @@ public WebConnectionInfo getConnectionState(
}

@Override
public WebConnectionInfo initConnection(@NotNull WebSession webSession, @Nullable String projectId, @NotNull String connectionId, @NotNull Map<String, Object> authProperties, @Nullable List<WebNetworkHandlerConfigInput> networkCredentials, boolean saveCredentials, boolean sharedCredentials, @Nullable String selectedSecretId) throws DBWebException {
public WebConnectionInfo initConnection(
@NotNull WebSession webSession,
@Nullable String projectId,
@NotNull String connectionId,
@NotNull Map<String, Object> authProperties,
@Nullable List<WebNetworkHandlerConfigInput> networkCredentials,
boolean saveCredentials,
boolean sharedCredentials,
@Nullable String selectedSecretId
) throws DBWebException {
WebConnectionInfo connectionInfo = WebDataSourceUtils.getWebConnectionInfo(webSession, projectId, connectionId);
connectionInfo.setSavedCredentials(authProperties, networkCredentials);

var dataSourceContainer = connectionInfo.getDataSourceContainer();;
var dataSourceContainer = connectionInfo.getDataSourceContainer();
validateConnection(dataSourceContainer);
if (dataSourceContainer.isConnected()) {
throw new DBWebException("Datasource '" + dataSourceContainer.getName() + "' is already connected");
Expand All @@ -440,8 +448,9 @@ public WebConnectionInfo initConnection(@NotNull WebSession webSession, @Nullabl
boolean oldSavePassword = dataSourceContainer.isSavePassword();
DBRProgressMonitor monitor = webSession.getProgressMonitor();
validateDriverLibrariesPresence(dataSourceContainer);
boolean connect = false;
try {
boolean connect = dataSourceContainer.connect(monitor, true, false);
connect = dataSourceContainer.connect(monitor, true, false);
if (connect) {
webSession.addSessionEvent(
new WSDataSourceConnectEvent(
Expand All @@ -453,13 +462,7 @@ public WebConnectionInfo initConnection(@NotNull WebSession webSession, @Nullabl
);
}
} catch (Exception e) {
if (e instanceof DBCConnectException) {
Throwable rootCause = CommonUtils.getRootCause(e);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(dataSourceContainer);
}
}
throw new DBWebException("Error connecting to database", e);
handleConnectException(webSession, dataSourceContainer, e);
} finally {
dataSourceContainer.setSavePassword(oldSavePassword);
connectionInfo.clearCache();
Expand Down Expand Up @@ -524,6 +527,20 @@ public WebConnectionInfo initConnection(@NotNull WebSession webSession, @Nullabl
return connectionInfo;
}

protected void handleConnectException(
@NotNull WebSession webSession,
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull Exception e
) throws DBWebException {
if (e instanceof DBCConnectException) {
Throwable rootCause = CommonUtils.getRootCause(e);
if (rootCause instanceof ClassNotFoundException) {
throwDriverNotFoundException(dataSourceContainer);
}
}
throw new DBWebException("Error connecting to database", e);
}

@Override
public void validateConnection(DBPDataSourceContainer dataSourceContainer) throws DBWebException {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
*/
package io.cloudbeaver.service.core.impl;


import io.cloudbeaver.*;
import io.cloudbeaver.model.*;
import io.cloudbeaver.model.app.ServletApplication;
Expand Down Expand Up @@ -44,27 +43,19 @@
import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPDriver;
import org.jkiss.dbeaver.model.exec.DBCConnectException;
import org.jkiss.dbeaver.model.navigator.*;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.DBWHandlerType;
import org.jkiss.dbeaver.model.net.DBWNetworkHandler;
import org.jkiss.dbeaver.model.net.DBWTunnel;
import org.jkiss.dbeaver.model.net.ssh.SSHSession;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.secret.DBSSecretValue;
import org.jkiss.dbeaver.model.websocket.WSConstants;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceConnectEvent;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.registry.DataSourceProviderRegistry;
import org.jkiss.dbeaver.registry.network.NetworkHandlerDescriptor;
import org.jkiss.dbeaver.registry.network.NetworkHandlerRegistry;
import org.jkiss.dbeaver.registry.settings.ProductSettingsRegistry;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.dbeaver.runtime.jobs.ConnectionTestJob;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;

import java.util.*;
Expand Down Expand Up @@ -742,16 +733,4 @@ private WebSessionProjectImpl getProjectById(WebSession webSession, String proje
}
return project;
}

private void validateDriverLibrariesPresence(@NotNull DBPDataSourceContainer container) throws DBWebException {
if (!DBWorkbench.isDistributed() && container.getDriver().needsExternalDependencies()) {
throwDriverNotFoundException(container);
}
}

@NotNull
private static String throwDriverNotFoundException(@NotNull DBPDataSourceContainer container) throws DBWebException {
throw new DBWebException("Driver files for %s are not found. Please ask the administrator to download it."
.formatted(container.getDriver().getName()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ type AdminUserInfo {
linkedAuthProviders: [String!]!
enabled: Boolean!
authRole: String
disableDate: DateTime
disableByUserId: String
disableReason: String
}

type AdminTeamInfo {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
* Copyright (C) 2010-2025 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.
Expand Down Expand Up @@ -28,6 +28,7 @@
import org.jkiss.dbeaver.model.security.SMDataSourceGrant;
import org.jkiss.dbeaver.model.security.SMObjectType;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -111,6 +112,21 @@ public String[] getLinkedAuthProviders() throws DBWebException {
return getUserLinkedProviders();
}

@Property
public String getDisableDate() {
return user.getDisableDate() != null ? user.getDisableDate().toString() : null;
}

@Property
public String getDisableByUserId() {
return user.getDisableByUserId();
}

@Property
public String getDisableReason() {
return user.getDisableReason();
}

private String[] getUserLinkedProviders() throws DBWebException {
if (userLinkedProviders != null) {
return userLinkedProviders;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ CREATE TABLE {table_prefix}CB_USER
CREATE_TIME TIMESTAMP NOT NULL,
DEFAULT_AUTH_ROLE VARCHAR(32) NULL,
CREDENTIALS_PROFILE_ID VARCHAR(128) NULL,
CHANGE_DATE TIMESTAMP NULL,
DISABLE_BY_USER_ID VARCHAR(32) NULL,
DISABLE_REASON VARCHAR(128) NULL,

PRIMARY KEY (USER_ID),
FOREIGN KEY (USER_ID) REFERENCES {table_prefix}CB_AUTH_SUBJECT (SUBJECT_ID) ON DELETE CASCADE,
Expand Down Expand Up @@ -295,4 +298,4 @@ CREATE TABLE {table_prefix}CB_ACCESS_TOKEN
PRIMARY KEY (USER_ID, TOKEN_ID),
UNIQUE (USER_ID, TOKEN_NAME),
FOREIGN KEY (USER_ID) REFERENCES {table_prefix}CB_USER(USER_ID) ON DELETE CASCADE
);
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE {table_prefix}CB_USER ADD CHANGE_DATE TIMESTAMP NULL;
ALTER TABLE {table_prefix}CB_USER ADD DISABLE_BY_USER_ID VARCHAR(32) NULL;
ALTER TABLE {table_prefix}CB_USER ADD DISABLE_REASON VARCHAR(128) NULL;
Loading