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

Added maximum sequential login failures to the quota. #54737

Merged
merged 3 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/en/operations/system-tables/quota_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Columns:
- `max_read_rows` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — Maximum number of rows read from all tables and table functions participated in queries.
- `read_bytes` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — The total number of bytes read from all tables and table functions participated in queries.
- `max_read_bytes` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — Maximum of bytes read from all tables and table functions.
- `failed_sequential_authentications` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/float.md))) — The total count of sequential authentication failures. If the user entered the correct password before exceed `failed_sequential_authentications` threshold then the counter will be reset.
- `max_failed_sequential_authentications` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/float.md))) — Maximum count of sequential authentication failures.
- `execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — The total query execution time, in seconds (wall time).
- `max_execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — Maximum of query execution time.

Expand Down
6 changes: 4 additions & 2 deletions docs/en/operations/system-tables/quotas_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ Columns:
- `max_read_rows` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — Maximum number of rows read from all tables and table functions participated in queries.
- `read_bytes` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — The total number of bytes read from all tables and table functions participated in queries.
- `max_read_bytes` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — Maximum of bytes read from all tables and table functions.
- `execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — The total query execution time, in seconds (wall time).
- `max_execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — Maximum of query execution time.
- `failed_sequential_authentications` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — The total count of sequential authentication failures. If the user entered the correct password before exceed `failed_sequential_authentications` threshold then the counter will be reset.
- `max_failed_sequential_authentications` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — Maximum count of sequential authentication failures.
- `execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/float.md))) — The total query execution time, in seconds (wall time).
- `max_execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/float.md))) — Maximum of query execution time.

## See Also {#see-also}

Expand Down
2 changes: 1 addition & 1 deletion docs/en/sql-reference/statements/create/quota.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name]

Keys `user_name`, `ip_address`, `client_key`, `client_key, user_name` and `client_key, ip_address` correspond to the fields in the [system.quotas](../../../operations/system-tables/quotas.md) table.

Parameters `queries`, `query_selects`, `query_inserts`, `errors`, `result_rows`, `result_bytes`, `read_rows`, `read_bytes`, `execution_time` correspond to the fields in the [system.quotas_usage](../../../operations/system-tables/quotas_usage.md) table.
Parameters `queries`, `query_selects`, `query_inserts`, `errors`, `result_rows`, `result_bytes`, `read_rows`, `read_bytes`, `execution_time`, `failed_sequential_authentications` correspond to the fields in the [system.quotas_usage](../../../operations/system-tables/quotas_usage.md) table.

`ON CLUSTER` clause allows creating quotas on a cluster, see [Distributed DDL](../../../sql-reference/distributed-ddl.md).

Expand Down
7 changes: 5 additions & 2 deletions docs/ru/operations/system-tables/quota_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ slug: /ru/operations/system-tables/quota_usage
- `max_read_rows` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — максимальное количество строк, считываемых из всех таблиц и табличных функций, участвующих в запросах.
- `read_bytes` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — общее количество байт, считанных из всех таблиц и табличных функций, участвующих в запросах.
- `max_read_bytes` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — максимальное количество байт, считываемых из всех таблиц и табличных функций.
- `execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — общее время выполнения запроса, в секундах.
- `max_execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — максимальное время выполнения запроса.
- `failed_sequential_authentications` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — Общее количество неудачных попыток подряд ввести пароль. Если пользователь ввел верный пароль до преодоления порогового значения `max_failed_sequential_authentications` то счетчик неудачных попыток будет сброшен.
- `max_failed_sequential_authentications` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — Максимальное количество неудачных попыток подряд ввести пароль.
- `execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/float.md))) — общее время выполнения запроса, в секундах.
- `max_execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/float.md))) — максимальное время выполнения запроса.


## Смотрите также {#see-also}

