]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_auth_filters.h
bump version to 12.1.1-pve1 while rebasing patches
[ceph.git] / ceph / src / rgw / rgw_auth_filters.h
CommitLineData
7c673cae
FG
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
15namespace rgw {
16namespace 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. */
20template <typename DecorateeT>
21class 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
62public:
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
31f18b77
FG
83 bool is_identity(
84 const boost::container::flat_set<Principal>& ids) const override {
85 return get_decoratee().is_identity(ids);
86 }
87
7c673cae
FG
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
102template <typename T>
103class ThirdPartyAccountApplier : public DecoratedApplier<T> {
104 /* const */RGWRados* const store;
105 const rgw_user acct_user_override;
106
107public:
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. */
128template <typename T>
129const rgw_user ThirdPartyAccountApplier<T>::UNKNOWN_ACCT;
130
131template <typename T>
132void 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
139template <typename T>
140void 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
176template <typename T> static inline
177ThirdPartyAccountApplier<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
185template <typename T>
186class SysReqApplier : public DecoratedApplier<T> {
187 CephContext* const cct;
188 /*const*/ RGWRados* const store;
189 const RGWHTTPArgs& args;
190 mutable boost::tribool is_system;
191
192public:
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
210template <typename T>
211void SysReqApplier<T>::to_str(std::ostream& out) const
212{
213 out << "rgw::auth::SysReqApplier" << " -> ";
214 DecoratedApplier<T>::to_str(out);
215}
216
217template <typename T>
218void 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
241template <typename T>
242void 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
255template <typename T> static inline
256SysReqApplier<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 */