Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions proto/redpanda/core/admin/v2/security.proto
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ message ResolveOidcIdentityResponse {

// The timestamp of the token's expiry.
google.protobuf.Timestamp expire = 2;

// The groups resolved from the OIDC token.
repeated string groups = 3;
}

// RefreshOidcKeysRequest is the request for the RefreshOidcKeys RPC.
Expand Down
34 changes: 27 additions & 7 deletions src/v/kafka/server/connection_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,12 @@ security::auth_result connection_context::authorized(
}

return authorized_user(
get_principal(), operation, name, quiet, superuser_required);
get_principal(),
operation,
name,
quiet,
superuser_required,
get_groups());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a huge fan of the ordering here, I feel like it should be principal, groups, ... , but this overload set is tricky.

}

template security::auth_result connection_context::authorized<model::topic>(
Expand Down Expand Up @@ -306,15 +311,17 @@ security::auth_result connection_context::authorized_user(
security::acl_operation operation,
const T& name,
authz_quiet quiet,
superuser_required superuser_required) {
superuser_required superuser_required,
const chunked_vector<security::acl_principal>& groups) {
auto authorized = _server.authorizer().authorized(
name,
operation,
principal,
security::acl_host(_client_addr),
security::superuser_required{
superuser_required ? security::superuser_required::yes
: security::superuser_required::no});
: security::superuser_required::no},
groups);

if (!authorized) {
if (_sasl) {
Expand Down Expand Up @@ -369,31 +376,35 @@ connection_context::authorized_user<model::topic>(
security::acl_operation operation,
const model::topic& name,
authz_quiet quiet,
superuser_required);
superuser_required,
const chunked_vector<security::acl_principal>& groups);

template security::auth_result
connection_context::authorized_user<kafka::group_id>(
security::acl_principal principal,
security::acl_operation operation,
const kafka::group_id& name,
authz_quiet quiet,
superuser_required);
superuser_required,
const chunked_vector<security::acl_principal>& groups);

template security::auth_result
connection_context::authorized_user<kafka::transactional_id>(
security::acl_principal principal,
security::acl_operation operation,
const kafka::transactional_id& name,
authz_quiet quiet,
superuser_required);
superuser_required,
const chunked_vector<security::acl_principal>& groups);

template security::auth_result
connection_context::authorized_user<security::acl_cluster_name>(
security::acl_principal principal,
security::acl_operation operation,
const security::acl_cluster_name& name,
authz_quiet quiet,
superuser_required);
superuser_required,
const chunked_vector<security::acl_principal>& groups);

ss::future<> connection_context::revoke_credentials(std::string_view name) {
if (
Expand Down Expand Up @@ -606,6 +617,15 @@ ss::future<> connection_context::handle_auth_v0(const size_t size) {
co_await conn->write(std::move(msg));
}

const chunked_vector<security::acl_principal>&
connection_context::get_groups() const {
if (_sasl && _sasl->has_mechanism()) {
return _sasl->mechanism().groups();
}
static const chunked_vector<security::acl_principal> empty;
return empty;
}

bool connection_context::is_finished_parsing() const {
return conn->input().eof() || abort_requested();
}
Expand Down
5 changes: 4 additions & 1 deletion src/v/kafka/server/connection_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,8 @@ class connection_context final
security::acl_operation operation,
const T& name,
authz_quiet quiet,
superuser_required superuser_required);
superuser_required superuser_required,
const chunked_vector<security::acl_principal>& groups);

security::acl_principal get_principal() const {
if (_mtls_state) {
Expand All @@ -317,6 +318,8 @@ class connection_context final
return security::acl_principal{security::principal_type::user, {}};
}

const chunked_vector<security::acl_principal>& get_groups() const;

bool is_finished_parsing() const;

// Reserve units from memory from the memory semaphore in proportion
Expand Down
9 changes: 6 additions & 3 deletions src/v/pandaproxy/schema_registry/authorization.cc
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ void handle_authz(
op,
params.principal,
params.host,
security::superuser_required::no);
security::superuser_required::no,
auth_result.get_groups());
},
[&](const detail::no_auth auto&) {
return security::auth_result::authz_disabled(
Expand Down Expand Up @@ -187,7 +188,8 @@ void handle_get_schemas_ids_id_authz(
op,
params.principal,
params.host,
security::superuser_required::no);
security::superuser_required::no,
auth_result.value().get_groups());

if (res.is_authorized()) {
authorizing_result = std::move(res);
Expand Down Expand Up @@ -237,7 +239,8 @@ void handle_get_subjects_authz(
op,
params.principal,
params.host,
security::superuser_required::no);
security::superuser_required::no,
auth_result.value().get_groups());
if (res.is_authorized()) {
passing_results.emplace_back(subject(), subject_resource_type);
return false; // keep
Expand Down
7 changes: 7 additions & 0 deletions src/v/redpanda/admin/services/security.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "security/role_store.h"
#include "security/scram_algorithm.h"

#include <algorithm>

namespace admin {

namespace {
Expand Down Expand Up @@ -561,6 +563,11 @@ security_service_impl::resolve_oidc_identity(
std::chrono::system_clock::time_point{
res.assume_value().expiry.time_since_epoch()}));

resp.set_groups(
{std::from_range,
auth_result->get_groups()
| std::views::transform(&security::acl_principal::name)});

co_return resp;
}

Expand Down
6 changes: 4 additions & 2 deletions src/v/security/audit/schemas/tests/ocsf_schemas_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,8 @@ BOOST_AUTO_TEST_CASE(make_api_activity_event_authorized) {
security::credential_user{username},
security::credential_password{"password"},
"sasl",
request_auth_result::superuser::no};
request_auth_result::superuser::no,
{}};

auto api_activity = sa::api_activity::construct(
req, auth_result, "http", true, std::nullopt);
Expand Down Expand Up @@ -681,7 +682,8 @@ BOOST_AUTO_TEST_CASE(make_authentication_event_success) {
security::credential_user{username},
security::credential_password{"password"},
"sasl",
request_auth_result::superuser::no};
request_auth_result::superuser::no,
{}};

auto authn = sa::authentication::construct(sa::authentication_event_options {
.auth_protocol = "sasl",
Expand Down
Loading
Loading