Expand Down
3 changes: 2 additions & 1 deletion docs/ru/operations/system-tables/quotas_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ slug: /ru/operations/system-tables/quotas_usage
- `max_read_rows` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — максимальное количество строк, считываемых из всех таблиц и табличных функций, участвующих в запросах.
- `read_bytes` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — общее количество байт, считанных из всех таблиц и табличных функций, участвующих в запросах.
- `max_read_bytes` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/int-uint.md))) — максимальное количество байт, считываемых из всех таблиц и табличных функций.
- `failed_sequential_authentications` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/float.md))) — Общее количество неудачных попыток подряд ввести пароль. Если пользователь ввел верный пароль до преодоления порогового значения `max_failed_sequential_authentications` то счетчик неудачных попыток будет сброшен.
- `max_failed_sequential_authentications` ([Nullable](../../sql-reference/data-types/nullable.md)([UInt64](../../sql-reference/data-types/float.md))) — Максимальное количество неудачных попыток подряд ввести пароль.
- `execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — общее время выполнения запроса, в секундах.
- `max_execution_time` ([Nullable](../../sql-reference/data-types/nullable.md)([Float64](../../sql-reference/data-types/float.md))) — максимальное время выполнения запроса.

## Смотрите также {#see-also}

- [SHOW QUOTA](../../sql-reference/statements/show.md#show-quota-statement)
2 changes: 1 addition & 1 deletion docs/ru/sql-reference/statements/alter/quota.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ALTER QUOTA [IF EXISTS] name [ON CLUSTER cluster_name]

Ключи `user_name`, `ip_address`, `client_key`, `client_key, user_name` и `client_key, ip_address` соответствуют полям таблицы [system.quotas](../../../operations/system-tables/quotas.md).

Параметры `queries`, `query_selects`, `query_inserts`, `errors`, `result_rows`, `result_bytes`, `read_rows`, `read_bytes`, `execution_time` соответствуют полям таблицы [system.quotas_usage](../../../operations/system-tables/quotas_usage.md).
Параметры `queries`, `query_selects`, `query_inserts`, `errors`, `result_rows`, `result_bytes`, `read_rows`, `read_bytes`, `execution_time`, `failed_sequential_authentications` соответствуют полям таблицы [system.quotas_usage](../../../operations/system-tables/quotas_usage.md).

В секции `ON CLUSTER` можно указать кластеры, на которых создается квота, см. [Распределенные DDL запросы](../../../sql-reference/distributed-ddl.md).

Expand Down
2 changes: 1 addition & 1 deletion docs/ru/sql-reference/statements/create/quota.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name]
```
Ключи `user_name`, `ip_address`, `client_key`, `client_key, user_name` и `client_key, ip_address` соответствуют полям таблицы [system.quotas](../../../operations/system-tables/quotas.md).

Параметры `queries`, `query_selects`, `query_inserts`, `errors`, `result_rows`, `result_bytes`, `read_rows`, `read_bytes`, `execution_time` соответствуют полям таблицы [system.quotas_usage](../../../operations/system-tables/quotas_usage.md).
Параметры `queries`, `query_selects`, `query_inserts`, `errors`, `result_rows`, `result_bytes`, `read_rows`, `read_bytes`, `execution_time`, `failed_sequential_authentications` соответствуют полям таблицы [system.quotas_usage](../../../operations/system-tables/quotas_usage.md).

В секции `ON CLUSTER` можно указать кластеры, на которых создается квота, см. [Распределенные DDL запросы](../../../sql-reference/distributed-ddl.md).

Expand Down
56 changes: 52 additions & 4 deletions src/Access/AccessControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,12 +559,33 @@ AccessChangesNotifier & AccessControl::getChangesNotifier()
}


