Skip to content

Commit 1018ab5

Browse files
committed
map external users to profile
1 parent 2ac83f1 commit 1018ab5

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

docs/en/operations/external-authenticators/tokens.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ All this implies that the SQL-driven [Access Control and Account Management](/do
234234
<common_roles>
235235
<token_test_role_1 />
236236
</common_roles>
237+
<default_profile>my_profile</default_profile>
237238
<roles_filter>
238239
\bclickhouse-[a-zA-Z0-9]+\b
239240
</roles_filter>
@@ -251,5 +252,6 @@ For now, no more than one `token` section can be defined inside `user_directorie
251252

252253
- `processor` — Name of one of processors defined in `token_processors` config section described above. This parameter is mandatory and cannot be empty.
253254
- `common_roles` — Section with a list of locally defined roles that will be assigned to each user retrieved from the IdP. Optional.
255+
- `default_profile` — Name of a locally defined settings profile that will be assigned to each user retrieved from the IdP. If the profile does not exist, a warning will be logged and the user will be created without a profile. Optional.
254256
- `roles_filter` — Regex string for groups filtering. Only groups matching this regex will be mapped to roles. Optional.
255257
- `roles_transform` — Sed-style transform pattern to apply to group names before mapping to roles. Format: `s/pattern/replacement/flags`. The `g` flag applies the replacement globally (all occurrences). Example: `s/-/_/g` converts `clickhouse-grp-dba` to `clickhouse_grp_dba`. Optional.

src/Access/TokenAccessStorage.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <Access/ExternalAuthenticators.h>
44
#include <Access/User.h>
55
#include <Access/Role.h>
6+
#include <Access/SettingsProfile.h>
67
#include <Access/Credentials.h>
78
#include <Common/Exception.h>
89
#include <Common/logger_useful.h>
@@ -161,6 +162,9 @@ TokenAccessStorage::TokenAccessStorage(const String & storage_name_, AccessContr
161162
}
162163
common_role_names.swap(common_roles_cfg);
163164

165+
if (config.has(prefix_str + "default_profile"))
166+
default_profile_name = config.getString(prefix_str + "default_profile");
167+
164168
user_external_roles.clear();
165169
users_per_roles.clear();
166170
roles_per_users.clear();
@@ -426,6 +430,42 @@ void TokenAccessStorage::assignRolesNoLock(User & user, const std::set<String> &
426430
user_external_roles[user_name] = external_roles;
427431
}
428432

433+
void TokenAccessStorage::assignProfileNoLock(User & user) const
434+
{
435+
if (default_profile_name.empty())
436+
return;
437+
438+
const auto & user_name = user.getName();
439+
auto & settings = user.settings;
440+
441+
// Look up the profile ID once
442+
const auto profile_id = access_control.find<SettingsProfile>(default_profile_name);
443+
if (!profile_id)
444+
{
445+
LOG_TRACE(getLogger(), "Did not assign profile '{}' to user '{}': profile not found", default_profile_name, user_name);
446+
return;
447+
}
448+
449+
// Check if profile is already assigned
450+
bool profile_already_assigned = false;
451+
for (const auto & element : settings)
452+
{
453+
if (element.parent_profile.has_value() && element.parent_profile == *profile_id)
454+
{
455+
profile_already_assigned = true;
456+
break;
457+
}
458+
}
459+
460+
if (!profile_already_assigned)
461+
{
462+
SettingsProfileElement profile_element;
463+
profile_element.parent_profile = *profile_id;
464+
settings.push_back(std::move(profile_element));
465+
LOG_TRACE(getLogger(), "Assigned profile '{}' to user '{}'", default_profile_name, user_name);
466+
}
467+
}
468+
429469
void TokenAccessStorage::updateAssignedRolesNoLock(const UUID & id, const String & user_name, const std::set<String> & external_roles) const
430470
{
431471
// Map and grant the roles from scratch only if the list of external role has changed.
@@ -521,12 +561,25 @@ std::optional<AuthResult> TokenAccessStorage::authenticateImpl(
521561
if (new_user)
522562
{
523563
assignRolesNoLock(*new_user, external_roles);
564+
assignProfileNoLock(*new_user);
524565
id = memory_storage.insert(new_user);
525566
}
526567
else
527568
{
528569
// Just in case external_roles are changed.
529570
updateAssignedRolesNoLock(*id, user->getName(), external_roles);
571+
572+
// Also update profile if needed
573+
memory_storage.update(*id, [this] (const AccessEntityPtr & entity_, const UUID &) -> AccessEntityPtr
574+
{
575+
if (auto user_entity = typeid_cast<std::shared_ptr<const User>>(entity_))
576+
{
577+
auto changed_user = typeid_cast<std::shared_ptr<User>>(user_entity->clone());
578+
assignProfileNoLock(*changed_user);
579+
return changed_user;
580+
}
581+
return entity_;
582+
});
530583
}
531584

532585
if (id)

src/Access/TokenAccessStorage.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <Access/MemoryAccessStorage.h>
44
#include <Access/Credentials.h>
5+
#include <Access/SettingsProfile.h>
56
#include <Common/re2.h>
67
#include <base/types.h>
78
#include <base/scope_guard.h>
@@ -53,6 +54,7 @@ class TokenAccessStorage : public IAccessStorage
5354
bool roles_transform_global = false;
5455

5556
std::set<String> common_role_names; // role name that should be granted to all users at all times
57+
String default_profile_name; // settings profile name that should be assigned to all users
5658
mutable std::map<String, std::set<String>> user_external_roles;
5759
mutable std::map<String, std::set<String>> users_per_roles; // role name -> user names (...it should be granted to; may but don't have to exist for common roles)
5860
mutable std::map<String, std::set<String>> roles_per_users; // user name -> role names (...that should be granted to it; may but don't have to include common roles)
@@ -67,6 +69,7 @@ class TokenAccessStorage : public IAccessStorage
6769

6870
void applyRoleChangeNoLock(bool grant, const UUID & role_id, const String & role_name);
6971
void assignRolesNoLock(User & user, const std::set<String> & external_roles) const;
72+
void assignProfileNoLock(User & user) const;
7073
void updateAssignedRolesNoLock(const UUID & id, const String & user_name, const std::set<String> & external_roles) const;
7174

7275
protected:

0 commit comments

Comments
 (0)