]>
git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_auth.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
6 #include "rgw_common.h"
9 #include "rgw_http_client.h"
10 #include "rgw_keystone.h"
12 #include "include/str_list.h"
14 #define dout_context g_ceph_context
15 #define dout_subsys ceph_subsys_rgw
21 std::unique_ptr
<rgw::auth::Identity
>
22 transform_old_authinfo(const req_state
* const s
)
24 /* This class is not intended for public use. Should be removed altogether
25 * with this function after moving all our APIs to the new authentication
27 class DummyIdentityApplier
: public rgw::auth::Identity
{
28 CephContext
* const cct
;
30 /* For this particular case it's OK to use rgw_user structure to convey
31 * the identity info as this was the policy for doing that before the
37 DummyIdentityApplier(CephContext
* const cct
,
38 const rgw_user
& auth_id
,
47 uint32_t get_perms_from_aclspec(const aclspec_t
& aclspec
) const override
{
48 return rgw_perms_from_aclspec_default_strategy(id
, aclspec
);
51 bool is_admin_of(const rgw_user
& acct_id
) const override
{
55 bool is_owner_of(const rgw_user
& acct_id
) const override
{
59 bool is_identity(const idset_t
& ids
) const override
{
61 if (p
.is_wildcard()) {
63 } else if (p
.is_tenant() && p
.get_tenant() == id
.tenant
) {
65 } else if (p
.is_user() &&
66 (p
.get_tenant() == id
.tenant
) &&
67 (p
.get_id() == id
.id
)) {
74 uint32_t get_perm_mask() const override
{
78 void to_str(std::ostream
& out
) const override
{
79 out
<< "RGWDummyIdentityApplier(auth_id=" << id
80 << ", perm_mask=" << perm_mask
81 << ", is_admin=" << is_admin
<< ")";
85 return std::unique_ptr
<rgw::auth::Identity
>(
86 new DummyIdentityApplier(s
->cct
,
89 /* System user has admin permissions by default - it's supposed to pass
90 * through any security check. */
94 } /* namespace auth */
98 uint32_t rgw_perms_from_aclspec_default_strategy(
100 const rgw::auth::Identity::aclspec_t
& aclspec
)
102 dout(5) << "Searching permissions for uid=" << uid
<< dendl
;
104 const auto iter
= aclspec
.find(uid
.to_str());
105 if (std::end(aclspec
) != iter
) {
106 dout(5) << "Found permission: " << iter
->second
<< dendl
;
110 dout(5) << "Permissions for user not found" << dendl
;
115 static inline const std::string
make_spec_item(const std::string
& tenant
,
116 const std::string
& id
)
118 return tenant
+ ":" + id
;
122 static inline std::pair
<bool, rgw::auth::Engine::result_t
>
123 strategy_handle_rejected(rgw::auth::Engine::result_t
&& engine_result
,
124 const rgw::auth::Strategy::Control policy
,
125 rgw::auth::Engine::result_t
&& strategy_result
)
127 using Control
= rgw::auth::Strategy::Control
;
129 case Control::REQUISITE
:
130 /* Don't try next. */
131 return std::make_pair(false, std::move(engine_result
));
133 case Control::SUFFICIENT
:
134 /* Don't try next. */
135 return std::make_pair(false, std::move(engine_result
));
137 case Control::FALLBACK
:
138 /* Don't try next. */
139 return std::make_pair(false, std::move(strategy_result
));
142 /* Huh, memory corruption? */
147 static inline std::pair
<bool, rgw::auth::Engine::result_t
>
148 strategy_handle_denied(rgw::auth::Engine::result_t
&& engine_result
,
149 const rgw::auth::Strategy::Control policy
,
150 rgw::auth::Engine::result_t
&& strategy_result
)
152 using Control
= rgw::auth::Strategy::Control
;
154 case Control::REQUISITE
:
155 /* Don't try next. */
156 return std::make_pair(false, std::move(engine_result
));
158 case Control::SUFFICIENT
:
160 return std::make_pair(true, std::move(engine_result
));
162 case Control::FALLBACK
:
163 return std::make_pair(true, std::move(strategy_result
));
166 /* Huh, memory corruption? */
171 static inline std::pair
<bool, rgw::auth::Engine::result_t
>
172 strategy_handle_granted(rgw::auth::Engine::result_t
&& engine_result
,
173 const rgw::auth::Strategy::Control policy
,
174 rgw::auth::Engine::result_t
&& strategy_result
)
176 using Control
= rgw::auth::Strategy::Control
;
178 case Control::REQUISITE
:
180 return std::make_pair(true, std::move(engine_result
));
182 case Control::SUFFICIENT
:
183 /* Don't try next. */
184 return std::make_pair(false, std::move(engine_result
));
186 case Control::FALLBACK
:
187 /* Don't try next. */
188 return std::make_pair(false, std::move(engine_result
));
191 /* Huh, memory corruption? */
196 rgw::auth::Engine::result_t
197 rgw::auth::Strategy::authenticate(const req_state
* const s
) const
199 result_t strategy_result
= result_t::deny();
201 for (const stack_item_t
& kv
: auth_stack
) {
202 const rgw::auth::Engine
& engine
= kv
.first
;
203 const auto& policy
= kv
.second
;
205 dout(20) << get_name() << ": trying " << engine
.get_name() << dendl
;
207 result_t engine_result
= result_t::deny();
209 engine_result
= engine
.authenticate(s
);
210 } catch (const int err
) {
211 engine_result
= result_t::deny(err
);
214 bool try_next
= true;
215 switch (engine_result
.get_status()) {
216 case result_t::Status::REJECTED
: {
217 dout(20) << engine
.get_name() << " rejected with reason="
218 << engine_result
.get_reason() << dendl
;
220 std::tie(try_next
, strategy_result
) = \
221 strategy_handle_rejected(std::move(engine_result
), policy
,
222 std::move(strategy_result
));
225 case result_t::Status::DENIED
: {
226 dout(20) << engine
.get_name() << " denied with reason="
227 << engine_result
.get_reason() << dendl
;
229 std::tie(try_next
, strategy_result
) = \
230 strategy_handle_denied(std::move(engine_result
), policy
,
231 std::move(strategy_result
));
234 case result_t::Status::GRANTED
: {
235 dout(20) << engine
.get_name() << " granted access" << dendl
;
237 std::tie(try_next
, strategy_result
) = \
238 strategy_handle_granted(std::move(engine_result
), policy
,
239 std::move(strategy_result
));
252 return strategy_result
;
256 rgw::auth::Strategy::apply(const rgw::auth::Strategy
& auth_strategy
,
257 req_state
* const s
) noexcept
260 auto result
= auth_strategy
.authenticate(s
);
261 if (result
.get_status() != decltype(result
)::Status::GRANTED
) {
262 /* Access denied is acknowledged by returning a std::unique_ptr with
264 ldout(s
->cct
, 5) << "Failed the auth strategy, reason="
265 << result
.get_reason() << dendl
;
266 return result
.get_reason();
270 rgw::auth::IdentityApplier::aplptr_t applier
= result
.get_applier();
271 rgw::auth::Completer::cmplptr_t completer
= result
.get_completer();
273 /* Account used by a given RGWOp is decoupled from identity employed
274 * in the authorization phase (RGWOp::verify_permissions). */
275 applier
->load_acct_info(*s
->user
);
276 s
->perm_mask
= applier
->get_perm_mask();
278 /* This is the signle place where we pass req_state as a pointer
279 * to non-const and thus its modification is allowed. In the time
280 * of writing only RGWTempURLEngine needed that feature. */
281 applier
->modify_request_state(s
);
283 completer
->modify_request_state(s
);
286 s
->auth
.identity
= std::move(applier
);
287 s
->auth
.completer
= std::move(completer
);
290 } catch (const int err
) {
291 ldout(s
->cct
, 5) << "applier throwed err=" << err
<< dendl
;
294 } catch (const int err
) {
295 ldout(s
->cct
, 5) << "auth engine throwed err=" << err
<< dendl
;
299 /* We never should be here. */
304 rgw::auth::Strategy::add_engine(const Control ctrl_flag
,
305 const Engine
& engine
) noexcept
307 auth_stack
.push_back(std::make_pair(std::cref(engine
), ctrl_flag
));
311 /* rgw::auth::RemoteAuthApplier */
312 uint32_t rgw::auth::RemoteApplier::get_perms_from_aclspec(const aclspec_t
& aclspec
) const
316 /* For backward compatibility with ACLOwner. */
317 perm
|= rgw_perms_from_aclspec_default_strategy(info
.acct_user
,
320 /* We also need to cover cases where rgw_keystone_implicit_tenants
322 if (info
.acct_user
.tenant
.empty()) {
323 const rgw_user
tenanted_acct_user(info
.acct_user
.id
, info
.acct_user
.id
);
325 perm
|= rgw_perms_from_aclspec_default_strategy(tenanted_acct_user
,
329 /* Now it's a time for invoking additional strategy that was supplied by
330 * a specific auth engine. */
331 if (extra_acl_strategy
) {
332 perm
|= extra_acl_strategy(aclspec
);
335 ldout(cct
, 20) << "from ACL got perm=" << perm
<< dendl
;
339 bool rgw::auth::RemoteApplier::is_admin_of(const rgw_user
& uid
) const
341 return info
.is_admin
;
344 bool rgw::auth::RemoteApplier::is_owner_of(const rgw_user
& uid
) const
346 if (info
.acct_user
.tenant
.empty()) {
347 const rgw_user
tenanted_acct_user(info
.acct_user
.id
, info
.acct_user
.id
);
349 if (tenanted_acct_user
== uid
) {
354 return info
.acct_user
== uid
;
357 bool rgw::auth::RemoteApplier::is_identity(const idset_t
& ids
) const {
358 for (auto& id
: ids
) {
359 if (id
.is_wildcard()) {
362 // We also need to cover cases where rgw_keystone_implicit_tenants
364 } else if (id
.is_tenant() &&
365 (info
.acct_user
.tenant
.empty() ?
367 info
.acct_user
.tenant
) == id
.get_tenant()) {
369 } else if (id
.is_user() &&
370 info
.acct_user
.id
== id
.get_id() &&
371 (info
.acct_user
.tenant
.empty() ?
373 info
.acct_user
.tenant
) == id
.get_tenant()) {
380 void rgw::auth::RemoteApplier::to_str(std::ostream
& out
) const
382 out
<< "rgw::auth::RemoteApplier(acct_user=" << info
.acct_user
383 << ", acct_name=" << info
.acct_name
384 << ", perm_mask=" << info
.perm_mask
385 << ", is_admin=" << info
.is_admin
<< ")";
388 void rgw::auth::RemoteApplier::create_account(const rgw_user
& acct_user
,
389 RGWUserInfo
& user_info
) const /* out */
391 rgw_user new_acct_user
= acct_user
;
393 if (info
.acct_type
) {
394 //ldap/keystone for s3 users
395 user_info
.type
= info
.acct_type
;
398 /* An upper layer may enforce creating new accounts within their own
400 if (new_acct_user
.tenant
.empty() && implicit_tenants
) {
401 new_acct_user
.tenant
= new_acct_user
.id
;
404 user_info
.user_id
= new_acct_user
;
405 user_info
.display_name
= info
.acct_name
;
407 int ret
= rgw_store_user_info(store
, user_info
, nullptr, nullptr,
410 ldout(cct
, 0) << "ERROR: failed to store new user info: user="
411 << user_info
.user_id
<< " ret=" << ret
<< dendl
;
416 /* TODO(rzarzynski): we need to handle display_name changes. */
417 void rgw::auth::RemoteApplier::load_acct_info(RGWUserInfo
& user_info
) const /* out */
419 /* It's supposed that RGWRemoteAuthApplier tries to load account info
420 * that belongs to the authenticated identity. Another policy may be
421 * applied by using a RGWThirdPartyAccountAuthApplier decorator. */
422 const rgw_user
& acct_user
= info
.acct_user
;
424 /* Normally, empty "tenant" field of acct_user means the authenticated
425 * identity has the legacy, global tenant. However, due to inclusion
426 * of multi-tenancy, we got some special compatibility kludge for remote
427 * backends like Keystone.
428 * If the global tenant is the requested one, we try the same tenant as
429 * the user name first. If that RGWUserInfo exists, we use it. This way,
430 * migrated OpenStack users can get their namespaced containers and nobody's
432 * If that fails, we look up in the requested (possibly empty) tenant.
433 * If that fails too, we create the account within the global or separated
434 * namespace depending on rgw_keystone_implicit_tenants. */
435 if (acct_user
.tenant
.empty()) {
436 const rgw_user
tenanted_uid(acct_user
.id
, acct_user
.id
);
438 if (rgw_get_user_info_by_uid(store
, tenanted_uid
, user_info
) >= 0) {
444 if (rgw_get_user_info_by_uid(store
, acct_user
, user_info
) < 0) {
445 ldout(cct
, 0) << "NOTICE: couldn't map swift user " << acct_user
<< dendl
;
446 create_account(acct_user
, user_info
);
449 /* Succeeded if we are here (create_account() hasn't throwed). */
453 /* rgw::auth::LocalApplier */
454 /* static declaration */
455 const std::string
rgw::auth::LocalApplier::NO_SUBUSER
;
457 uint32_t rgw::auth::LocalApplier::get_perms_from_aclspec(const aclspec_t
& aclspec
) const
459 return rgw_perms_from_aclspec_default_strategy(user_info
.user_id
, aclspec
);
462 bool rgw::auth::LocalApplier::is_admin_of(const rgw_user
& uid
) const
464 return user_info
.admin
|| user_info
.system
;
467 bool rgw::auth::LocalApplier::is_owner_of(const rgw_user
& uid
) const
469 return uid
== user_info
.user_id
;
472 bool rgw::auth::LocalApplier::is_identity(const idset_t
& ids
) const {
473 for (auto& id
: ids
) {
474 if (id
.is_wildcard()) {
476 } else if (id
.is_tenant() &&
477 id
.get_tenant() == user_info
.user_id
.tenant
) {
479 } else if (id
.is_user() &&
480 (id
.get_tenant() == user_info
.user_id
.tenant
) &&
481 (id
.get_id() == user_info
.user_id
.id
)) {
488 void rgw::auth::LocalApplier::to_str(std::ostream
& out
) const {
489 out
<< "rgw::auth::LocalApplier(acct_user=" << user_info
.user_id
490 << ", acct_name=" << user_info
.display_name
491 << ", subuser=" << subuser
492 << ", perm_mask=" << get_perm_mask()
493 << ", is_admin=" << static_cast<bool>(user_info
.admin
) << ")";
496 uint32_t rgw::auth::LocalApplier::get_perm_mask(const std::string
& subuser_name
,
497 const RGWUserInfo
&uinfo
) const
499 if (! subuser_name
.empty() && subuser_name
!= NO_SUBUSER
) {
500 const auto iter
= uinfo
.subusers
.find(subuser_name
);
502 if (iter
!= std::end(uinfo
.subusers
)) {
503 return iter
->second
.perm_mask
;
505 /* Subuser specified but not found. */
506 return RGW_PERM_NONE
;
509 /* Due to backward compatibility. */
510 return RGW_PERM_FULL_CONTROL
;
514 void rgw::auth::LocalApplier::load_acct_info(RGWUserInfo
& user_info
) const /* out */
516 /* Load the account that belongs to the authenticated identity. An extra call
517 * to RADOS may be safely skipped in this case. */
518 user_info
= this->user_info
;
522 rgw::auth::Engine::result_t
523 rgw::auth::AnonymousEngine::authenticate(const req_state
* const s
) const
525 if (! is_applicable(s
)) {
526 return result_t::deny(-EPERM
);
528 RGWUserInfo user_info
;
529 rgw_get_anon_user(user_info
);
532 apl_factory
->create_apl_local(cct
, s
, user_info
,
533 rgw::auth::LocalApplier::NO_SUBUSER
);
534 return result_t::grant(std::move(apl
));