Skip to content

Commit 9bed2b9

Browse files
committed
feat redis: support username authorization
1 parent e616760 commit 9bed2b9

28 files changed

Lines changed: 447 additions & 178 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
.DS_Store
44
.mypy_cache
55
.pytest_cache
6+
.python-version
67
*.orig
78
/Makefile.local
89
*.yawiki
@@ -12,6 +13,7 @@
1213
/build*/
1314
/cmake-build-*/
1415
CMakeLists.txt.user
16+
CMakeUserPresets.json
1517
compile_commands.json
1618
tags
1719
static-analyzer-report

redis/include/userver/storages/redis/base.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ USERVER_NAMESPACE_BEGIN
1414

1515
namespace storages::redis {
1616

17+
using Username = utils::StrongTypedef<class UsernameTag, std::string>;
1718
using Password = utils::NonLoggable<class PasswordTag, std::string>;
1819

1920
enum class ConnectionSecurity { kNone, kTLS };
2021

2122
struct ConnectionInfo {
2223
std::string host = "localhost";
2324
int port = 26379;
25+
Username username;
2426
Password password;
2527
bool read_only = false;
2628
ConnectionSecurity connection_security = ConnectionSecurity::kNone;
@@ -31,18 +33,19 @@ struct ConnectionInfo {
3133
ConnectionInfo(
3234
std::string host,
3335
int port,
36+
Username username,
3437
Password password,
3538
bool read_only = false,
3639
ConnectionSecurity security = ConnectionSecurity::kNone,
3740
std::size_t db_index = 0
3841
)
3942
: host{std::move(host)},
4043
port{port},
44+
username{std::move(username)},
4145
password{std::move(password)},
4246
read_only{read_only},
4347
connection_security(security),
44-
database_index(db_index)
45-
{}
48+
database_index(db_index) {}
4649
};
4750

4851
struct Stat {
@@ -81,9 +84,7 @@ struct MetricsSettings {
8184

8285
DynamicSettings dynamic_settings;
8386

84-
MetricsSettings(const DynamicSettings& dynamic_settings)
85-
: dynamic_settings(dynamic_settings)
86-
{}
87+
MetricsSettings(const DynamicSettings& dynamic_settings) : dynamic_settings(dynamic_settings) {}
8788
MetricsSettings() = default;
8889
MetricsSettings(const MetricsSettings&) = default;
8990
MetricsSettings(MetricsSettings&&) = default;

redis/src/storages/redis/component.cpp

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,7 @@ RedisPools Parse(const yaml_config::YamlConfig& value, formats::parse::To<RedisP
115115
}
116116

117117
Redis::Redis(const ComponentConfig& config, const ComponentContext& component_context)
118-
: ComponentBase(config, component_context),
119-
config_(component_context.FindComponent<DynamicConfig>().GetSource())
120-
{
118+
: ComponentBase(config, component_context), config_(component_context.FindComponent<DynamicConfig>().GetSource()) {
121119
const auto&
122120
testsuite_redis_control = component_context.FindComponent<components::TestsuiteSupport>().GetRedisControl();
123121
Connect(config, component_context, testsuite_redis_control);
@@ -145,11 +143,13 @@ std::shared_ptr<storages::redis::Client> Redis::GetClient(
145143
) const {
146144
auto it = clients_.find(name);
147145
if (it == clients_.end()) {
148-
throw std::runtime_error(fmt::format(
149-
"{} redis client not found. Available clients: [{}]",
150-
name,
151-
fmt::join(clients_ | boost::adaptors::map_keys, ", ")
152-
));
146+
throw std::runtime_error(
147+
fmt::format(
148+
"{} redis client not found. Available clients: [{}]",
149+
name,
150+
fmt::join(clients_ | boost::adaptors::map_keys, ", ")
151+
)
152+
);
153153
}
154154
it->second->WaitConnectedOnce(wait_connected);
155155
return it->second;
@@ -158,11 +158,13 @@ std::shared_ptr<storages::redis::Client> Redis::GetClient(
158158
std::shared_ptr<storages::redis::impl::Sentinel> Redis::Client(const std::string& name) const {
159159
auto it = sentinels_.find(name);
160160
if (it == sentinels_.end()) {
161-
throw std::runtime_error(fmt::format(
162-
"{} redis client not found. Available clients: [{}]",
163-
name,
164-
fmt::join(clients_ | boost::adaptors::map_keys, ", ")
165-
));
161+
throw std::runtime_error(
162+
fmt::format(
163+
"{} redis client not found. Available clients: [{}]",
164+
name,
165+
fmt::join(clients_ | boost::adaptors::map_keys, ", ")
166+
)
167+
);
166168
}
167169
return it->second;
168170
}
@@ -173,12 +175,14 @@ std::shared_ptr<storages::redis::SubscribeClient> Redis::GetSubscribeClient(
173175
) const {
174176
auto it = subscribe_clients_.find(name);
175177
if (it == subscribe_clients_.end()) {
176-
throw std::runtime_error(fmt::format(
177-
"{} redis subscribe-client not found. Available subscribe-clients: "
178-
"[{}]",
179-
name,
180-
fmt::join(subscribe_clients_ | boost::adaptors::map_keys, ", ")
181-
));
178+
throw std::runtime_error(
179+
fmt::format(
180+
"{} redis subscribe-client not found. Available subscribe-clients: "
181+
"[{}]",
182+
name,
183+
fmt::join(subscribe_clients_ | boost::adaptors::map_keys, ", ")
184+
)
185+
);
182186
}
183187
it->second->WaitConnectedOnce(wait_connected);
184188
return std::static_pointer_cast<storages::redis::SubscribeClient>(it->second);
@@ -331,11 +335,13 @@ void Redis::OnSecdistUpdate(const storages::secdist::SecdistConfig& cfg) {
331335

332336
std::vector<storages::redis::ConnectionInfo> cii;
333337
for (const auto& host_port : settings.sentinels) {
334-
const storages::redis::ConnectionInfo ci(host_port.host, host_port.port, settings.password);
338+
const storages::redis::ConnectionInfo
339+
ci(host_port.host, host_port.port, settings.username, settings.password);
335340
cii.push_back(ci);
336341
}
337342

338343
sentinel->SetConnectionInfo(cii);
344+
sentinel->UpdateUsername(settings.username);
339345
sentinel->UpdatePassword(settings.password);
340346
}
341347
}

redis/src/storages/redis/impl/cluster_topology_holder.cpp

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ ClusterTopologyHolder::ClusterTopologyHolder(
128128
const engine::ev::ThreadControl& sentinel_thread_control,
129129
const std::shared_ptr<engine::ev::ThreadPool>& redis_thread_pool,
130130
std::string shard_group_name,
131+
Username username,
131132
Password password,
132133
const std::vector<std::string>& /*shards*/,
133134
const std::vector<ConnectionInfo>& conns,
@@ -136,11 +137,16 @@ ClusterTopologyHolder::ClusterTopologyHolder(
136137
: ev_thread_(sentinel_thread_control),
137138
redis_thread_pool_(redis_thread_pool),
138139
shard_group_name_(std::move(shard_group_name)),
140+
username_(std::move(username)),
139141
password_(std::move(password)),
140142
shards_names_(MakeShardNames()),
141143
conns_(conns),
142144
statistics_holder_(),
143-
update_topology_timer_(ev_thread_, [this] { UpdateClusterTopology(); }, kSentinelGetHostsCheckInterval),
145+
update_topology_timer_(
146+
ev_thread_,
147+
[this] { UpdateClusterTopology(); },
148+
kSentinelGetHostsCheckInterval
149+
),
144150
update_topology_watch_(
145151
ev_thread_,
146152
[this] {
@@ -155,15 +161,23 @@ ClusterTopologyHolder::ClusterTopologyHolder(
155161
explore_nodes_watch_.Start();
156162
}
157163
),
158-
explore_nodes_timer_(ev_thread_, [this] { ExploreNodes(); }, kSentinelGetHostsCheckInterval),
164+
explore_nodes_timer_(
165+
ev_thread_,
166+
[this] { ExploreNodes(); },
167+
kSentinelGetHostsCheckInterval
168+
),
159169
create_nodes_watch_(
160170
ev_thread_,
161171
[this] {
162172
CreateNodes();
163173
create_nodes_watch_.Start();
164174
}
165175
),
166-
delete_expired_nodes_timer_(ev_thread_, [this] { DeleteNodes(); }, kDeleteNodesCheckInterval),
176+
delete_expired_nodes_timer_(
177+
ev_thread_,
178+
[this] { DeleteNodes(); },
179+
kDeleteNodesCheckInterval
180+
),
167181
sentinels_process_creation_timer_(
168182
ev_thread_,
169183
[this] {
@@ -194,8 +208,7 @@ ClusterTopologyHolder::ClusterTopologyHolder(
194208
),
195209
is_topology_received_(false),
196210
update_cluster_slots_flag_(false),
197-
connection_security_(connection_security)
198-
{
211+
connection_security_(connection_security) {
199212
log_extra_.Extend("shard_group_name", shard_group_name_);
200213
LOG_DEBUG() << log_extra_ << "Created ClusterTopologyHolder";
201214
}
@@ -339,11 +352,21 @@ boost::signals2::signal<void(size_t)>& ClusterTopologyHolder::GetSignalTopologyC
339352
return signal_topology_changed_;
340353
}
341354

355+
void ClusterTopologyHolder::UpdateUsername(const Username& username) {
356+
auto lock = username_.UniqueLock();
357+
*lock = username;
358+
}
359+
342360
void ClusterTopologyHolder::UpdatePassword(const Password& password) {
343361
auto lock = password_.UniqueLock();
344362
*lock = password;
345363
}
346364

365+
Username ClusterTopologyHolder::GetUsername() {
366+
const auto lock = username_.Lock();
367+
return *lock;
368+
}
369+
347370
Password ClusterTopologyHolder::GetPassword() {
348371
const auto lock = password_.Lock();
349372
return *lock;
@@ -471,6 +494,7 @@ std::shared_ptr<RedisConnectionHolder> ClusterTopologyHolder::CreateRedisInstanc
471494
shard_group_name_,
472495
host,
473496
port,
497+
GetUsername(),
474498
GetPassword(),
475499
kClusterDatabaseIndex,
476500
buffering_settings_ptr->value_or(CommandsBufferingSettings{}),
@@ -497,11 +521,14 @@ void ClusterTopologyHolder::UpdateClusterTopology() {
497521
/// ...
498522
ProcessGetClusterHostsRequest(
499523
shards_names_,
500-
GetClusterHostsRequest(*sentinels_, GetPassword(), shard_group_name_),
524+
GetClusterHostsRequest(*sentinels_, GetUsername(), GetPassword(), shard_group_name_),
501525
[this,
502-
reset{std::move(reset_update_cluster_slots)
503-
}](ClusterShardHostInfos shard_infos, size_t requests_sent, size_t responses_parsed, bool is_non_cluster_error
504-
) {
526+
reset{
527+
std::move(reset_update_cluster_slots)
528+
}](ClusterShardHostInfos shard_infos,
529+
size_t requests_sent,
530+
size_t responses_parsed,
531+
bool is_non_cluster_error) {
505532
LOG_DEBUG()
506533
<< log_extra_ << "Parsing response from cluster slots: shard_infos.size(): " << shard_infos.size()
507534
<< ", requests_sent=" << requests_sent << ", responses_parsed=" << responses_parsed;

redis/src/storages/redis/impl/cluster_topology_holder.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class ClusterTopologyHolder final : public TopologyHolderBase {
2525
const engine::ev::ThreadControl& sentinel_thread_control,
2626
const std::shared_ptr<engine::ev::ThreadPool>& redis_thread_pool,
2727
std::string shard_group_name,
28+
Username username,
2829
Password password,
2930
const std::vector<std::string>& /*shards*/,
3031
const std::vector<ConnectionInfo>& conns,
@@ -47,8 +48,13 @@ class ClusterTopologyHolder final : public TopologyHolderBase {
4748
void SetConnectionInfo(const std::vector<ConnectionInfoInt>& info_array) override;
4849
boost::signals2::signal<void(HostPort, Redis::State)>& GetSignalNodeStateChanged() override;
4950
boost::signals2::signal<void(size_t)>& GetSignalTopologyChanged() override;
51+
52+
void UpdateUsername(const Username& username) override;
5053
void UpdatePassword(const Password& password) override;
54+
55+
Username GetUsername() override;
5156
Password GetPassword() override;
57+
5258
std::string GetReadinessInfo() const override;
5359

5460
static size_t GetClusterSlotsCalledCounter() { return cluster_slots_call_counter.load(std::memory_order_relaxed); }
@@ -61,6 +67,7 @@ class ClusterTopologyHolder final : public TopologyHolderBase {
6167

6268
const std::string shard_group_name_;
6369
logging::LogExtra log_extra_;
70+
concurrent::Variable<Username, std::mutex> username_;
6471
concurrent::Variable<Password, std::mutex> password_;
6572
std::shared_ptr<const std::vector<std::string>> shards_names_;
6673
const std::vector<ConnectionInfo> conns_;

0 commit comments

Comments
 (0)