summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_auth_filters.h
blob: 1b59f3bb25a1bed099bc862a664add518429b11b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab ft=cpp

#ifndef CEPH_RGW_AUTH_FILTERS_H
#define CEPH_RGW_AUTH_FILTERS_H

#include <type_traits>

#include <boost/logic/tribool.hpp>
#include <boost/optional.hpp>

#include "rgw_service.h"
#include "rgw_common.h"
#include "rgw_auth.h"
#include "rgw_user.h"

namespace rgw {
namespace auth {

/* Abstract decorator over any implementation of rgw::auth::IdentityApplier
 * which could be provided both as a pointer-to-object or the object itself. */
template <typename DecorateeT>
class DecoratedApplier : public rgw::auth::IdentityApplier {
  typedef typename std::remove_pointer<DecorateeT>::type DerefedDecorateeT;

  static_assert(std::is_base_of<rgw::auth::IdentityApplier,
                                DerefedDecorateeT>::value,
                "DecorateeT must be a subclass of rgw::auth::IdentityApplier");

  DecorateeT decoratee;

  /* There is an indirection layer over accessing decoratee to share the same
   * code base between dynamic and static decorators. The difference is about
   * what we store internally: pointer to a decorated object versus the whole
   * object itself. Googling for "SFINAE" can help to understand the code. */
  template <typename T = void,
            typename std::enable_if<
    std::is_pointer<DecorateeT>::value, T>::type* = nullptr>
  DerefedDecorateeT& get_decoratee() {
    return *decoratee;
  }

  template <typename T = void,
            typename std::enable_if<
    ! std::is_pointer<DecorateeT>::value, T>::type* = nullptr>
  DerefedDecorateeT& get_decoratee() {
    return decoratee;
  }

  template <typename T = void,
            typename std::enable_if<
    std::is_pointer<DecorateeT>::value, T>::type* = nullptr>
  const DerefedDecorateeT& get_decoratee() const {
    return *decoratee;
  }

  template <typename T = void,
            typename std::enable_if<
    ! std::is_pointer<DecorateeT>::value, T>::type* = nullptr>
  const DerefedDecorateeT& get_decoratee() const {
    return decoratee;
  }

public:
  explicit DecoratedApplier(DecorateeT&& decoratee)
    : decoratee(std::forward<DecorateeT>(decoratee)) {
  }

  uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override {
    return get_decoratee().get_perms_from_aclspec(dpp, aclspec);
  }

  bool is_admin_of(const rgw_user& uid) const override {
    return get_decoratee().is_admin_of(uid);
  }

  bool is_owner_of(const rgw_user& uid) const override {
    return get_decoratee().is_owner_of(uid);
  }

  bool is_anonymous() const override {
    return get_decoratee().is_anonymous();
  }

  uint32_t get_perm_mask() const override {
    return get_decoratee().get_perm_mask();
  }

  uint32_t get_identity_type() const override {
    return get_decoratee().get_identity_type();
  }

  string get_acct_name() const override {
    return get_decoratee().get_acct_name();
  }

  string get_subuser() const override {
    return get_decoratee().get_subuser();
  }

  bool is_identity(
    const boost::container::flat_set<Principal>& ids) const override {
    return get_decoratee().is_identity(ids);
  }

  void to_str(std::ostream& out) const override {
    get_decoratee().to_str(out);
  }

  string get_role_tenant() const override {     /* in/out */
    return get_decoratee().get_role_tenant();
  }

  void load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const override {  /* out */
    return get_decoratee().load_acct_info(dpp, user_info);
  }

  void modify_request_state(const DoutPrefixProvider* dpp, req_state * s) const override {     /* in/out */
    return get_decoratee().modify_request_state(dpp, s);
  }

  void write_ops_log_entry(rgw_log_entry& entry) const override {
    return get_decoratee().write_ops_log_entry(entry);
  }
};


template <typename T>
class ThirdPartyAccountApplier : public DecoratedApplier<T> {
  /* const */RGWCtl* const ctl;
  const rgw_user acct_user_override;

public:
  /* A value representing situations where there is no requested account
   * override. In other words, acct_user_override will be equal to this
   * constant where the request isn't a cross-tenant one. */
  static const rgw_user UNKNOWN_ACCT;

  template <typename U>
  ThirdPartyAccountApplier(RGWCtl* const ctl,
                           const rgw_user &acct_user_override,
                           U&& decoratee)
    : DecoratedApplier<T>(std::move(decoratee)),
      ctl(ctl),
      acct_user_override(acct_user_override) {
  }

