diff --git a/src/rgw/rgw_auth.cc b/src/rgw/rgw_auth.cc index b5771021b80655..08fef148d1190f 100644 --- a/src/rgw/rgw_auth.cc +++ b/src/rgw/rgw_auth.cc @@ -149,6 +149,11 @@ void RGWRemoteAuthApplier::create_account(const rgw_user& acct_user, { rgw_user new_acct_user = acct_user; + if (!info.acct_type.empty()) { + //ldap/keystone for s3 users + user_info.type = info.acct_type; + } + /* Administrator may enforce creating new accounts within their own tenants. * The config parameter name is kept due to legacy. */ if (new_acct_user.tenant.empty() && g_conf->rgw_keystone_implicit_tenants) { diff --git a/src/rgw/rgw_auth.h b/src/rgw/rgw_auth.h index efcd654425fe1c..22512bc298e928 100644 --- a/src/rgw/rgw_auth.h +++ b/src/rgw/rgw_auth.h @@ -117,16 +117,19 @@ class RGWRemoteAuthApplier : public RGWAuthApplier { const std::string acct_name; const uint32_t perm_mask; const bool is_admin; + const std::string acct_type; public: AuthInfo(const rgw_user& acct_user, const std::string& acct_name, const uint32_t perm_mask, - const bool is_admin) + const bool is_admin, + const std::string acct_type="") : acct_user(acct_user), acct_name(acct_name), perm_mask(perm_mask), - is_admin(is_admin) { + is_admin(is_admin), + acct_type(acct_type) { } }; diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index f669ea43cc2797..60325c6e40bef2 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -547,6 +547,7 @@ struct RGWUserInfo RGWQuotaInfo bucket_quota; map temp_url_keys; RGWQuotaInfo user_quota; + std::string type; RGWUserInfo() : auid(0), @@ -554,7 +555,8 @@ struct RGWUserInfo max_buckets(RGW_DEFAULT_MAX_BUCKETS), op_mask(RGW_OP_TYPE_ALL), admin(0), - system(0) { + system(0), + type("") { } RGWAccessKey* get_key0() { @@ -605,6 +607,7 @@ struct RGWUserInfo ::encode(user_quota, bl); ::encode(user_id.tenant, bl); ::encode(admin, bl); + ::encode(type, bl); ENCODE_FINISH(bl); } void decode(bufferlist::iterator& bl) { @@ -677,6 +680,7 @@ struct RGWUserInfo } if (struct_v >= 18) { ::decode(admin, bl); + ::decode(type, bl); } DECODE_FINISH(bl); } diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 23267199c78bdf..d1a40b0af207a5 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -31,6 +31,9 @@ #include "rgw_token.h" #include "include/assert.h" +#include "rgw_auth.h" +#include "rgw_auth_decoimpl.h" + #define dout_subsys ceph_subsys_rgw using namespace rgw; @@ -3936,52 +3939,48 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s) } } - if ((external_auth_result < 0) && - (store->ctx()->_conf->rgw_s3_auth_use_ldap) && - (! store->ctx()->_conf->rgw_ldap_uri.empty())) { - - RGW_Auth_S3::init(store); + class S3AuthFactory : public RGWRemoteAuthApplier::Factory { + typedef RGWAuthApplier::aplptr_t aplptr_t; + RGWRados * const store; + const std::string acct_override; - ldout(store->ctx(), 15) - << __func__ << " LDAP auth uri=" - << store->ctx()->_conf->rgw_ldap_uri - << dendl; + public: + S3AuthFactory(RGWRados * const store, + const std::string& acct_override) + : store(store), + acct_override(acct_override) { + } - RGWToken token{from_base64(auth_id)}; + aplptr_t create_apl_remote(CephContext * const cct, + RGWRemoteAuthApplier::acl_strategy_t&& acl_alg, + const RGWRemoteAuthApplier::AuthInfo info + ) const override { + return aplptr_t( + new RGWThirdPartyAccountAuthApplier( + RGWRemoteAuthApplier(cct, store, std::move(acl_alg), info), + store, acct_override)); + } + } aplfact(store, s->account_name); - if (! token.valid()) - external_auth_result = -EACCES; - else { - ldout(store->ctx(), 10) - << __func__ << " try LDAP auth uri=" - << store->ctx()->_conf->rgw_ldap_uri - << " token.id=" << token.id - << dendl; - - if (ldh->auth(token.id, token.key) != 0) - external_auth_result = -EACCES; - else { - /* ok, succeeded */ - external_auth_result = 0; + /* Extractor */ + RGWLDAPTokenExtractor token_extr(s); - /* create local account, if none exists */ - s->user->user_id = token.id; - s->user->display_name = token.id; // cn? - int ret = rgw_get_user_info_by_uid(store, s->user->user_id, *(s->user)); - if (ret < 0) { - ret = rgw_store_user_info(store, *(s->user), nullptr, nullptr, - real_time(), true); - if (ret < 0) { - dout(10) << "NOTICE: failed to store new user's info: ret=" << ret - << dendl; - } - } + RGWLDAPAuthEngine ldap(s->cct, store, token_extr, &aplfact); - /* set request perms */ - s->perm_mask = RGW_PERM_FULL_CONTROL; - } /* success */ - } /* token */ - } /* ldap */ + if (!ldap.is_applicable()) { + return -EPERM; + } else { + auto applier = ldap.authenticate(); + if (!applier) { + return -EPERM; + } + else { + applier->load_acct_info(*s->user); + s->perm_mask = applier->get_perm_mask(); + s->auth_identity = std::move(applier); + return 0; + } + } /* keystone failed (or not enabled); check if we want to use rados backend */ if (!store->ctx()->_conf->rgw_s3_auth_use_rados @@ -3997,7 +3996,7 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s) return external_auth_result; } - /* now verify signature */ + /* now verify signature */ string auth_hdr; if (!rgw_create_s3_canonical_header(s->info, &s->header_time, auth_hdr, qsr)) { @@ -4342,3 +4341,98 @@ RGWOp* RGWHandler_REST_Service_S3Website::get_obj_op(bool get_data) op->set_get_data(get_data); return op; } + +rgw::LDAPHelper* RGWLDAPAuthEngine::ldh = nullptr; +std::mutex RGWLDAPAuthEngine::mtx; + +void RGWLDAPAuthEngine::init(CephContext* const cct) +{ + if (!ldh) { + std::lock_guard lck(mtx); + if (!ldh) { + const string& ldap_uri = cct->_conf->rgw_ldap_uri; + const string& ldap_binddn = cct->_conf->rgw_ldap_binddn; + const string& ldap_searchdn = cct->_conf->rgw_ldap_searchdn; + const string& ldap_dnattr = cct->_conf->rgw_ldap_dnattr; + std::string ldap_bindpw = parse_rgw_ldap_bindpw(cct); + + ldh = new rgw::LDAPHelper(ldap_uri, ldap_binddn, ldap_bindpw, + ldap_searchdn, ldap_dnattr); + + ldh->init(); + ldh->bind(); + } + } +} + +RGWRemoteAuthApplier::acl_strategy_t RGWLDAPAuthEngine::get_acl_strategy() const +{ + //This is based on the assumption that the default acl strategy in + // get_perms_from_aclspec, will take care. Extra acl spec is not required. + return nullptr; +} + +RGWRemoteAuthApplier::AuthInfo +RGWLDAPAuthEngine::get_creds_info(const rgw::RGWToken& token) const noexcept +{ + return RGWRemoteAuthApplier::AuthInfo { + rgw_user(token.id), + token.id, + RGW_PERM_FULL_CONTROL, + true, + "ldap" + }; +} + +bool RGWLDAPAuthEngine::is_applicable() const noexcept +{ + if (!RGWTokenBasedAuthEngine::is_applicable()) { + return false; + } + + if (!cct->_conf->rgw_s3_auth_use_ldap || + cct->_conf->rgw_ldap_uri.empty()) { + return false; + } + + if(!base64_token.valid()) { + return false; + } + + return true; +} + +RGWAuthApplier::aplptr_t RGWLDAPAuthEngine::authenticate() const +{ + //Check if a user of type other than 'ldap' is already present, if yes, then + //return error. + RGWUserInfo user_info; + user_info.user_id = base64_token.id; + if (rgw_get_user_info_by_uid(store, user_info.user_id, user_info) >= 0) { + if (user_info.type.compare("ldap") != 0) { + ldout(cct, 10) << "ERROR: User id of type: " << user_info.type << "is already present" << dendl; + return nullptr; + } + } + + if (ldh->auth(base64_token.id, base64_token.key) != 0) { + return nullptr; + } + + return apl_factory->create_apl_remote(cct, get_acl_strategy(), get_creds_info(base64_token)); +} + +std::string RGWLDAPTokenExtractor::get_token() const +{ + string token = ""; + if (!s->http_auth || !(*s->http_auth)) { + token = s->info.args.get("AWSAccessKeyId"); + } else { + string auth_str(s->http_auth + 4); + int pos = auth_str.rfind(':'); + if (pos >=0 ) { + token = auth_str.substr(0, pos); + } + } + return token; +} diff --git a/src/rgw/rgw_rest_s3.h b/src/rgw/rgw_rest_s3.h index cecc14c97656d3..c7c2908bc150aa 100644 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@ -16,6 +16,9 @@ #include "rgw_rest_conn.h" #include "rgw_ldap.h" +#include "rgw_token.h" +#include "include/assert.h" + #define RGW_AUTH_GRACE_MINS 15 void rgw_get_errno_s3(struct rgw_http_errors *e, int err_no); @@ -627,4 +630,48 @@ static inline int valid_s3_bucket_name(const string& name, bool relaxed=false) return 0; } +class RGWLDAPAuthEngine: RGWTokenBasedAuthEngine +{ + static rgw::LDAPHelper* ldh; + static std::mutex mtx; + rgw::RGWToken base64_token; + + static void init(CephContext* const cct); + +protected: + RGWRados* const store; + const RGWRemoteAuthApplier::Factory * const apl_factory; + + RGWRemoteAuthApplier::acl_strategy_t get_acl_strategy() const; + RGWRemoteAuthApplier::AuthInfo get_creds_info(const rgw::RGWToken& token) const noexcept; + +public: + RGWLDAPAuthEngine(CephContext* const cct, + RGWRados* const store, + Extractor &ex, + const RGWRemoteAuthApplier::Factory * const apl_factory) + : RGWTokenBasedAuthEngine(cct, ex), + store(store), + apl_factory(apl_factory) { + init(cct); + base64_token = rgw::from_base64(token); + } + const char* get_name() const noexcept override { + return "RGWLDAPAuthEngine"; + } + bool is_applicable() const noexcept override; + RGWAuthApplier::aplptr_t authenticate() const override; +}; + +class RGWLDAPTokenExtractor : public RGWTokenBasedAuthEngine::Extractor { +protected: + const req_state * const s; + +public: + RGWLDAPTokenExtractor(const req_state * const s) + : s(s) { + } + std::string get_token() const override; +}; + #endif /* CEPH_RGW_REST_S3_H */ diff --git a/src/rgw/rgw_token.h b/src/rgw/rgw_token.h index 7dce9a9ef3cebb..972c57448db2d7 100644 --- a/src/rgw/rgw_token.h +++ b/src/rgw/rgw_token.h @@ -71,7 +71,7 @@ namespace rgw { virtual uint32_t version() const { return 1; }; - bool valid() { + bool valid() const{ return ((type != TOKEN_NONE) && (! id.empty()) && (! key.empty()));