]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/oidc rados: add rgwrados::oidcs namespace abstraction for cls_user for accounts.
authorKrunal Chheda <kchheda3@bloomberg.net>
Wed, 25 Feb 2026 21:30:49 +0000 (16:30 -0500)
committerKrunal Chheda <kchheda3@bloomberg.net>
Tue, 3 Mar 2026 20:44:29 +0000 (15:44 -0500)
Signed-off-by: Krunal Chheda <kchheda3@bloomberg.net>
src/rgw/CMakeLists.txt
src/rgw/driver/rados/account.cc
src/rgw/driver/rados/account.h
src/rgw/driver/rados/oidc.cc
src/rgw/driver/rados/oidc.h
src/rgw/driver/rados/oidcs.cc [new file with mode: 0644]
src/rgw/driver/rados/oidcs.h [new file with mode: 0644]

index 41b349bdd9fbd7d90c98bccf0ecae1a2414ad94e..86578969ddc1584d97d8f771fc4481982df53c72 100644 (file)
@@ -217,6 +217,7 @@ if(WITH_RADOSGW_RADOS)
           driver/rados/rgw_trim_mdlog.cc
           driver/rados/rgw_user.cc
           driver/rados/oidc.cc
+          driver/rados/oidcs.cc
           driver/rados/role.cc
           driver/rados/roles.cc
           driver/rados/sync_fairness.cc
index cd65f0fdd0f48e1be4fc7f92d846459d1f45f29d..d746c7d2dbffb6d0ca6693a2ef796895ad70a429 100644 (file)
@@ -37,6 +37,7 @@ static constexpr std::string_view users_oid_prefix = "users.";
 static constexpr std::string_view groups_oid_prefix = "groups.";
 static constexpr std::string_view roles_oid_prefix = "roles.";
 static constexpr std::string_view topics_oid_prefix = "topics.";
+static constexpr std::string_view oidcs_oid_prefix = "oidcs.";
 static const std::string account_oid_prefix = "account.";
 static constexpr std::string_view name_oid_prefix = "name.";
 
@@ -81,6 +82,14 @@ rgw_raw_obj get_topics_obj(const RGWZoneParams& zone,
   return {zone.account_pool, get_topics_key(account_id)};
 }
 
+static std::string get_oidcs_key(std::string_view account_id) {
+  return string_cat_reserve(oidcs_oid_prefix, account_id);
+}
+rgw_raw_obj get_oidcs_obj(const RGWZoneParams& zone,
+                          std::string_view account_id) {
+  return {zone.account_pool, get_oidcs_key(account_id)};
+}
+
 static std::string get_account_key(std::string_view account_id) {
   return string_cat_reserve(account_oid_prefix, account_id);
 }