  void to_str(std::ostream& out) const override;
  void load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const override;   /* out */
};

/* static declaration: UNKNOWN_ACCT will be an empty rgw_user that is a result
 * of the default construction. */
template <typename T>
const rgw_user ThirdPartyAccountApplier<T>::UNKNOWN_ACCT;

template <typename T>
void ThirdPartyAccountApplier<T>::to_str(std::ostream& out) const
{
  out << "rgw::auth::ThirdPartyAccountApplier(" + acct_user_override.to_str() + ")"
      <<   " -> ";
  DecoratedApplier<T>::to_str(out);
}

template <typename T>
void ThirdPartyAccountApplier<T>::load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const
{
  if (UNKNOWN_ACCT == acct_user_override) {
    /* There is no override specified by the upper layer. This means that we'll
     * load the account owned by the authenticated identity (aka auth_user). */
    DecoratedApplier<T>::load_acct_info(dpp, user_info);
  } else if (DecoratedApplier<T>::is_owner_of(acct_user_override)) {
    /* The override has been specified but the account belongs to the authenticated
     * identity. We may safely forward the call to a next stage. */
    DecoratedApplier<T>::load_acct_info(dpp, user_info);
  } else if (this->is_anonymous()) {
    /* If the user was authed by the anonymous engine then scope the ANON user
     * to the correct tenant */
    if (acct_user_override.tenant.empty())
      user_info.user_id = rgw_user(acct_user_override.id, RGW_USER_ANON_ID);
    else
      user_info.user_id = rgw_user(acct_user_override.tenant, RGW_USER_ANON_ID);
  } else {
    /* Compatibility mechanism for multi-tenancy. For more details refer to
     * load_acct_info method of rgw::auth::RemoteApplier. */
    if (acct_user_override.tenant.empty()) {
      const rgw_user tenanted_uid(acct_user_override.id, acct_user_override.id);

      if (ctl->user->get_info_by_uid(dpp, tenanted_uid, &user_info, null_yield) >= 0) {
        /* Succeeded. */
        return;
      }
    }

    const int ret = ctl->user->get_info_by_uid(dpp, acct_user_override, &user_info, null_yield);
    if (ret < 0) {
      /* We aren't trying to recover from ENOENT here. It's supposed that creating
       * someone else's account isn't a thing we want to support in this filter. */
      if (ret == -ENOENT) {
        throw -EACCES;
      } else {
        throw ret;
      }
    }

  }
}

template <typename T> static inline
ThirdPartyAccountApplier<T> add_3rdparty(RGWCtl* const ctl,
                                         const rgw_user &acct_user_override,
                                         T&& t) {
  return ThirdPartyAccountApplier<T>(ctl, acct_user_override,
                                     std::forward<T>(t));
}


template <typename T>
class SysReqApplier : public DecoratedApplier<T> {
  CephContext* const cct;
  /*const*/ RGWCtl* const ctl;
  const RGWHTTPArgs& args;
  mutable boost::tribool is_system;

public:
  template <typename U>
  SysReqApplier(CephContext* const cct,
                /*const*/ RGWCtl* const ctl,
                const req_state* const s,
                U&& decoratee)
    : DecoratedApplier<T>(std::forward<T>(decoratee)),
      cct(cct),
      ctl(ctl),
      args(s->info.args),
      is_system(boost::logic::indeterminate) {
  }

  void to_str(std::ostream& out) const override;
  void load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const override;   /* out */
  void modify_request_state(const DoutPrefixProvider* dpp, req_state* s) const override;       /* in/out */
};

template <typename T>
void SysReqApplier<T>::to_str(std::ostream& out) const
{
  out << "rgw::auth::SysReqApplier" << " -> ";
  DecoratedApplier<T>::to_str(out);
}

template <typename T>
void SysReqApplier<T>::load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const
{
  DecoratedApplier<T>::load_acct_info(dpp, user_info);
  is_system = user_info.system;

  if (is_system) {
    //ldpp_dout(dpp, 20) << "system request" << dendl;

    rgw_user effective_uid(args.sys_get(RGW_SYS_PARAM_PREFIX "uid"));
    if (! effective_uid.empty()) {
      /* We aren't writing directly to user_info for consistency and security
       * reasons. rgw_get_user_info_by_uid doesn't trigger the operator=() but
       * calls ::decode instead. */
      RGWUserInfo euser_info;
      if (ctl->user->get_info_by_uid(dpp, effective_uid, &euser_info, null_yield) < 0) {
        //ldpp_dout(dpp, 0) << "User lookup failed!" << dendl;
        throw -EACCES;
      }
      user_info = euser_info;
    }
  }
}

template <typename T>
void SysReqApplier<T>::modify_request_state(const DoutPrefixProvider* dpp, req_state* const s) const
{
  if (boost::logic::indeterminate(is_system)) {
    RGWUserInfo unused_info;
    load_acct_info(dpp, unused_info);
  }

  if (is_system) {
    s->info.args.set_system();
    s->system_request = true;
  }
  DecoratedApplier<T>::modify_request_state(dpp, s);
}

template <typename T> static inline
SysReqApplier<T> add_sysreq(CephContext* const cct,
                            /* const */ RGWCtl* const ctl,
                            const req_state* const s,
                            T&& t) {
  return SysReqApplier<T>(cct, ctl, s, std::forward<T>(t));
}

} /* namespace auth */
} /* namespace rgw */

#endif /* CEPH_RGW_AUTH_FILTERS_H */