1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
4 #ifndef CEPH_RGW_AUTH_FILTERS_H
5 #define CEPH_RGW_AUTH_FILTERS_H
9 #include <boost/logic/tribool.hpp>
10 #include <boost/optional.hpp>
12 #include "rgw_service.h"
13 #include "rgw_common.h"
20 /* Abstract decorator over any implementation of rgw::auth::IdentityApplier
21 * which could be provided both as a pointer-to-object or the object itself. */
22 template <typename DecorateeT
>
23 class DecoratedApplier
: public rgw::auth::IdentityApplier
{
24 typedef typename
std::remove_pointer
<DecorateeT
>::type DerefedDecorateeT
;
26 static_assert(std::is_base_of
<rgw::auth::IdentityApplier
,
27 DerefedDecorateeT
>::value
,
28 "DecorateeT must be a subclass of rgw::auth::IdentityApplier");
32 /* There is an indirection layer over accessing decoratee to share the same
33 * code base between dynamic and static decorators. The difference is about
34 * what we store internally: pointer to a decorated object versus the whole
35 * object itself. Googling for "SFINAE" can help to understand the code. */
36 template <typename T
= void,
37 typename
std::enable_if
<
38 std::is_pointer
<DecorateeT
>::value
, T
>::type
* = nullptr>
39 DerefedDecorateeT
& get_decoratee() {
43 template <typename T
= void,
44 typename
std::enable_if
<
45 ! std::is_pointer
<DecorateeT
>::value
, T
>::type
* = nullptr>
46 DerefedDecorateeT
& get_decoratee() {
50 template <typename T
= void,
51 typename
std::enable_if
<
52 std::is_pointer
<DecorateeT
>::value
, T
>::type
* = nullptr>
53 const DerefedDecorateeT
& get_decoratee() const {
57 template <typename T
= void,
58 typename
std::enable_if
<
59 ! std::is_pointer
<DecorateeT
>::value
, T
>::type
* = nullptr>
60 const DerefedDecorateeT
& get_decoratee() const {
65 explicit DecoratedApplier(DecorateeT
&& decoratee
)
66 : decoratee(std::forward
<DecorateeT
>(decoratee
)) {
69 uint32_t get_perms_from_aclspec(const DoutPrefixProvider
* dpp
, const aclspec_t
& aclspec
) const override
{
70 return get_decoratee().get_perms_from_aclspec(dpp
, aclspec
);
73 bool is_admin_of(const rgw_user
& uid
) const override
{
74 return get_decoratee().is_admin_of(uid
);
77 bool is_owner_of(const rgw_user
& uid
) const override
{
78 return get_decoratee().is_owner_of(uid
);
81 bool is_anonymous() const override
{
82 return get_decoratee().is_anonymous();
85 uint32_t get_perm_mask() const override
{
86 return get_decoratee().get_perm_mask();
89 uint32_t get_identity_type() const override
{
90 return get_decoratee().get_identity_type();
93 std::string
get_acct_name() const override
{
94 return get_decoratee().get_acct_name();
97 std::string
get_subuser() const override
{
98 return get_decoratee().get_subuser();
102 const boost::container::flat_set
<Principal
>& ids
) const override
{
103 return get_decoratee().is_identity(ids
);
106 void to_str(std::ostream
& out
) const override
{
107 get_decoratee().to_str(out
);
110 std::string
get_role_tenant() const override
{ /* in/out */
111 return get_decoratee().get_role_tenant();
114 void load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const override
{ /* out */
115 return get_decoratee().load_acct_info(dpp
, user_info
);
118 void modify_request_state(const DoutPrefixProvider
* dpp
, req_state
* s
) const override
{ /* in/out */
119 return get_decoratee().modify_request_state(dpp
, s
);
122 void write_ops_log_entry(rgw_log_entry
& entry
) const override
{
123 return get_decoratee().write_ops_log_entry(entry
);
128 template <typename T
>
129 class ThirdPartyAccountApplier
: public DecoratedApplier
<T
> {
130 rgw::sal::Store
* store
;
131 const rgw_user acct_user_override
;
134 /* A value representing situations where there is no requested account
135 * override. In other words, acct_user_override will be equal to this
136 * constant where the request isn't a cross-tenant one. */
137 static const rgw_user UNKNOWN_ACCT
;
139 template <typename U
>
140 ThirdPartyAccountApplier(rgw::sal::Store
* store
,
141 const rgw_user
&acct_user_override
,
143 : DecoratedApplier
<T
>(std::move(decoratee
)),
145 acct_user_override(acct_user_override
) {
148 void to_str(std::ostream
& out
) const override
;
149 void load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const override
; /* out */
152 /* static declaration: UNKNOWN_ACCT will be an empty rgw_user that is a result
153 * of the default construction. */
154 template <typename T
>
155 const rgw_user ThirdPartyAccountApplier
<T
>::UNKNOWN_ACCT
;
157 template <typename T
>
158 void ThirdPartyAccountApplier
<T
>::to_str(std::ostream
& out
) const
160 out
<< "rgw::auth::ThirdPartyAccountApplier(" + acct_user_override
.to_str() + ")"
162 DecoratedApplier
<T
>::to_str(out
);
165 template <typename T
>
166 void ThirdPartyAccountApplier
<T
>::load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const
168 if (UNKNOWN_ACCT
== acct_user_override
) {
169 /* There is no override specified by the upper layer. This means that we'll
170 * load the account owned by the authenticated identity (aka auth_user). */
171 DecoratedApplier
<T
>::load_acct_info(dpp
, user_info
);
172 } else if (DecoratedApplier
<T
>::is_owner_of(acct_user_override
)) {
173 /* The override has been specified but the account belongs to the authenticated
174 * identity. We may safely forward the call to a next stage. */
175 DecoratedApplier
<T
>::load_acct_info(dpp
, user_info
);
176 } else if (this->is_anonymous()) {
177 /* If the user was authed by the anonymous engine then scope the ANON user
178 * to the correct tenant */
179 if (acct_user_override
.tenant
.empty())
180 user_info
.user_id
= rgw_user(acct_user_override
.id
, RGW_USER_ANON_ID
);
182 user_info
.user_id
= rgw_user(acct_user_override
.tenant
, RGW_USER_ANON_ID
);
184 /* Compatibility mechanism for multi-tenancy. For more details refer to
185 * load_acct_info method of rgw::auth::RemoteApplier. */
186 std::unique_ptr
<rgw::sal::User
> user
;
188 if (acct_user_override
.tenant
.empty()) {
189 const rgw_user
tenanted_uid(acct_user_override
.id
, acct_user_override
.id
);
190 user
= store
->get_user(tenanted_uid
);
192 if (user
->load_user(dpp
, null_yield
) >= 0) {
193 user_info
= user
->get_info();
199 user
= store
->get_user(acct_user_override
);
200 const int ret
= user
->load_user(dpp
, null_yield
);
202 /* We aren't trying to recover from ENOENT here. It's supposed that creating
203 * someone else's account isn't a thing we want to support in this filter. */
204 if (ret
== -ENOENT
) {
210 user_info
= user
->get_info();
214 template <typename T
> static inline
215 ThirdPartyAccountApplier
<T
> add_3rdparty(rgw::sal::Store
* store
,
216 const rgw_user
&acct_user_override
,
218 return ThirdPartyAccountApplier
<T
>(store
, acct_user_override
,
223 template <typename T
>
224 class SysReqApplier
: public DecoratedApplier
<T
> {
225 CephContext
* const cct
;
226 rgw::sal::Store
* store
;
227 const RGWHTTPArgs
& args
;
228 mutable boost::tribool is_system
;
231 template <typename U
>
232 SysReqApplier(CephContext
* const cct
,
233 rgw::sal::Store
* store
,
234 const req_state
* const s
,
236 : DecoratedApplier
<T
>(std::forward
<T
>(decoratee
)),
240 is_system(boost::logic::indeterminate
) {
243 void to_str(std::ostream
& out
) const override
;
244 void load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const override
; /* out */
245 void modify_request_state(const DoutPrefixProvider
* dpp
, req_state
* s
) const override
; /* in/out */
248 template <typename T
>
249 void SysReqApplier
<T
>::to_str(std::ostream
& out
) const
251 out
<< "rgw::auth::SysReqApplier" << " -> ";
252 DecoratedApplier
<T
>::to_str(out
);
255 template <typename T
>
256 void SysReqApplier
<T
>::load_acct_info(const DoutPrefixProvider
* dpp
, RGWUserInfo
& user_info
) const
258 DecoratedApplier
<T
>::load_acct_info(dpp
, user_info
);
259 is_system
= user_info
.system
;
262 //ldpp_dout(dpp, 20) << "system request" << dendl;
264 rgw_user
effective_uid(args
.sys_get(RGW_SYS_PARAM_PREFIX
"uid"));
265 if (! effective_uid
.empty()) {
266 /* We aren't writing directly to user_info for consistency and security
267 * reasons. rgw_get_user_info_by_uid doesn't trigger the operator=() but
268 * calls ::decode instead. */
269 std::unique_ptr
<rgw::sal::User
> user
= store
->get_user(effective_uid
);
270 if (user
->load_user(dpp
, null_yield
) < 0) {
271 //ldpp_dout(dpp, 0) << "User lookup failed!" << dendl;
274 user_info
= user
->get_info();
279 template <typename T
>
280 void SysReqApplier
<T
>::modify_request_state(const DoutPrefixProvider
* dpp
, req_state
* const s
) const
282 if (boost::logic::indeterminate(is_system
)) {
283 RGWUserInfo unused_info
;
284 load_acct_info(dpp
, unused_info
);
288 s
->info
.args
.set_system();
289 s
->system_request
= true;
291 DecoratedApplier
<T
>::modify_request_state(dpp
, s
);
294 template <typename T
> static inline
295 SysReqApplier
<T
> add_sysreq(CephContext
* const cct
,
296 rgw::sal::Store
* store
,
297 const req_state
* const s
,
299 return SysReqApplier
<T
>(cct
, store
, s
, std::forward
<T
>(t
));
302 } /* namespace auth */
303 } /* namespace rgw */
305 #endif /* CEPH_RGW_AUTH_FILTERS_H */