]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_auth.cc
bump version to 12.0.3-pve3
[ceph.git] / ceph / src / rgw / rgw_auth.cc
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#include <array>
5
6#include "rgw_common.h"
7#include "rgw_auth.h"
8#include "rgw_user.h"
9#include "rgw_http_client.h"
10#include "rgw_keystone.h"
11
12#include "include/str_list.h"
13
14#define dout_context g_ceph_context
15#define dout_subsys ceph_subsys_rgw
16
17
18namespace rgw {
19namespace auth {
20
21std::unique_ptr<rgw::auth::Identity>
22transform_old_authinfo(const req_state* const s)
23{
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
26 * infrastructure. */
27 class DummyIdentityApplier : public rgw::auth::Identity {
28 CephContext* const cct;
29
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
32 * new auth. */
33 const rgw_user id;
34 const int perm_mask;
35 const bool is_admin;
36 public:
37 DummyIdentityApplier(CephContext* const cct,
38 const rgw_user& auth_id,
39 const int perm_mask,
40 const bool is_admin)
41 : cct(cct),
42 id(auth_id),
43 perm_mask(perm_mask),
44 is_admin(is_admin) {
45 }
46
47 uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override {
48 return rgw_perms_from_aclspec_default_strategy(id, aclspec);
49 }
50
51 bool is_admin_of(const rgw_user& acct_id) const override {
52 return is_admin;
53 }
54
55 bool is_owner_of(const rgw_user& acct_id) const override {
56 return id == acct_id;
57 }
58
59 uint32_t get_perm_mask() const override {
60 return perm_mask;
61 }
62
63 void to_str(std::ostream& out) const override {
64 out << "RGWDummyIdentityApplier(auth_id=" << id
65 << ", perm_mask=" << perm_mask
66 << ", is_admin=" << is_admin << ")";
67 }
68 };
69
70 return std::unique_ptr<rgw::auth::Identity>(
71 new DummyIdentityApplier(s->cct,
72 s->user->user_id,
73 s->perm_mask,
74 /* System user has admin permissions by default - it's supposed to pass
75 * through any security check. */
76 s->system_request));
77}
78
79} /* namespace auth */
80} /* namespace rgw */
81
82
83uint32_t rgw_perms_from_aclspec_default_strategy(
84 const rgw_user& uid,
85 const rgw::auth::Identity::aclspec_t& aclspec)
86{
87 dout(5) << "Searching permissions for uid=" << uid << dendl;
88
89 const auto iter = aclspec.find(uid.to_str());
90 if (std::end(aclspec) != iter) {
91 dout(5) << "Found permission: " << iter->second << dendl;
92 return iter->second;
93 }
94
95 dout(5) << "Permissions for user not found" << dendl;
96 return 0;
97}
98
99
100static inline const std::string make_spec_item(const std::string& tenant,
101 const std::string& id)
102{
103 return tenant + ":" + id;
104}
105
106
107static inline std::pair<bool, rgw::auth::Engine::result_t>
108strategy_handle_rejected(rgw::auth::Engine::result_t&& engine_result,
109 const rgw::auth::Strategy::Control policy,
110 rgw::auth::Engine::result_t&& strategy_result)
111{
112 using Control = rgw::auth::Strategy::Control;
113 switch (policy) {
114 case Control::REQUISITE:
115 /* Don't try next. */
116 return std::make_pair(false, std::move(engine_result));
117
118 case Control::SUFFICIENT:
119 /* Don't try next. */
120 return std::make_pair(false, std::move(engine_result));
121
122 case Control::FALLBACK:
123 /* Don't try next. */
124 return std::make_pair(false, std::move(strategy_result));
125
126 default:
127 /* Huh, memory corruption? */
128 abort();
129 }
130}
131
132static inline std::pair<bool, rgw::auth::Engine::result_t>
133strategy_handle_denied(rgw::auth::Engine::result_t&& engine_result,
134 const rgw::auth::Strategy::Control policy,
135 rgw::auth::Engine::result_t&& strategy_result)
136{
137 using Control = rgw::auth::Strategy::Control;
138 switch (policy) {
139 case Control::REQUISITE:
140 /* Don't try next. */
141 return std::make_pair(false, std::move(engine_result));
142
143 case Control::SUFFICIENT:
144 /* Just try next. */
145 return std::make_pair(true, std::move(engine_result));
146
147 case Control::FALLBACK:
148 return std::make_pair(true, std::move(strategy_result));
149
150 default:
151 /* Huh, memory corruption? */
152 abort();
153 }
154}
155
156static inline std::pair<bool, rgw::auth::Engine::result_t>
157strategy_handle_granted(rgw::auth::Engine::result_t&& engine_result,
158 const rgw::auth::Strategy::Control policy,
159 rgw::auth::Engine::result_t&& strategy_result)
160{
161 using Control = rgw::auth::Strategy::Control;
162 switch (policy) {
163 case Control::REQUISITE:
164 /* Try next. */
165 return std::make_pair(true, std::move(engine_result));
166
167 case Control::SUFFICIENT:
168 /* Don't try next. */
169 return std::make_pair(false, std::move(engine_result));
170
171 case Control::FALLBACK:
172 /* Don't try next. */
173 return std::make_pair(false, std::move(engine_result));
174
175 default:
176 /* Huh, memory corruption? */
177 abort();
178 }
179}
180
181rgw::auth::Engine::result_t
182rgw::auth::Strategy::authenticate(const req_state* const s) const
183{
184 result_t strategy_result = result_t::deny();
185
186 for (const stack_item_t& kv : auth_stack) {
187 const rgw::auth::Engine& engine = kv.first;
188 const auto& policy = kv.second;
189
190 dout(20) << get_name() << ": trying " << engine.get_name() << dendl;
191
192 result_t engine_result = result_t::deny();
193 try {
194 engine_result = engine.authenticate(s);
195 } catch (const int err) {
196 engine_result = result_t::deny(err);
197 }
198
199 bool try_next = true;
200 switch (engine_result.get_status()) {
201 case result_t::Status::REJECTED: {
202 dout(20) << engine.get_name() << " rejected with reason="
203 << engine_result.get_reason() << dendl;
204
205 std::tie(try_next, strategy_result) = \
206 strategy_handle_rejected(std::move(engine_result), policy,
207 std::move(strategy_result));
208 break;
209 }
210 case result_t::Status::DENIED: {
211 dout(20) << engine.get_name() << " denied with reason="
212 << engine_result.get_reason() << dendl;
213
214 std::tie(try_next, strategy_result) = \
215 strategy_handle_denied(std::move(engine_result), policy,
216 std::move(strategy_result));
217 break;
218 }
219 case result_t::Status::GRANTED: {
220 dout(20) << engine.get_name() << " granted access" << dendl;
221
222 std::tie(try_next, strategy_result) = \
223 strategy_handle_granted(std::move(engine_result), policy,
224 std::move(strategy_result));
225 break;
226 }
227 default: {
228 abort();
229 }
230 }
231
232 if (! try_next) {
233 break;
234 }
235 }
236
237 return strategy_result;
238}
239
240void
241rgw::auth::Strategy::add_engine(const Control ctrl_flag,
242 const Engine& engine) noexcept
243{
244 auth_stack.push_back(std::make_pair(std::cref(engine), ctrl_flag));
245}
246
247
248/* rgw::auth::RemoteAuthApplier */
249uint32_t rgw::auth::RemoteApplier::get_perms_from_aclspec(const aclspec_t& aclspec) const
250{
251 uint32_t perm = 0;
252
253 /* For backward compatibility with ACLOwner. */
254 perm |= rgw_perms_from_aclspec_default_strategy(info.acct_user,
255 aclspec);
256
257 /* We also need to cover cases where rgw_keystone_implicit_tenants
258 * was enabled. */
259 if (info.acct_user.tenant.empty()) {
260 const rgw_user tenanted_acct_user(info.acct_user.id, info.acct_user.id);
261
262 perm |= rgw_perms_from_aclspec_default_strategy(tenanted_acct_user,
263 aclspec);
264 }
265
266 /* Now it's a time for invoking additional strategy that was supplied by
267 * a specific auth engine. */
268 if (extra_acl_strategy) {
269 perm |= extra_acl_strategy(aclspec);
270 }
271
272 ldout(cct, 20) << "from ACL got perm=" << perm << dendl;
273 return perm;
274}
275
276bool rgw::auth::RemoteApplier::is_admin_of(const rgw_user& uid) const
277{
278 return info.is_admin;
279}
280
281bool rgw::auth::RemoteApplier::is_owner_of(const rgw_user& uid) const
282{
283 if (info.acct_user.tenant.empty()) {
284 const rgw_user tenanted_acct_user(info.acct_user.id, info.acct_user.id);
285
286 if (tenanted_acct_user == uid) {
287 return true;
288 }
289 }
290
291 return info.acct_user == uid;
292}
293
294void rgw::auth::RemoteApplier::to_str(std::ostream& out) const
295{
296 out << "rgw::auth::RemoteApplier(acct_user=" << info.acct_user
297 << ", acct_name=" << info.acct_name
298 << ", perm_mask=" << info.perm_mask
299 << ", is_admin=" << info.is_admin << ")";
300}
301
302void rgw::auth::RemoteApplier::create_account(const rgw_user& acct_user,
303 RGWUserInfo& user_info) const /* out */
304{
305 rgw_user new_acct_user = acct_user;
306
307 if (info.acct_type) {
308 //ldap/keystone for s3 users
309 user_info.type = info.acct_type;
310 }
311
312 /* An upper layer may enforce creating new accounts within their own
313 * tenants. */
314 if (new_acct_user.tenant.empty() && implicit_tenants) {
315 new_acct_user.tenant = new_acct_user.id;
316 }
317
318 user_info.user_id = new_acct_user;
319 user_info.display_name = info.acct_name;
320
321 int ret = rgw_store_user_info(store, user_info, nullptr, nullptr,
322 real_time(), true);
323 if (ret < 0) {
324 ldout(cct, 0) << "ERROR: failed to store new user info: user="
325 << user_info.user_id << " ret=" << ret << dendl;
326 throw ret;
327 }
328}
329
330/* TODO(rzarzynski): we need to handle display_name changes. */
331void rgw::auth::RemoteApplier::load_acct_info(RGWUserInfo& user_info) const /* out */
332{
333 /* It's supposed that RGWRemoteAuthApplier tries to load account info
334 * that belongs to the authenticated identity. Another policy may be
335 * applied by using a RGWThirdPartyAccountAuthApplier decorator. */
336 const rgw_user& acct_user = info.acct_user;
337
338 /* Normally, empty "tenant" field of acct_user means the authenticated
339 * identity has the legacy, global tenant. However, due to inclusion
340 * of multi-tenancy, we got some special compatibility kludge for remote
341 * backends like Keystone.
342 * If the global tenant is the requested one, we try the same tenant as
343 * the user name first. If that RGWUserInfo exists, we use it. This way,
344 * migrated OpenStack users can get their namespaced containers and nobody's
345 * the wiser.
346 * If that fails, we look up in the requested (possibly empty) tenant.
347 * If that fails too, we create the account within the global or separated
348 * namespace depending on rgw_keystone_implicit_tenants. */
349 if (acct_user.tenant.empty()) {
350 const rgw_user tenanted_uid(acct_user.id, acct_user.id);
351
352 if (rgw_get_user_info_by_uid(store, tenanted_uid, user_info) >= 0) {
353 /* Succeeded. */
354 return;
355 }
356 }
357
358 if (rgw_get_user_info_by_uid(store, acct_user, user_info) < 0) {
359 ldout(cct, 0) << "NOTICE: couldn't map swift user " << acct_user << dendl;
360 create_account(acct_user, user_info);
361 }
362
363 /* Succeeded if we are here (create_account() hasn't throwed). */
364}
365
366
367/* rgw::auth::LocalApplier */
368/* static declaration */
369const std::string rgw::auth::LocalApplier::NO_SUBUSER;
370
371uint32_t rgw::auth::LocalApplier::get_perms_from_aclspec(const aclspec_t& aclspec) const
372{
373 return rgw_perms_from_aclspec_default_strategy(user_info.user_id, aclspec);
374}
375
376bool rgw::auth::LocalApplier::is_admin_of(const rgw_user& uid) const
377{
378 return user_info.admin || user_info.system;
379}
380
381bool rgw::auth::LocalApplier::is_owner_of(const rgw_user& uid) const
382{
383 return uid == user_info.user_id;
384}
385
386void rgw::auth::LocalApplier::to_str(std::ostream& out) const
387{
388 out << "rgw::auth::LocalApplier(acct_user=" << user_info.user_id
389 << ", acct_name=" << user_info.display_name
390 << ", subuser=" << subuser
391 << ", perm_mask=" << get_perm_mask()
392 << ", is_admin=" << static_cast<bool>(user_info.admin) << ")";
393}
394
395uint32_t rgw::auth::LocalApplier::get_perm_mask(const std::string& subuser_name,
396 const RGWUserInfo &uinfo) const
397{
398 if (! subuser_name.empty() && subuser_name != NO_SUBUSER) {
399 const auto iter = uinfo.subusers.find(subuser_name);
400
401 if (iter != std::end(uinfo.subusers)) {
402 return iter->second.perm_mask;
403 } else {
404 /* Subuser specified but not found. */
405 return RGW_PERM_NONE;
406 }
407 } else {
408 /* Due to backward compatibility. */
409 return RGW_PERM_FULL_CONTROL;
410 }
411}
412
413void rgw::auth::LocalApplier::load_acct_info(RGWUserInfo& user_info) const /* out */
414{
415 /* Load the account that belongs to the authenticated identity. An extra call
416 * to RADOS may be safely skipped in this case. */
417 user_info = this->user_info;
418}
419
420
421rgw::auth::Engine::result_t
422rgw::auth::AnonymousEngine::authenticate(const req_state* const s) const
423{
424 if (! is_applicable(s)) {
425 return result_t::deny();
426 } else {
427 RGWUserInfo user_info;
428 rgw_get_anon_user(user_info);
429
430 // FIXME: over 80 columns
431 auto apl = apl_factory->create_apl_local(cct, s, user_info,
432 rgw::auth::LocalApplier::NO_SUBUSER);
433 return result_t::grant(std::move(apl));
434 }
435}