From 19fcec84d8d7d21e796c7624e521b60d28ee21ed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:45:59 +0200 Subject: Adding upstream version 16.2.11+ds. Signed-off-by: Daniel Baumann --- src/rgw/rgw_oidc_provider.cc | 297 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 src/rgw/rgw_oidc_provider.cc (limited to 'src/rgw/rgw_oidc_provider.cc') diff --git a/src/rgw/rgw_oidc_provider.cc b/src/rgw/rgw_oidc_provider.cc new file mode 100644 index 000000000..757ae90ca --- /dev/null +++ b/src/rgw/rgw_oidc_provider.cc @@ -0,0 +1,297 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +#include +#include +#include + +#include "common/errno.h" +#include "common/Formatter.h" +#include "common/ceph_json.h" +#include "common/ceph_time.h" +#include "rgw_rados.h" +#include "rgw_zone.h" + +#include "include/types.h" +#include "rgw_string.h" + +#include "rgw_common.h" +#include "rgw_tools.h" +#include "rgw_oidc_provider.h" + +#include "services/svc_zone.h" +#include "services/svc_sys_obj.h" + +#define dout_subsys ceph_subsys_rgw + +const string RGWOIDCProvider::oidc_url_oid_prefix = "oidc_url."; +const string RGWOIDCProvider::oidc_arn_prefix = "arn:aws:iam::"; + +int RGWOIDCProvider::store_url(const DoutPrefixProvider *dpp, const string& url, bool exclusive, + optional_yield y) +{ + using ceph::encode; + string oid = tenant + get_url_oid_prefix() + url; + + auto svc = ctl->svc; + + bufferlist bl; + encode(*this, bl); + auto obj_ctx = svc->sysobj->init_obj_ctx(); + return rgw_put_system_obj(dpp, obj_ctx, svc->zone->get_zone_params().oidc_pool, oid, + bl, exclusive, NULL, real_time(), y); +} + +int RGWOIDCProvider::get_tenant_url_from_arn(string& tenant, string& url) +{ + auto provider_arn = rgw::ARN::parse(arn); + if (!provider_arn) { + return -EINVAL; + } + url = provider_arn->resource; + tenant = provider_arn->account; + auto pos = url.find("oidc-provider/"); + if (pos != std::string::npos) { + url.erase(pos, 14); + } + return 0; +} + +int RGWOIDCProvider::create(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) +{ + int ret; + + if (! validate_input()) { + return -EINVAL; + } + + string idp_url = url_remove_prefix(provider_url); + + /* check to see the name is not used */ + ret = read_url(dpp, idp_url, tenant); + if (exclusive && ret == 0) { + ldpp_dout(dpp, 0) << "ERROR: url " << provider_url << " already in use" + << id << dendl; + return -EEXIST; + } else if ( ret < 0 && ret != -ENOENT) { + ldpp_dout(dpp, 0) << "failed reading provider url " << provider_url << ": " + << cpp_strerror(-ret) << dendl; + return ret; + } + + //arn + arn = oidc_arn_prefix + tenant + ":oidc-provider/" + idp_url; + + // Creation time + real_clock::time_point t = real_clock::now(); + + struct timeval tv; + real_clock::to_timeval(t, tv); + + char buf[30]; + struct tm result; + gmtime_r(&tv.tv_sec, &result); + strftime(buf,30,"%Y-%m-%dT%H:%M:%S", &result); + sprintf(buf + strlen(buf),".%dZ",(int)tv.tv_usec/1000); + creation_date.assign(buf, strlen(buf)); + + auto svc = ctl->svc; + + auto& pool = svc->zone->get_zone_params().oidc_pool; + ret = store_url(dpp, idp_url, exclusive, y); + if (ret < 0) { + ldpp_dout(dpp, 0) << "ERROR: storing role info in pool: " << pool.name << ": " + << provider_url << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + + return 0; +} + +int RGWOIDCProvider::delete_obj(const DoutPrefixProvider *dpp, optional_yield y) +{ + auto svc = ctl->svc; + auto& pool = svc->zone->get_zone_params().oidc_pool; + + string url, tenant; + auto ret = get_tenant_url_from_arn(tenant, url); + if (ret < 0) { + ldpp_dout(dpp, 0) << "ERROR: failed to parse arn" << dendl; + return -EINVAL; + } + + if (this->tenant != tenant) { + ldpp_dout(dpp, 0) << "ERROR: tenant in arn doesn't match that of user " << this->tenant << ", " + << tenant << ": " << dendl; + return -EINVAL; + } + + // Delete url + string oid = tenant + get_url_oid_prefix() + url; + ret = rgw_delete_system_obj(dpp, svc->sysobj, pool, oid, NULL, y); + if (ret < 0) { + ldpp_dout(dpp, 0) << "ERROR: deleting oidc url from pool: " << pool.name << ": " + << provider_url << ": " << cpp_strerror(-ret) << dendl; + } + + return ret; +} + +int RGWOIDCProvider::get(const DoutPrefixProvider *dpp) +{ + string url, tenant; + auto ret = get_tenant_url_from_arn(tenant, url); + if (ret < 0) { + ldpp_dout(dpp, 0) << "ERROR: failed to parse arn" << dendl; + return -EINVAL; + } + + if (this->tenant != tenant) { + ldpp_dout(dpp, 0) << "ERROR: tenant in arn doesn't match that of user " << this->tenant << ", " + << tenant << ": " << dendl; + return -EINVAL; + } + + ret = read_url(dpp, url, tenant); + if (ret < 0) { + return ret; + } + + return 0; +} + +void RGWOIDCProvider::dump(Formatter *f) const +{ + encode_json("OpenIDConnectProviderArn", arn, f); +} + +void RGWOIDCProvider::dump_all(Formatter *f) const +{ + f->open_object_section("ClientIDList"); + for (auto it : client_ids) { + encode_json("member", it, f); + } + f->close_section(); + encode_json("CreateDate", creation_date, f); + f->open_object_section("ThumbprintList"); + for (auto it : thumbprints) { + encode_json("member", it, f); + } + f->close_section(); + encode_json("Url", provider_url, f); +} + +void RGWOIDCProvider::decode_json(JSONObj *obj) +{ + JSONDecoder::decode_json("OpenIDConnectProviderArn", arn, obj); +} + +int RGWOIDCProvider::read_url(const DoutPrefixProvider *dpp, const string& url, const string& tenant) +{ + auto svc = ctl->svc; + auto& pool = svc->zone->get_zone_params().oidc_pool; + string oid = tenant + get_url_oid_prefix() + url; + bufferlist bl; + auto obj_ctx = svc->sysobj->init_obj_ctx(); + + int ret = rgw_get_system_obj(obj_ctx, pool, oid, bl, NULL, NULL, null_yield, dpp); + if (ret < 0) { + return ret; + } + + try { + using ceph::decode; + auto iter = bl.cbegin(); + decode(*this, iter); + } catch (buffer::error& err) { + ldpp_dout(dpp, 0) << "ERROR: failed to decode oidc provider info from pool: " << pool.name << + ": " << url << dendl; + return -EIO; + } + + return 0; +} + +bool RGWOIDCProvider::validate_input() +{ + if (provider_url.length() > MAX_OIDC_URL_LEN) { + ldout(cct, 0) << "ERROR: Invalid length of url " << dendl; + return false; + } + if (client_ids.size() > MAX_OIDC_NUM_CLIENT_IDS) { + ldout(cct, 0) << "ERROR: Invalid number of client ids " << dendl; + return false; + } + + for (auto& it : client_ids) { + if (it.length() > MAX_OIDC_CLIENT_ID_LEN) { + return false; + } + } + + if (thumbprints.size() > MAX_OIDC_NUM_THUMBPRINTS) { + ldout(cct, 0) << "ERROR: Invalid number of thumbprints " << thumbprints.size() << dendl; + return false; + } + + for (auto& it : thumbprints) { + if (it.length() > MAX_OIDC_THUMBPRINT_LEN) { + return false; + } + } + + return true; +} + +int RGWOIDCProvider::get_providers(const DoutPrefixProvider *dpp, RGWRados *store, + const string& tenant, + vector& providers) +{ + auto ctl = store->pctl; + auto svc = ctl->svc; + auto pool = store->svc.zone->get_zone_params().oidc_pool; + string prefix = tenant + oidc_url_oid_prefix; + + //Get the filtered objects + list result; + bool is_truncated; + RGWListRawObjsCtx ctx; + do { + list oids; + int r = store->list_raw_objects(dpp, pool, prefix, 1000, ctx, oids, &is_truncated); + if (r < 0) { + ldpp_dout(dpp, 0) << "ERROR: listing filtered objects failed: " << pool.name << ": " + << prefix << ": " << cpp_strerror(-r) << dendl; + return r; + } + for (const auto& iter : oids) { + RGWOIDCProvider provider(ctl->cct, store->pctl); + bufferlist bl; + auto obj_ctx = svc->sysobj->init_obj_ctx(); + + int ret = rgw_get_system_obj(obj_ctx, pool, iter, bl, NULL, NULL, null_yield, dpp); + if (ret < 0) { + return ret; + } + + try { + using ceph::decode; + auto iter = bl.cbegin(); + decode(provider, iter); + } catch (buffer::error& err) { + ldpp_dout(dpp, 0) << "ERROR: failed to decode oidc provider info from pool: " << pool.name << + ": " << iter << dendl; + return -EIO; + } + + providers.push_back(std::move(provider)); + } + } while (is_truncated); + + return 0; +} + +const string& RGWOIDCProvider::get_url_oid_prefix() +{ + return oidc_url_oid_prefix; +} -- cgit v1.2.3