1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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_common.h"
18 /* Abstract decorator over any implementation of rgw::auth::IdentityApplier
19 * which could be provided both as a pointer-to-object or the object itself. */
20 template <typename DecorateeT
>
21 class DecoratedApplier
: public rgw::auth::IdentityApplier
{
22 typedef typename
std::remove_pointer
<DecorateeT
>::type DerefedDecorateeT
;
24 static_assert(std::is_base_of
<rgw::auth::IdentityApplier
,
25 DerefedDecorateeT
>::value
,
26 "DecorateeT must be a subclass of rgw::auth::IdentityApplier");
30 /* There is an indirection layer over accessing decoratee to share the same
31 * code base between dynamic and static decorators. The difference is about
32 * what we store internally: pointer to a decorated object versus the whole
33 * object itself. Googling for "SFINAE" can help to understand the code. */
34 template <typename T
= void,
35 typename
std::enable_if
<
36 std::is_pointer
<DecorateeT
>::value
, T
>::type
* = nullptr>
37 DerefedDecorateeT
& get_decoratee() {
41 template <typename T
= void,
42 typename
std::enable_if
<
43 ! std::is_pointer
<DecorateeT
>::value
, T
>::type
* = nullptr>
44 DerefedDecorateeT
& get_decoratee() {
48 template <typename T
= void,
49 typename
std::enable_if
<
50 std::is_pointer
<DecorateeT
>::value
, T
>::type
* = nullptr>
51 const DerefedDecorateeT
& get_decoratee() const {
55 template <typename T
= void,
56 typename
std::enable_if
<
57 ! std::is_pointer
<DecorateeT
>::value
, T
>::type
* = nullptr>
58 const DerefedDecorateeT
& get_decoratee() const {
63 DecoratedApplier(DecorateeT
&& decoratee
)
64 : decoratee(std::forward
<DecorateeT
>(decoratee
)) {
67 uint32_t get_perms_from_aclspec(const aclspec_t
& aclspec
) const override
{
68 return get_decoratee().get_perms_from_aclspec(aclspec
);
71 bool is_admin_of(const rgw_user
& uid
) const override
{
72 return get_decoratee().is_admin_of(uid
);
75 bool is_owner_of(const rgw_user
& uid
) const override
{
76 return get_decoratee().is_owner_of(uid
);
79 uint32_t get_perm_mask() const override
{
80 return get_decoratee().get_perm_mask();
84 const boost::container::flat_set
<Principal
>& ids
) const override
{
85 return get_decoratee().is_identity(ids
);
88 void to_str(std::ostream
& out
) const override
{
89 get_decoratee().to_str(out
);
92 void load_acct_info(RGWUserInfo
& user_info
) const override
{ /* out */
93 return get_decoratee().load_acct_info(user_info
);
96 void modify_request_state(req_state
* s
) const override
{ /* in/out */
97 return get_decoratee().modify_request_state(s
);
102 template <typename T
>
103 class ThirdPartyAccountApplier
: public DecoratedApplier
<T
> {
104 /* const */RGWRados
* const store
;
105 const rgw_user acct_user_override
;
108 /* A value representing situations where there is no requested account
109 * override. In other words, acct_user_override will be equal to this
110 * constant where the request isn't a cross-tenant one. */
111 static const rgw_user UNKNOWN_ACCT
;
113 template <typename U
>
114 ThirdPartyAccountApplier(RGWRados
* const store
,
115 const rgw_user acct_user_override
,
117 : DecoratedApplier
<T
>(std::move(decoratee
)),
119 acct_user_override(acct_user_override
) {
122 void to_str(std::ostream
& out
) const override
;
123 void load_acct_info(RGWUserInfo
& user_info
) const override
; /* out */
126 /* static declaration: UNKNOWN_ACCT will be an empty rgw_user that is a result
127 * of the default construction. */
128 template <typename T
>
129 const rgw_user ThirdPartyAccountApplier
<T
>::UNKNOWN_ACCT
;
131 template <typename T
>
132 void ThirdPartyAccountApplier
<T
>::to_str(std::ostream
& out
) const
134 out
<< "rgw::auth::ThirdPartyAccountApplier(" + acct_user_override
.to_str() + ")"
136 DecoratedApplier
<T
>::to_str(out
);
139 template <typename T
>
140 void ThirdPartyAccountApplier
<T
>::load_acct_info(RGWUserInfo
& user_info
) const
142 if (UNKNOWN_ACCT
== acct_user_override
) {
143 /* There is no override specified by the upper layer. This means that we'll
144 * load the account owned by the authenticated identity (aka auth_user). */
145 DecoratedApplier
<T
>::load_acct_info(user_info
);
146 } else if (DecoratedApplier
<T
>::is_owner_of(acct_user_override
)) {
147 /* The override has been specified but the account belongs to the authenticated
148 * identity. We may safely forward the call to a next stage. */
149 DecoratedApplier
<T
>::load_acct_info(user_info
);
151 /* Compatibility mechanism for multi-tenancy. For more details refer to
152 * load_acct_info method of rgw::auth::RemoteApplier. */
153 if (acct_user_override
.tenant
.empty()) {
154 const rgw_user
tenanted_uid(acct_user_override
.id
, acct_user_override
.id
);
156 if (rgw_get_user_info_by_uid(store
, tenanted_uid
, user_info
) >= 0) {
162 const int ret
= rgw_get_user_info_by_uid(store
, acct_user_override
, user_info
);
164 /* We aren't trying to recover from ENOENT here. It's supposed that creating
165 * someone else's account isn't a thing we want to support in this filter. */
166 if (ret
== -ENOENT
) {
176 template <typename T
> static inline
177 ThirdPartyAccountApplier
<T
> add_3rdparty(RGWRados
* const store
,
178 const rgw_user acct_user_override
,
180 return ThirdPartyAccountApplier
<T
>(store
, acct_user_override
,
185 template <typename T
>
186 class SysReqApplier
: public DecoratedApplier
<T
> {
187 CephContext
* const cct
;
188 /*const*/ RGWRados
* const store
;
189 const RGWHTTPArgs
& args
;
190 mutable boost::tribool is_system
;
193 template <typename U
>
194 SysReqApplier(CephContext
* const cct
,
195 /*const*/ RGWRados
* const store
,
196 const req_state
* const s
,
198 : DecoratedApplier
<T
>(std::forward
<T
>(decoratee
)),
202 is_system(boost::logic::indeterminate
) {
205 void to_str(std::ostream
& out
) const override
;
206 void load_acct_info(RGWUserInfo
& user_info
) const override
; /* out */
207 void modify_request_state(req_state
* s
) const override
; /* in/out */
210 template <typename T
>
211 void SysReqApplier
<T
>::to_str(std::ostream
& out
) const
213 out
<< "rgw::auth::SysReqApplier" << " -> ";
214 DecoratedApplier
<T
>::to_str(out
);
217 template <typename T
>
218 void SysReqApplier
<T
>::load_acct_info(RGWUserInfo
& user_info
) const
220 DecoratedApplier
<T
>::load_acct_info(user_info
);
221 is_system
= user_info
.system
;
224 //dout(20) << "system request" << dendl;
226 rgw_user
effective_uid(args
.sys_get(RGW_SYS_PARAM_PREFIX
"uid"));
227 if (! effective_uid
.empty()) {
228 /* We aren't writing directly to user_info for consistency and security
229 * reasons. rgw_get_user_info_by_uid doesn't trigger the operator=() but
230 * calls ::decode instead. */
231 RGWUserInfo euser_info
;
232 if (rgw_get_user_info_by_uid(store
, effective_uid
, euser_info
) < 0) {
233 //ldout(s->cct, 0) << "User lookup failed!" << dendl;
236 user_info
= euser_info
;
241 template <typename T
>
242 void SysReqApplier
<T
>::modify_request_state(req_state
* const s
) const
244 if (boost::logic::indeterminate(is_system
)) {
245 RGWUserInfo unused_info
;
246 load_acct_info(unused_info
);
250 s
->info
.args
.set_system();
251 s
->system_request
= true;
255 template <typename T
> static inline
256 SysReqApplier
<T
> add_sysreq(CephContext
* const cct
,
257 /* const */ RGWRados
* const store
,
258 const req_state
* const s
,
260 return SysReqApplier
<T
>(cct
, store
, s
, std::forward
<T
>(t
));
263 } /* namespace auth */
264 } /* namespace rgw */
266 #endif /* CEPH_RGW_AUTH_FILTERS_H */