index 2a54e4b5c16641167a9acdf8139b9402a510eaa0..9fb407911ec0cba81a33886c648051122cfd5c05 100644 (file)
@@ -66,6 +66,12 @@ rgw_raw_obj get_roles_obj(const RGWZoneParams& zone,
 rgw_raw_obj get_topics_obj(const RGWZoneParams& zone,
                            std::string_view account_id);
 
+/// Return the rados object that tracks the given account's OIDC providers. This
+/// can be used with the cls_user interface in namespace rgwrados::oidcs.
+rgw_raw_obj get_oidcs_obj(
+    const RGWZoneParams& zone,
+    std::string_view account_id);
+
 
 /// Read account info by id
 int read(const DoutPrefixProvider* dpp,
index d4df60ef5e97cda1a517e3615507c98669efc2f2..31881d3e3a9fd58b21f8a248c1ed36d2b85a3da1 100644 (file)
 
 #include "oidc.h"
 
+#include <limits>
+
+#include "account.h"
+#include "oidcs.h"
 #include "common/errno.h"
+#include "rgw_account.h"
 #include "rgw_common.h"
 #include "rgw_metadata.h"
 #include "rgw_metadata_lister.h"
@@ -151,6 +156,17 @@ write(
     return r;
   }
 
+  if (rgw::account::validate_id(info.tenant)) {
+    // link the OIDC provider to its account
+    const auto& oidcs = account::get_oidcs_obj(zone, info.tenant);
+    r = oidcs::add(
+        dpp, y, rados, oidcs, info, false,
+        std::numeric_limits<uint32_t>::max());
+    if (r < 0) {
+      ldpp_dout(dpp, 0) << "WARNING: could not link OIDC provider to account "
+          << info.tenant << ": " << cpp_strerror(r) << dendl;
+    } // not fatal
+  }
 
   // record in the mdlog on success
   if (mdlog) {
@@ -183,6 +199,15 @@ remove(
     return r;
   }
 
+  if (rgw::account::validate_id(tenant)) {
+    // unlink the OIDC provider from its account
+    const auto& oidcs = account::get_oidcs_obj(zone, std::string(tenant));
+    r = oidcs::remove(dpp, y, rados, oidcs, url);
+    if (r < 0) {
+      ldpp_dout(dpp, 0) << "ERROR: could not unlink OIDC provider from account "
+          << tenant << ": " << cpp_strerror(r) << dendl;
+    } // not fatal
+  }
 
   // record in the mdlog on success
   if (mdlog) {
@@ -201,6 +226,11 @@ list(
     std::string_view tenant,
     std::vector<RGWOIDCProviderInfo>& providers)
 {
+  // Use optimized account index if tenant is an account
+  if (rgw::account::validate_id(tenant)) {
+    return list_account_oidcs(dpp, y, sysobj, rados, zone, tenant, providers);
+  }
+
   // Prefix format: "{tenant}oidc_url." to match original implementation
   std::string prefix = string_cat_reserve(tenant, oidc_url_oid_prefix);
   auto& pool = zone.oidc_pool;
@@ -253,6 +283,69 @@ list(
   return 0;
 }
 
+int
+list_oidc_urls(
+    const DoutPrefixProvider* dpp,
+    optional_yield y,
+    librados::Rados& rados,
+    const RGWZoneParams& zone,
+    std::string_view account_id,
+    std::string_view marker,
+    uint32_t max_items,
+    std::vector<std::string>& urls,
+    std::string& next_marker)
+{
+  const rgw_raw_obj obj = account::get_oidcs_obj(zone, account_id);
+  return oidcs::list(dpp, y, rados, obj, marker, max_items, urls, next_marker);
+}
+
+int
+list_account_oidcs(
+    const DoutPrefixProvider* dpp,
+    optional_yield y,
+    RGWSI_SysObj& sysobj,
+    librados::Rados& rados,
+    const RGWZoneParams& zone,
+    std::string_view account_id,
+    std::vector<RGWOIDCProviderInfo>& providers)
+{
+  // Use the account index to get OIDC provider URLs
+  std::vector<std::string> urls;
+  std::string marker;
+  std::string next_marker;
+
+  do {
+    urls.clear();
+    int r = list_oidc_urls(dpp, y, rados, zone, account_id, marker,
+                           1000, urls, next_marker);
+    if (r < 0) {
+      ldpp_dout(dpp, 0) << "ERROR: failed to list OIDC provider URLs for account "
+          << account_id << ": " << cpp_strerror(r) << dendl;
+      return r;
+    }
+
+    for (const auto& url : urls) {
+      RGWOIDCProviderInfo info;
+      r = read(dpp, y, sysobj, zone, account_id, url, info);
+      if (r == -ENOENT) {
+        // OIDC provider was deleted, skip it
+        ldpp_dout(dpp, 10) << "OIDC provider " << url << " not found, skipping" << dendl;
+        continue;
+      }
+      if (r < 0) {
+        ldpp_dout(dpp, 0) << "ERROR: failed to read OIDC provider " << url
+            << ": " << cpp_strerror(r) << dendl;
+        return r;
+      }
+      providers.push_back(std::move(info));
+    }
+
+    marker = next_marker;
+  } while (!next_marker.empty());
+
+  return 0;
+}
+
 
 class MetadataObject : public RGWMetadataObject {
   RGWOIDCProviderInfo info;
index ab1e845570c4671bb45b1ae85e160b456477ab03..91e39fc12d51700a331209db7bcf924693550e3a 100644 (file)
@@ -79,6 +79,28 @@ int list(
     std::string_view tenant,
     std::vector<RGWOIDCProviderInfo>& providers);
 
+/// List OIDC provider URLs for an account (paginated).
+int list_oidc_urls(
+    const DoutPrefixProvider* dpp,
+    optional_yield y,
+    librados::Rados& rados,
+    const RGWZoneParams& zone,
+    std::string_view account_id,
+    std::string_view marker,
+    uint32_t max_items,
+    std::vector<std::string>& urls,
+    std::string& next_marker);
+
+/// List all OIDC providers for an account using optimized account index.
+int list_account_oidcs(
+    const DoutPrefixProvider* dpp,
+    optional_yield y,
+    RGWSI_SysObj& sysobj,
+    librados::Rados& rados,
+    const RGWZoneParams& zone,
+    std::string_view account_id,
+    std::vector<RGWOIDCProviderInfo>& providers);
+
 /// OIDC provider metadata handler factory.
 auto create_metadata_handler(
     librados::Rados& rados,
diff --git a/src/rgw/driver/rados/oidcs.cc b/src/rgw/driver/rados/oidcs.cc
new file mode 100644 (file)
index 0000000..4d38cb2
--- /dev/null
@@ -0,0 +1,116 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab ft=cpp
+
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright contributors to the Ceph project
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#include "oidcs.h"
+
+#include "include/rados/librados.hpp"
+#include "cls/user/cls_user_client.h"
+#include "rgw_common.h"
+#include "rgw_oidc_provider.h"
+#include "rgw_sal.h"
+
+namespace rgwrados::oidcs {
+
+int
+add(
+    const DoutPrefixProvider* dpp,
+    optional_yield y,
+    librados::Rados& rados,
+    const rgw_raw_obj& obj,
+    const RGWOIDCProviderInfo& info,
+    bool exclusive,
+    uint32_t limit)
+{
+  cls_user_account_resource resource;
+  resource.name = url_remove_prefix(info.provider_url);
+
+  rgw_rados_ref ref;
+  int r = rgw_get_rados_ref(dpp, &rados, obj, &ref);
+  if (r < 0) {
+    return r;
+  }
+
+  librados::ObjectWriteOperation op;
+  ::cls_user_account_resource_add(op, resource, exclusive, limit);
+  return ref.operate(dpp, std::move(op), y);
+}
+
+int
+remove(
+    const DoutPrefixProvider* dpp,
+    optional_yield y,
+    librados::Rados& rados,
+    const rgw_raw_obj& obj,
+    std::string_view provider_url)
+{
+  rgw_rados_ref ref;
+  int r = rgw_get_rados_ref(dpp, &rados, obj, &ref);
+  if (r < 0) {
+    return r;
+  }
+
+  librados::ObjectWriteOperation op;
+  ::cls_user_account_resource_rm(op, provider_url);
+  return ref.operate(dpp, std::move(op), y);
+}
+
+int
+list(
+    const DoutPrefixProvider* dpp,
+    optional_yield y,
+    librados::Rados& rados,
+    const rgw_raw_obj& obj,
+    std::string_view marker,
+    uint32_t max_items,
+    std::vector<std::string>& provider_urls,
+    std::string& next_marker)
+{
+  rgw_rados_ref ref;
+  int r = rgw_get_rados_ref(dpp, &rados, obj, &ref);
+  if (r < 0) {
+    return r;
+  }
+
+  librados::ObjectReadOperation op;
+  const std::string path_prefix; // unused
+  std::vector<cls_user_account_resource> entries;
+  bool truncated = false;
+  int ret = 0;
+  ::cls_user_account_resource_list(
+      op, marker, path_prefix, max_items,
+      entries, &truncated, &next_marker, &ret);
+
+  r = ref.operate(dpp, std::move(op), nullptr, y);
+  if (r == -ENOENT) {
+    next_marker.clear();
+    return 0;
+  }
+  if (r < 0) {
+    return r;
+  }
+  if (ret < 0) {
+    return ret;
+  }
+
+  for (auto& resource : entries) {
+    provider_urls.push_back(std::move(resource.name));
+  }
+
+  return 0;
+}
+
+} // namespace rgwrados::oidcs
+
+
diff --git a/src/rgw/driver/rados/oidcs.h b/src/rgw/driver/rados/oidcs.h
new file mode 100644 (file)
index 0000000..af833b3
--- /dev/null
@@ -0,0 +1,59 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab ft=cpp
+
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright contributors to the Ceph project
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include <vector>
+#include "include/rados/librados_fwd.hpp"
+#include "rgw_sal_fwd.h"
+
+class DoutPrefixProvider;
+class optional_yield;
+struct rgw_raw_obj;
+struct RGWOIDCProviderInfo;
+
+
+namespace rgwrados::oidcs {
+
+/// Add the given OIDC provider to the list.
+int add(const DoutPrefixProvider* dpp,
+        optional_yield y,
+        librados::Rados& rados,
+        const rgw_raw_obj& obj,
+        const RGWOIDCProviderInfo& info,
+        bool exclusive, uint32_t limit);
+
+/// Remove the given OIDC provider from the list.
+int remove(const DoutPrefixProvider* dpp,
+           optional_yield y,
+           librados::Rados& rados,
+           const rgw_raw_obj& obj,
+           std::string_view provider_url);
+
+/// Return a paginated listing of OIDC provider URLs.
+int list(const DoutPrefixProvider* dpp,
+         optional_yield y,
+         librados::Rados& rados,
+         const rgw_raw_obj& obj,
+         std::string_view marker,
+         uint32_t max_items,
+         std::vector<std::string>& provider_urls,
+         std::string& next_marker);
+
+} // namespace rgwrados::oidcs
+
+