diff options
author | Yehuda Sadeh <yehuda@redhat.com> | 2019-02-07 01:01:48 +0100 |
---|---|---|
committer | Casey Bodley <cbodley@redhat.com> | 2019-07-29 21:20:46 +0200 |
commit | 91f12786c05148fc5446c47b17e3e6c75cd00d31 (patch) | |
tree | c16009280523bdada26406760a8db8be4a2c2a9e /src/rgw | |
parent | rgw: move manifest code around, initial tier separation (diff) | |
download | ceph-91f12786c05148fc5446c47b17e3e6c75cd00d31.tar.xz ceph-91f12786c05148fc5446c47b17e3e6c75cd00d31.zip |
rgw: svc/mfa: new service for mfa functionality
Signed-off-by: Yehuda Sadeh <yehuda@redhat.com>
Diffstat (limited to 'src/rgw')
-rw-r--r-- | src/rgw/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/rgw/rgw_service.cc | 9 | ||||
-rw-r--r-- | src/rgw/rgw_service.h | 3 | ||||
-rw-r--r-- | src/rgw/services/svc_mfa.cc | 237 | ||||
-rw-r--r-- | src/rgw/services/svc_mfa.h | 68 |
5 files changed, 318 insertions, 0 deletions
diff --git a/src/rgw/CMakeLists.txt b/src/rgw/CMakeLists.txt index 365e369e8ac..683f5e74aa9 100644 --- a/src/rgw/CMakeLists.txt +++ b/src/rgw/CMakeLists.txt @@ -21,6 +21,7 @@ endfunction() set(librgw_common_srcs services/svc_finisher.cc + services/svc_mfa.cc services/svc_notify.cc services/svc_quota.cc services/svc_sync_modules.cc diff --git a/src/rgw/rgw_service.cc b/src/rgw/rgw_service.cc index 0369806c0d9..83c22de4f9c 100644 --- a/src/rgw/rgw_service.cc +++ b/src/rgw/rgw_service.cc @@ -4,6 +4,7 @@ #include "rgw_service.h" #include "services/svc_finisher.h" +#include "services/svc_mfa.h" #include "services/svc_notify.h" #include "services/svc_rados.h" #include "services/svc_zone.h" @@ -30,6 +31,7 @@ int RGWServices_Def::init(CephContext *cct, bool raw) { finisher = std::make_unique<RGWSI_Finisher>(cct); + mfa = std::make_unique<RGWSI_MFA>(cct); notify = std::make_unique<RGWSI_Notify>(cct); rados = std::make_unique<RGWSI_RADOS>(cct); zone = std::make_unique<RGWSI_Zone>(cct); @@ -43,6 +45,7 @@ int RGWServices_Def::init(CephContext *cct, sysobj_cache = std::make_unique<RGWSI_SysObj_Cache>(cct); } finisher->init(); + mfa->init(zone.get(), rados.get()); notify->init(zone.get(), rados.get(), finisher.get()); rados->init(); zone->init(sysobj.get(), rados.get(), sync_modules.get()); @@ -87,6 +90,12 @@ int RGWServices_Def::init(CephContext *cct, } } + r = mfa->start(); + if (r < 0) { + ldout(cct, 0) << "ERROR: failed to start mfa service (" << cpp_strerror(-r) << dendl; + return r; + } + r = zone_utils->start(); if (r < 0) { ldout(cct, 0) << "ERROR: failed to start zone_utils service (" << cpp_strerror(-r) << dendl; diff --git a/src/rgw/rgw_service.h b/src/rgw/rgw_service.h index 316bacdb6ca..282be223f8d 100644 --- a/src/rgw/rgw_service.h +++ b/src/rgw/rgw_service.h @@ -45,6 +45,7 @@ public: }; class RGWSI_Finisher; +class RGWSI_MFA; class RGWSI_Notify; class RGWSI_RADOS; class RGWSI_Zone; @@ -61,6 +62,7 @@ struct RGWServices_Def bool has_shutdown{false}; std::unique_ptr<RGWSI_Finisher> finisher; + std::unique_ptr<RGWSI_MFA> mfa; std::unique_ptr<RGWSI_Notify> notify; std::unique_ptr<RGWSI_RADOS> rados; std::unique_ptr<RGWSI_Zone> zone; @@ -84,6 +86,7 @@ struct RGWServices RGWServices_Def _svc; RGWSI_Finisher *finisher{nullptr}; + RGWSI_MFA *mfa{nullptr}; RGWSI_Notify *notify{nullptr}; RGWSI_RADOS *rados{nullptr}; RGWSI_Zone *zone{nullptr}; diff --git a/src/rgw/services/svc_mfa.cc b/src/rgw/services/svc_mfa.cc new file mode 100644 index 00000000000..438eb816559 --- /dev/null +++ b/src/rgw/services/svc_mfa.cc @@ -0,0 +1,237 @@ + + +#include "svc_mfa.h" +#include "svc_rados.h" +#include "svc_zone.h" + +#include "rgw/rgw_zone.h" + +#include "cls/otp/cls_otp_client.h" + + +#define dout_subsys ceph_subsys_rgw + + +int RGWSI_MFA::get_mfa_obj(const rgw_user& user, std::optional<RGWSI_RADOS::Obj> *obj) { + string oid = get_mfa_oid(user); + rgw_raw_obj o(zone_svc->get_zone_params().otp_pool, oid); + + obj->emplace(rados_svc->obj(o)); + int r = (*obj)->open(); + if (r < 0) { + ldout(cct, 4) << "failed to open rados context for " << o << dendl; + return r; + } + + return 0; +} + +int RGWSI_MFA::get_mfa_ref(const rgw_user& user, rgw_rados_ref *ref) { + std::optional<RGWSI_RADOS::Obj> obj; + int r = get_mfa_obj(user, &obj); + if (r < 0) { + return r; + } + *ref = obj->get_ref(); + return 0; +} + +int RGWSI_MFA::check_mfa(const rgw_user& user, const string& otp_id, const string& pin, optional_yield y) +{ + rgw_rados_ref ref; + int r = get_mfa_ref(user, &ref); + if (r < 0) { + return r; + } + + rados::cls::otp::otp_check_t result; + + r = rados::cls::otp::OTP::check(cct, ref.ioctx, ref.obj.oid, otp_id, pin, &result); + if (r < 0) + return r; + + ldout(cct, 20) << "OTP check, otp_id=" << otp_id << " result=" << (int)result.result << dendl; + + return (result.result == rados::cls::otp::OTP_CHECK_SUCCESS ? 0 : -EACCES); +} + +void RGWSI_MFA::prepare_mfa_write(librados::ObjectWriteOperation *op, + RGWObjVersionTracker *objv_tracker, + const ceph::real_time& mtime) +{ + RGWObjVersionTracker ot; + + if (objv_tracker) { + ot = *objv_tracker; + } + + if (ot.write_version.tag.empty()) { + if (ot.read_version.tag.empty()) { + ot.generate_new_write_ver(cct); + } else { + ot.write_version = ot.read_version; + ot.write_version.ver++; + } + } + + ot.prepare_op_for_write(op); + struct timespec mtime_ts = real_clock::to_timespec(mtime); + op->mtime2(&mtime_ts); +} + +int RGWSI_MFA::create_mfa(const rgw_user& user, const rados::cls::otp::otp_info_t& config, + RGWObjVersionTracker *objv_tracker, const ceph::real_time& mtime, optional_yield y) +{ + std::optional<RGWSI_RADOS::Obj> obj; + int r = get_mfa_obj(user, &obj); + if (r < 0) { + return r; + } + + librados::ObjectWriteOperation op; + prepare_mfa_write(&op, objv_tracker, mtime); + rados::cls::otp::OTP::create(&op, config); + r = obj->operate(&op, y); + if (r < 0) { + ldout(cct, 20) << "OTP create, otp_id=" << config.id << " result=" << (int)r << dendl; + return r; + } + + return 0; +} + +int RGWSI_MFA::remove_mfa(const rgw_user& user, const string& id, + RGWObjVersionTracker *objv_tracker, + const ceph::real_time& mtime, + optional_yield y) +{ + std::optional<RGWSI_RADOS::Obj> obj; + int r = get_mfa_obj(user, &obj); + if (r < 0) { + return r; + } + + librados::ObjectWriteOperation op; + prepare_mfa_write(&op, objv_tracker, mtime); + rados::cls::otp::OTP::remove(&op, id); + r = obj->operate(&op, y); + if (r < 0) { + ldout(cct, 20) << "OTP remove, otp_id=" << id << " result=" << (int)r << dendl; + return r; + } + + return 0; +} + +int RGWSI_MFA::get_mfa(const rgw_user& user, const string& id, rados::cls::otp::otp_info_t *result, + optional_yield y) +{ + rgw_rados_ref ref; + + int r = get_mfa_ref(user, &ref); + if (r < 0) { + return r; + } + + r = rados::cls::otp::OTP::get(nullptr, ref.ioctx, ref.obj.oid, id, result); + if (r < 0) { + return r; + } + + return 0; +} + +int RGWSI_MFA::list_mfa(const rgw_user& user, list<rados::cls::otp::otp_info_t> *result, + optional_yield y) +{ + rgw_rados_ref ref; + + int r = get_mfa_ref(user, &ref); + if (r < 0) { + return r; + } + + r = rados::cls::otp::OTP::get_all(nullptr, ref.ioctx, ref.obj.oid, result); + if (r < 0) { + return r; + } + + return 0; +} + +int RGWSI_MFA::otp_get_current_time(const rgw_user& user, ceph::real_time *result, + optional_yield y) +{ + rgw_rados_ref ref; + + int r = get_mfa_ref(user, &ref); + if (r < 0) { + return r; + } + + r = rados::cls::otp::OTP::get_current_time(ref.ioctx, ref.obj.oid, result); + if (r < 0) { + return r; + } + + return 0; +} + +int RGWSI_MFA::set_mfa(const string& oid, const list<rados::cls::otp::otp_info_t>& entries, + bool reset_obj, RGWObjVersionTracker *objv_tracker, + const real_time& mtime, + optional_yield y) +{ + rgw_raw_obj o(zone_svc->get_zone_params().otp_pool, oid); + auto obj = rados_svc->obj(o); + int r = obj.open(); + if (r < 0) { + ldout(cct, 4) << "failed to open rados context for " << o << dendl; + return r; + } + librados::ObjectWriteOperation op; + if (reset_obj) { + op.remove(); + op.set_op_flags2(LIBRADOS_OP_FLAG_FAILOK); + op.create(false); + } + prepare_mfa_write(&op, objv_tracker, mtime); + rados::cls::otp::OTP::set(&op, entries); + r = obj.operate(&op, y); + if (r < 0) { + ldout(cct, 20) << "OTP set entries.size()=" << entries.size() << " result=" << (int)r << dendl; + return r; + } + + return 0; +} + +int RGWSI_MFA::list_mfa(const string& oid, list<rados::cls::otp::otp_info_t> *result, + RGWObjVersionTracker *objv_tracker, ceph::real_time *pmtime, + optional_yield y) +{ + rgw_raw_obj o(zone_svc->get_zone_params().otp_pool, oid); + auto obj = rados_svc->obj(o); + int r = obj.open(); + if (r < 0) { + ldout(cct, 4) << "failed to open rados context for " << o << dendl; + return r; + } + auto& ref = obj.get_ref(); + librados::ObjectReadOperation op; + struct timespec mtime_ts; + if (pmtime) { + op.stat2(nullptr, &mtime_ts, nullptr); + } + objv_tracker->prepare_op_for_read(&op); + r = rados::cls::otp::OTP::get_all(&op, ref.ioctx, ref.obj.oid, result); + if (r < 0) { + return r; + } + if (pmtime) { + *pmtime = ceph::real_clock::from_timespec(mtime_ts); + } + + return 0; +} + diff --git a/src/rgw/services/svc_mfa.h b/src/rgw/services/svc_mfa.h new file mode 100644 index 00000000000..be51cbdbc87 --- /dev/null +++ b/src/rgw/services/svc_mfa.h @@ -0,0 +1,68 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2019 Red Hat, Inc. + * + * 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 "cls/otp/cls_otp_types.h" + +#include "rgw/rgw_service.h" + +#include "svc_rados.h" + + +class RGWSI_MFA : public RGWServiceInstance +{ + RGWSI_Zone *zone_svc{nullptr}; + RGWSI_RADOS *rados_svc{nullptr}; + + string get_mfa_oid(const rgw_user& user) { + return string("user:") + user.to_str(); + } + + int get_mfa_obj(const rgw_user& user, std::optional<RGWSI_RADOS::Obj> *obj); + int get_mfa_ref(const rgw_user& user, rgw_rados_ref *ref); + + void prepare_mfa_write(librados::ObjectWriteOperation *op, + RGWObjVersionTracker *objv_tracker, + const ceph::real_time& mtime); + +public: + RGWSI_MFA(CephContext *cct): RGWServiceInstance(cct) {} + + void init(RGWSI_Zone *_zone_svc, RGWSI_RADOS *_rados_svc) { + rados_svc = _rados_svc; + zone_svc = _zone_svc; + } + + int check_mfa(const rgw_user& user, const string& otp_id, const string& pin, optional_yield y); + int create_mfa(const rgw_user& user, const rados::cls::otp::otp_info_t& config, + RGWObjVersionTracker *objv_tracker, const ceph::real_time& mtime, optional_yield y); + int remove_mfa(const rgw_user& user, const string& id, + RGWObjVersionTracker *objv_tracker, + const ceph::real_time& mtime, + optional_yield y); + int get_mfa(const rgw_user& user, const string& id, rados::cls::otp::otp_info_t *result, optional_yield y); + int list_mfa(const rgw_user& user, list<rados::cls::otp::otp_info_t> *result, optional_yield y); + int otp_get_current_time(const rgw_user& user, ceph::real_time *result, optional_yield y); + int set_mfa(const string& oid, const list<rados::cls::otp::otp_info_t>& entries, + bool reset_obj, RGWObjVersionTracker *objv_tracker, + const real_time& mtime, optional_yield y); + int list_mfa(const string& oid, list<rados::cls::otp::otp_info_t> *result, + RGWObjVersionTracker *objv_tracker, ceph::real_time *pmtime, optional_yield y); +}; + + + |