Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / rgw / rgw_auth_filters.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #ifndef CEPH_RGW_AUTH_FILTERS_H
5 #define CEPH_RGW_AUTH_FILTERS_H
6
7 #include <type_traits>
8
9 #include <boost/logic/tribool.hpp>
10 #include <boost/optional.hpp>
11
12 #include "rgw_common.h"
13 #include "rgw_auth.h"
14
15 namespace rgw {
16 namespace auth {
17
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;
23
24   static_assert(std::is_base_of<rgw::auth::IdentityApplier,
25                                 DerefedDecorateeT>::value,
26                 "DecorateeT must be a subclass of rgw::auth::IdentityApplier");
27
28   DecorateeT decoratee;
29
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() {
38     return *decoratee;
39   }
40
41   template <typename T = void,
42             typename std::enable_if<
43     ! std::is_pointer<DecorateeT>::value, T>::type* = nullptr>
44   DerefedDecorateeT& get_decoratee() {
45     return decoratee;
46   }
47
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 {
52     return *decoratee;
53   }
54
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 {
59     return decoratee;
60   }
61
62 public:
63   DecoratedApplier(DecorateeT&& decoratee)
64     : decoratee(std::forward<DecorateeT>(decoratee)) {
65   }
66
67   uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override {
68     return get_decoratee().get_perms_from_aclspec(aclspec);
69   }
70
71   bool is_admin_of(const rgw_user& uid) const override {
72     return get_decoratee().is_admin_of(uid);
73   }
74
75   bool is_owner_of(const rgw_user& uid) const override {
76     return get_decoratee().is_owner_of(uid);
77   }
78
79   uint32_t get_perm_mask() const override {
80     return get_decoratee().get_perm_mask();
81   }
82
83   bool is_identity(
84     const boost::container::flat_set<Principal>& ids) const override {
85     return get_decoratee().is_identity(ids);
86   }
87
88   void to_str(std::ostream& out) const override {
89     get_decoratee().to_str(out);
90   }
91
92   void load_acct_info(RGWUserInfo& user_info) const override {  /* out */
93     return get_decoratee().load_acct_info(user_info);
94   }
95
96   void modify_request_state(req_state * s) const override {     /* in/out */
97     return get_decoratee().modify_request_state(s);
98   }
99 };
100
101
102 template <typename T>
103 class ThirdPartyAccountApplier : public DecoratedApplier<T> {
104   /* const */RGWRados* const store;
105   const rgw_user acct_user_override;
106
107 public:
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;
112
113   template <typename U>
114   ThirdPartyAccountApplier(RGWRados* const store,
115                            const rgw_user acct_user_override,
116                            U&& decoratee)
117     : DecoratedApplier<T>(std::move(decoratee)),
118       store(store),
119       acct_user_override(acct_user_override) {
120   }
121
122   void to_str(std::ostream& out) const override;
123   void load_acct_info(RGWUserInfo& user_info) const override;   /* out */
124 };
125
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;
130
131 template <typename T>
132 void ThirdPartyAccountApplier<T>::to_str(std::ostream& out) const
133 {
134   out << "rgw::auth::ThirdPartyAccountApplier(" + acct_user_override.to_str() + ")"
135       <<   " -> ";
136   DecoratedApplier<T>::to_str(out);
137 }
138
139 template <typename T>
140 void ThirdPartyAccountApplier<T>::load_acct_info(RGWUserInfo& user_info) const
141 {
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);
150   } else {
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);
155
156       if (rgw_get_user_info_by_uid(store, tenanted_uid, user_info) >= 0) {
157         /* Succeeded. */
158         return;
159       }
160     }
161
162     const int ret = rgw_get_user_info_by_uid(store, acct_user_override, user_info);
163     if (ret < 0) {
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) {
167         throw -EACCES;
168       } else {
169         throw ret;
170       }
171     }
172
173   }
174 }
175
176 template <typename T> static inline
177 ThirdPartyAccountApplier<T> add_3rdparty(RGWRados* const store,
178                                          const rgw_user acct_user_override,
179                                          T&& t) {
180   return ThirdPartyAccountApplier<T>(store, acct_user_override,
181                                      std::forward<T>(t));
182 }
183
184
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;
191
192 public:
193   template <typename U>
194   SysReqApplier(CephContext* const cct,
195                 /*const*/ RGWRados* const store,
196                 const req_state* const s,
197                 U&& decoratee)
198     : DecoratedApplier<T>(std::forward<T>(decoratee)),
199       cct(cct),
200       store(store),
201       args(s->info.args),
202       is_system(boost::logic::indeterminate) {
203   }
204
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 */
208 };
209
210 template <typename T>
211 void SysReqApplier<T>::to_str(std::ostream& out) const
212 {
213   out << "rgw::auth::SysReqApplier" << " -> ";
214   DecoratedApplier<T>::to_str(out);
215 }
216
217 template <typename T>
218 void SysReqApplier<T>::load_acct_info(RGWUserInfo& user_info) const
219 {
220   DecoratedApplier<T>::load_acct_info(user_info);
221   is_system = user_info.system;
222
223   if (is_system) {
224     //dout(20) << "system request" << dendl;
225
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;
234         throw -EACCES;
235       }
236       user_info = euser_info;
237     }
238   }
239 }
240
241 template <typename T>
242 void SysReqApplier<T>::modify_request_state(req_state* const s) const
243 {
244   if (boost::logic::indeterminate(is_system)) {
245     RGWUserInfo unused_info;
246     load_acct_info(unused_info);
247   }
248
249   if (is_system) {
250     s->info.args.set_system();
251     s->system_request = true;
252   }
253 }
254
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,
259                             T&& t) {
260   return SysReqApplier<T>(cct, store, s, std::forward<T>(t));
261 }
262
263 } /* namespace auth */
264 } /* namespace rgw */
265
266 #endif /* CEPH_RGW_AUTH_FILTERS_H */