AuthResult AccessControl::authenticate(const Credentials & credentials, const Poco::Net::IPAddress & address) const
AuthResult AccessControl::authenticate(const Credentials & credentials, const Poco::Net::IPAddress & address, const String & forwarded_address) const
{
// NOTE: In the case where the user has never been logged in using LDAP,
// Then user_id is not generated, and the authentication quota will always be nullptr.
auto authentication_quota = getAuthenticationQuota(credentials.getUserName(), address, forwarded_address);
if (authentication_quota)
{
/// Reserve a single try from the quota to check whether we have another authentication try.
/// This is required for correct behavior in this situation:
/// User has 1 login failures quota.
/// * At the first login with an invalid password: Increase the quota counter. 1 (used) > 1 (max) is false.
///   Then try to authenticate the user and throw an AUTHENTICATION_FAILED error.
/// * In case of the second try: increase quota counter, 2 (used) > 1 (max), then throw QUOTA_EXCEED
///   and don't let the user authenticate.
///
/// The authentication failures counter will be reset after successful authentication.
authentication_quota->used(QuotaType::FAILED_SEQUENTIAL_AUTHENTICATIONS, 1);
}

try
{
return MultipleAccessStorage::authenticate(credentials, address, *external_authenticators, allow_no_password,
allow_plaintext_password);
const auto auth_result = MultipleAccessStorage::authenticate(credentials, address, *external_authenticators, allow_no_password,
allow_plaintext_password);
if (authentication_quota)
authentication_quota->reset(QuotaType::FAILED_SEQUENTIAL_AUTHENTICATIONS);

return auth_result;
}
catch (...)
{
Expand Down Expand Up @@ -763,7 +784,34 @@ std::shared_ptr<const EnabledQuota> AccessControl::getEnabledQuota(
const String & forwarded_address,
const String & custom_quota_key) const
{
return quota_cache->getEnabledQuota(user_id, user_name, enabled_roles, address, forwarded_address, custom_quota_key);
return quota_cache->getEnabledQuota(user_id, user_name, enabled_roles, address, forwarded_address, custom_quota_key, true);
}

Demilivor marked this conversation as resolved.
Show resolved Hide resolved
std::shared_ptr<const EnabledQuota> AccessControl::getAuthenticationQuota(
const String & user_name, const Poco::Net::IPAddress & address, const std::string & forwarded_address) const
{
auto user_id = find<User>(user_name);
UserPtr user;
if (user_id && (user = tryRead<User>(*user_id)))
{
const auto new_current_roles = user->granted_roles.findGranted(user->default_roles);
const auto roles_info = getEnabledRolesInfo(new_current_roles, {});

// client_key is not received at the moment of authentication during TCP connection
// if key type is set to QuotaKeyType::CLIENT_KEY
// QuotaCache::QuotaInfo::calculateKey will throw exception without throw_if_client_key_empty = false
String quota_key;
bool throw_if_client_key_empty = false;
return quota_cache->getEnabledQuota(*user_id,
user->getName(),
roles_info->enabled_roles,
address,
forwarded_address,
quota_key,
throw_if_client_key_empty);
}
else
return nullptr;
}


Expand Down
7 changes: 6 additions & 1 deletion src/Access/AccessControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class AccessControl : public MultipleAccessStorage
scope_guard subscribeForChanges(const UUID & id, const OnChangedHandler & handler) const;
scope_guard subscribeForChanges(const std::vector<UUID> & ids, const OnChangedHandler & handler) const;

AuthResult authenticate(const Credentials & credentials, const Poco::Net::IPAddress & address) const;
AuthResult authenticate(const Credentials & credentials, const Poco::Net::IPAddress & address, const String & forwarded_address) const;

/// Makes a backup of access entities.
void restoreFromBackup(RestorerFromBackup & restorer) override;
Expand Down Expand Up @@ -206,6 +206,11 @@ class AccessControl : public MultipleAccessStorage
const String & forwarded_address,
const String & custom_quota_key) const;

std::shared_ptr<const EnabledQuota> getAuthenticationQuota(
const String & user_name,
const Poco::Net::IPAddress & address,
const std::string & forwarded_address) const;

std::vector<QuotaUsage> getAllQuotasUsage() const;

std::shared_ptr<const EnabledSettings> getEnabledSettings(
Expand Down
5 changes: 5 additions & 0 deletions src/Access/Common/QuotaDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ const QuotaTypeInfo & QuotaTypeInfo::get(QuotaType type)
static const auto info = make_info("WRITTEN_BYTES", 1);
return info;
}
case QuotaType::FAILED_SEQUENTIAL_AUTHENTICATIONS:
{
static const auto info = make_info("FAILED_SEQUENTIAL_AUTHENTICATIONS", 1);
return info;
}
case QuotaType::MAX: break;
}
throw Exception(ErrorCodes::LOGICAL_ERROR, "Unexpected quota type: {}", static_cast<int>(type));
Expand Down
21 changes: 11 additions & 10 deletions src/Access/Common/QuotaDefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ using QuotaValue = UInt64;
/// Kinds of resource what we wish to quota.
enum class QuotaType
{
QUERIES, /// Number of queries.
QUERY_SELECTS, /// Number of select queries.
QUERY_INSERTS, /// Number of insert queries.
ERRORS, /// Number of queries with exceptions.
RESULT_ROWS, /// Number of rows returned as result.
RESULT_BYTES, /// Number of bytes returned as result.
READ_ROWS, /// Number of rows read from tables.
READ_BYTES, /// Number of bytes read from tables.
EXECUTION_TIME, /// Total amount of query execution time in nanoseconds.
WRITTEN_BYTES, /// Number of bytes written to tables.
QUERIES, /// Number of queries.
QUERY_SELECTS, /// Number of select queries.
QUERY_INSERTS, /// Number of insert queries.
ERRORS, /// Number of queries with exceptions.
RESULT_ROWS, /// Number of rows returned as result.
RESULT_BYTES, /// Number of bytes returned as result.
READ_ROWS, /// Number of rows read from tables.
READ_BYTES, /// Number of bytes read from tables.
EXECUTION_TIME, /// Total amount of query execution time in nanoseconds.
WRITTEN_BYTES, /// Number of bytes written to tables.
FAILED_SEQUENTIAL_AUTHENTICATIONS, /// Number of recent failed authentications.

MAX
};
Expand Down
16 changes: 16 additions & 0 deletions src/Access/EnabledQuota.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ struct EnabledQuota::Impl
std::uniform_int_distribution<Int64> distribution{0, count - 1};
return std::chrono::system_clock::duration(distribution(thread_local_rng));
}

static void resetQuotaValue(const Intervals & intervals, QuotaType quota_type, QuotaValue value, std::chrono::system_clock::time_point current_time)
{
const auto quota_type_i = static_cast<size_t>(quota_type);
for (const auto & interval : intervals.intervals)
{
interval.used[quota_type_i] = value;
interval.getEndOfInterval(current_time);
}
}
};


Expand Down Expand Up @@ -285,6 +295,12 @@ void EnabledQuota::checkExceeded(QuotaType quota_type) const
}


void EnabledQuota::reset(QuotaType quota_type) const
{
const auto loaded = intervals.load();
Impl::resetQuotaValue(*loaded, quota_type, 0, std::chrono::system_clock::now());
}

std::optional<QuotaUsage> EnabledQuota::getUsage() const
{
auto loaded = intervals.load();
Expand Down
2 changes: 2 additions & 0 deletions src/Access/EnabledQuota.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class EnabledQuota : public boost::noncopyable
void checkExceeded() const;
void checkExceeded(QuotaType quota_type) const;

void reset(QuotaType quota_type) const;

/// Returns the information about quota consumption.
std::optional<QuotaUsage> getUsage() const;

Expand Down