From 2c160418472ee0598262816bffb185d635611232 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Sun, 3 Dec 2017 05:53:22 -0800 Subject: [PATCH] rgw-admin: add mfa resync command $ radosgw-admin mfa resync --uid= --totp=serial= \ --totp-pin= --totp-pin= Signed-off-by: Yehuda Sadeh --- src/cls/otp/cls_otp.cc | 2 +- src/cls/otp/cls_otp_types.cc | 6 +- src/cls/otp/cls_otp_types.h | 2 +- src/rgw/CMakeLists.txt | 3 +- src/rgw/rgw_admin.cc | 126 ++++++++++++++++++++++++++++++++++- 5 files changed, 129 insertions(+), 10 deletions(-) diff --git a/src/cls/otp/cls_otp.cc b/src/cls/otp/cls_otp.cc index 1519ea47025e0..a8ca2b5afaefb 100644 --- a/src/cls/otp/cls_otp.cc +++ b/src/cls/otp/cls_otp.cc @@ -132,7 +132,7 @@ bool otp_instance::verify(const ceph::real_time& timestamp, const string& val) } result = oath_totp_validate3(secret, slen, - secs, otp.step_size, 0, otp.window, + secs, otp.step_size, otp.time_ofs, otp.window, nullptr /* otp pos */, &index, val.c_str()); if (result == OATH_INVALID_OTP || diff --git a/src/cls/otp/cls_otp_types.cc b/src/cls/otp/cls_otp_types.cc index a73b74e997c5a..159b3604966cb 100644 --- a/src/cls/otp/cls_otp_types.cc +++ b/src/cls/otp/cls_otp_types.cc @@ -28,7 +28,7 @@ void otp_info_t::dump(Formatter *f) const encode_json("type", (int)type, f); encode_json("id", id, f); encode_json("seed", seed, f); - encode_json("time_ofs", utime_t(time_ofs), f); + encode_json("time_ofs", time_ofs, f); encode_json("step_size", step_size, f); encode_json("window", window, f); } @@ -40,9 +40,7 @@ void otp_info_t::decode_json(JSONObj *obj) type = (OTPType)t; JSONDecoder::decode_json("id", id, obj); JSONDecoder::decode_json("seed", seed, obj); - utime_t to; - JSONDecoder::decode_json("time_ofs", to, obj); - time_ofs = to.to_real_time(); + JSONDecoder::decode_json("time_ofs", time_ofs, obj); JSONDecoder::decode_json("step_size", step_size, obj); JSONDecoder::decode_json("window", window, obj); } diff --git a/src/cls/otp/cls_otp_types.h b/src/cls/otp/cls_otp_types.h index 7810461e60b8f..ff4e4059e3d06 100644 --- a/src/cls/otp/cls_otp_types.h +++ b/src/cls/otp/cls_otp_types.h @@ -23,7 +23,7 @@ namespace rados { OTPType type{OTP_TOTP}; string id; string seed; - ceph::real_time time_ofs; + int32_t time_ofs{0}; uint32_t step_size{30}; /* num of seconds foreach otp to test */ uint32_t window{2}; /* num of otp after/before start otp to test */ diff --git a/src/rgw/CMakeLists.txt b/src/rgw/CMakeLists.txt index 8ec7f19ddcc84..606bdcd72e2bc 100644 --- a/src/rgw/CMakeLists.txt +++ b/src/rgw/CMakeLists.txt @@ -155,7 +155,8 @@ target_link_libraries(rgw_a librados cls_otp_client cls_lock_client cls_rgw_clie cls_replica_log_client cls_user_client ceph-common common_utf8 global ${CURL_LIBRARIES} ${EXPAT_LIBRARIES} - ${OPENLDAP_LIBRARIES} ${CRYPTO_LIBS}) + ${OPENLDAP_LIBRARIES} ${CRYPTO_LIBS} + oath) if (WITH_RADOSGW_BEAST_FRONTEND) target_compile_definitions(rgw_a PUBLIC BOOST_COROUTINES_NO_DEPRECATION_WARNING) diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index bd7df8dc86aba..c6e601a3f47ce 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -8,6 +8,8 @@ #include +#include + #include "auth/Crypto.h" #include "compressor/Compressor.h" @@ -508,6 +510,7 @@ enum { OPT_MFA_GET, OPT_MFA_LIST, OPT_MFA_CHECK, + OPT_MFA_RESYNC, }; static int get_cmd(const char *cmd, const char *prev_cmd, const char *prev_prev_cmd, bool *need_more) @@ -974,6 +977,8 @@ static int get_cmd(const char *cmd, const char *prev_cmd, const char *prev_prev_ return OPT_MFA_LIST; if (strcmp(cmd, "check") == 0) return OPT_MFA_CHECK; + if (strcmp(cmd, "resync") == 0) + return OPT_MFA_RESYNC; } return -EINVAL; @@ -2395,6 +2400,60 @@ int create_new_bucket_instance(RGWRados *store, return 0; } +static int scan_totp(CephContext *cct, ceph::real_time& now, rados::cls::otp::otp_info_t& totp, vector& pins, + time_t *pofs) +{ +#define MAX_TOTP_SKEW_HOURS (24 * 7) + assert(pins.size() == 2); + + size_t slen = totp.seed.size() / 2 + 1; + char seed[slen]; + int rc = oath_hex2bin(totp.seed.c_str(), seed, &slen); + if (rc != OATH_OK) { + cerr << "ERROR: failed to parse seed" << std::endl; + return -EINVAL; + } + + time_t start_time = ceph::real_clock::to_time_t(now); + time_t time_ofs = 0, time_ofs_abs = 0; + time_t step_size = totp.step_size; + if (step_size == 0) { + step_size = OATH_TOTP_DEFAULT_TIME_STEP_SIZE; + } + uint32_t count = 0; + int sign = 1; + + uint32_t max_skew = MAX_TOTP_SKEW_HOURS * 3600; + + while (time_ofs_abs < max_skew) { + rc = oath_totp_validate2(seed, slen, + start_time, + step_size, + time_ofs, + 1, + nullptr, + pins[0].c_str()); + if (rc != OATH_INVALID_OTP) { + rc = oath_totp_validate2(seed, slen, + start_time, + step_size, + time_ofs - step_size, /* smaller time_ofs moves time forward */ + 1, + nullptr, + pins[1].c_str()); + if (rc != OATH_INVALID_OTP) { + *pofs = time_ofs - step_size + step_size * totp.window / 2; + ldout(cct, 20) << "found at time=" << start_time - time_ofs << " time_ofs=" << time_ofs << dendl; + return 0; + } + } + sign = -sign; + time_ofs_abs = (++count) * step_size; + time_ofs = sign * time_ofs_abs; + } + + return -ENOENT; +} #ifdef BUILDING_FOR_EMBEDDED extern "C" int cephd_rgw_admin(int argc, const char **argv) @@ -2566,7 +2625,7 @@ int main(int argc, const char **argv) string totp_serial; string totp_seed; - string totp_pin; + vector totp_pin; int totp_seconds = 0; int totp_window = 0; @@ -2894,7 +2953,7 @@ int main(int argc, const char **argv) } else if (ceph_argparse_witharg(args, i, &val, "--totp-serial", (char*)NULL)) { totp_serial = val; } else if (ceph_argparse_witharg(args, i, &val, "--totp-pin", (char*)NULL)) { - totp_pin = val; + totp_pin.push_back(val); } else if (ceph_argparse_witharg(args, i, &val, "--totp-seed", (char*)NULL)) { totp_seed = val; } else if (ceph_argparse_witharg(args, i, &val, "--totp-seconds", (char*)NULL)) { @@ -3054,6 +3113,7 @@ int main(int argc, const char **argv) rgw_bucket_init(store->meta_mgr); rgw_otp_init(store); + struct rgw_curl_setup { rgw_curl_setup() { rgw::curl::setup_curl(boost::none); @@ -3063,6 +3123,8 @@ int main(int argc, const char **argv) } } curl_cleanup; + oath_init(); + StoreDestructor store_destructor(store); if (raw_storage_op) { @@ -7446,7 +7508,7 @@ next: } list result; - int ret = store->check_mfa(user_id, totp_serial, totp_pin); + int ret = store->check_mfa(user_id, totp_serial, totp_pin.front()); if (ret < 0) { cerr << "MFA check failed, error: " << cpp_strerror(-ret) << std::endl; return -ret; @@ -7455,5 +7517,63 @@ next: cout << "ok" << std::endl; } + if (opt_cmd == OPT_MFA_RESYNC) { + if (user_id.empty()) { + cerr << "ERROR: user id was not provided (via --uid)" << std::endl; + return EINVAL; + } + + if (totp_serial.empty()) { + cerr << "ERROR: TOTP device serial number was not provided (via --totp-serial)" << std::endl; + return EINVAL; + } + + if (totp_pin.size() != 2) { + cerr << "ERROR: missing two --totp-pin params (--totp-pin= --totp-pin=)" << std::endl; + } + + rados::cls::otp::otp_info_t config; + int ret = store->get_mfa(user_id, totp_serial, &config); + if (ret < 0) { + if (ret == -ENOENT || ret == -ENODATA) { + cerr << "MFA serial id not found" << std::endl; + } else { + cerr << "MFA retrieval failed, error: " << cpp_strerror(-ret) << std::endl; + } + return -ret; + } + + ceph::real_time now = real_clock::now(); // need to get it from the osd + + time_t time_ofs; + + ret = scan_totp(store->ctx(), now, config, totp_pin, &time_ofs); + if (ret < 0) { + if (ret == -ENOENT) { + cerr << "failed to resync, TOTP values not found in range" << std::endl; + } else { + cerr << "ERROR: failed to scan for TOTP values: " << cpp_strerror(-ret) << std::endl; + } + return -ret; + } + + config.time_ofs = time_ofs; + + /* now update the backend */ + real_time mtime = real_clock::now(); + string oid = store->get_mfa_oid(user_id); + + ret = store->meta_mgr->mutate(rgw_otp_get_handler(), oid, mtime, &objv_tracker, + MDLOG_STATUS_WRITE, RGWMetadataHandler::APPLY_ALWAYS, + [&] { + return store->create_mfa(user_id, config, &objv_tracker, mtime); + }); + if (ret < 0) { + cerr << "MFA update failed, error: " << cpp_strerror(-ret) << std::endl; + return -ret; + } + + } + return 0; } -- 2.39.5