Skip to content

Commit

Permalink
Merge pull request ceph#27178 from pritha-srivastava/wip-rgw-iam
Browse files Browse the repository at this point in the history
rgw: Adding 'iam' namespace for Role and User Policy related REST APIs.

Reviewed-by: Adam C. Emerson <[email protected]>
Reviewed-by: Matt Benjamin <[email protected]>
  • Loading branch information
cbodley authored Apr 15, 2019
2 parents dde34ed + 121a269 commit be4017e
Show file tree
Hide file tree
Showing 16 changed files with 375 additions and 74 deletions.
2 changes: 1 addition & 1 deletion src/common/options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5504,7 +5504,7 @@ std::vector<Option> get_rgw_options() {
"will be located in the path that is specified here. "),

Option("rgw_enable_apis", Option::TYPE_STR, Option::LEVEL_ADVANCED)
.set_default("s3, s3website, swift, swift_auth, admin, sts")
.set_default("s3, s3website, swift, swift_auth, admin, sts, iam")
.set_description("A list of set of RESTful APIs that rgw handles."),

Option("rgw_cache_enabled", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
Expand Down
3 changes: 2 additions & 1 deletion src/rgw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ set(librgw_common_srcs
rgw_zone.cc
rgw_sts.cc
rgw_rest_sts.cc
rgw_perf_counters.cc)
rgw_perf_counters.cc
rgw_rest_iam.cc)

if(WITH_RADOSGW_AMQP_ENDPOINT)
list(APPEND librgw_common_srcs rgw_amqp.cc)
Expand Down
12 changes: 10 additions & 2 deletions src/rgw/rgw_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ rgw_http_errors rgw_http_s3_errors({
{ ERR_EMAIL_EXIST, {409, "EmailExists" }},
{ ERR_KEY_EXIST, {409, "KeyExists"}},
{ ERR_TAG_CONFLICT, {409, "OperationAborted"}},
{ ERR_ROLE_EXISTS, {409, "EntityAlreadyExists"}},
{ ERR_DELETE_CONFLICT, {409, "DeleteConflict"}},
{ ERR_POSITION_NOT_EQUAL_TO_LENGTH, {409, "PositionNotEqualToLength"}},
{ ERR_OBJECT_NOT_APPENDABLE, {409, "ObjectNotAppendable"}},
{ ERR_INVALID_BUCKET_STATE, {409, "InvalidBucketState"}},
Expand Down Expand Up @@ -147,6 +145,11 @@ rgw_http_errors rgw_http_sts_errors({
{ ERR_INVALID_IDENTITY_TOKEN, {400, "InvalidIdentityToken" }},
});

rgw_http_errors rgw_http_iam_errors({
{ ERR_ROLE_EXISTS, {409, "EntityAlreadyExists"}},
{ ERR_DELETE_CONFLICT, {409, "DeleteConflict"}},
});

using namespace ceph::crypto;

rgw_err::
Expand Down Expand Up @@ -301,6 +304,11 @@ void set_req_state_err(struct rgw_err& err, /* out */
return;
}

if (prot_flags & RGW_REST_IAM) {
if (search_err(rgw_http_iam_errors, err_no, err.http_ret, err.err_code))
return;
}

//Default to searching in s3 errors
if (search_err(rgw_http_s3_errors, err_no, err.http_ret, err.err_code))
return;
Expand Down
1 change: 1 addition & 0 deletions src/rgw/rgw_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ using ceph::crypto::MD5;
#define RGW_REST_S3 0x4
#define RGW_REST_WEBSITE 0x8
#define RGW_REST_STS 0x10
#define RGW_REST_IAM 0x20

#define RGW_SUSPENDED_USER_AUID (uint64_t)-2

Expand Down
2 changes: 2 additions & 0 deletions src/rgw/rgw_http_errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ extern rgw_http_errors rgw_http_swift_errors;

extern rgw_http_errors rgw_http_sts_errors;

extern rgw_http_errors rgw_http_iam_errors;

static inline int rgw_http_error_to_errno(int http_err)
{
if (http_err >= 200 && http_err <= 299)
Expand Down
3 changes: 2 additions & 1 deletion src/rgw/rgw_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -356,12 +356,13 @@ int main(int argc, const char **argv)
// S3 website mode is a specialization of S3
const bool s3website_enabled = apis_map.count("s3website") > 0;
const bool sts_enabled = apis_map.count("sts") > 0;
const bool iam_enabled = apis_map.count("iam") > 0;
// Swift API entrypoint could placed in the root instead of S3
const bool swift_at_root = g_conf()->rgw_swift_url_prefix == "/";
if (apis_map.count("s3") > 0 || s3website_enabled) {
if (! swift_at_root) {
rest.register_default_mgr(set_logging(rest_filter(store, RGW_REST_S3,
new RGWRESTMgr_S3(s3website_enabled, sts_enabled))));
new RGWRESTMgr_S3(s3website_enabled, sts_enabled, iam_enabled))));
} else {
derr << "Cannot have the S3 or S3 Website enabled together with "
<< "Swift API placed in the root of hierarchy" << dendl;
Expand Down
2 changes: 2 additions & 0 deletions src/rgw/rgw_rest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
#include <limits.h>

#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>
#include "common/Formatter.h"
#include "common/HTMLFormatter.h"
#include "common/utf8.h"
#include "include/str_list.h"
#include "rgw_common.h"
#include "rgw_rados.h"
#include "rgw_zone.h"
#include "rgw_auth_s3.h"
#include "rgw_formats.h"
#include "rgw_op.h"
#include "rgw_rest.h"
Expand Down
147 changes: 147 additions & 0 deletions src/rgw/rgw_rest_iam.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#include <boost/tokenizer.hpp>

#include "rgw_rest.h"
#include "rgw_rest_iam.h"

#include "rgw_request.h"
#include "rgw_process.h"

#include "rgw_rest_role.h"
#include "rgw_rest_user_policy.h"

#define dout_context g_ceph_context
#define dout_subsys ceph_subsys_rgw

void RGWHandler_REST_IAM::rgw_iam_parse_input()
{
if (post_body.size() > 0) {
ldout(s->cct, 10) << "Content of POST: " << post_body << dendl;

if (post_body.find("Action") != string::npos) {
boost::char_separator<char> sep("&");
boost::tokenizer<boost::char_separator<char>> tokens(post_body, sep);
for (const auto& t : tokens) {
auto pos = t.find("=");
if (pos != string::npos) {
std::string key = t.substr(0, pos);
std::string value = t.substr(pos + 1, t.size() - 1);
if (key == "AssumeRolePolicyDocument" || key == "Path" || key == "PolicyDocument") {
value = url_decode(value);
}
s->info.args.append(key, value);
}
}
}
}
auto payload_hash = rgw::auth::s3::calc_v4_payload_hash(post_body);
s->info.args.append("PayloadHash", payload_hash);
}

RGWOp *RGWHandler_REST_IAM::op_post()
{
rgw_iam_parse_input();

if (s->info.args.exists("Action")) {
string action = s->info.args.get("Action");
if (action.compare("CreateRole") == 0)
return new RGWCreateRole;
if (action.compare("DeleteRole") == 0)
return new RGWDeleteRole;
if (action.compare("GetRole") == 0)
return new RGWGetRole;
if (action.compare("UpdateAssumeRolePolicy") == 0)
return new RGWModifyRole;
if (action.compare("ListRoles") == 0)
return new RGWListRoles;
if (action.compare("PutRolePolicy") == 0)
return new RGWPutRolePolicy;
if (action.compare("GetRolePolicy") == 0)
return new RGWGetRolePolicy;
if (action.compare("ListRolePolicies") == 0)
return new RGWListRolePolicies;
if (action.compare("DeleteRolePolicy") == 0)
return new RGWDeleteRolePolicy;
if (action.compare("PutUserPolicy") == 0)
return new RGWPutUserPolicy;
if (action.compare("GetUserPolicy") == 0)
return new RGWGetUserPolicy;
if (action.compare("ListUserPolicies") == 0)
return new RGWListUserPolicies;
if (action.compare("DeleteUserPolicy") == 0)
return new RGWDeleteUserPolicy;
}

return nullptr;
}

int RGWHandler_REST_IAM::init(RGWRados *store,
struct req_state *s,
rgw::io::BasicClient *cio)
{
s->dialect = "iam";

if (int ret = RGWHandler_REST_IAM::init_from_header(s, RGW_FORMAT_XML, true); ret < 0) {
ldout(s->cct, 10) << "init_from_header returned err=" << ret << dendl;
return ret;
}

return RGWHandler_REST::init(store, s, cio);
}

int RGWHandler_REST_IAM::authorize(const DoutPrefixProvider* dpp)
{
return RGW_Auth_S3::authorize(dpp, store, auth_registry, s);
}

int RGWHandler_REST_IAM::init_from_header(struct req_state* s,
int default_formatter,
bool configurable_format)
{
string req;
string first;

s->prot_flags = RGW_REST_IAM;

const char *p, *req_name;
if (req_name = s->relative_uri.c_str(); *req_name == '?') {
p = req_name;
} else {
p = s->info.request_params.c_str();
}

s->info.args.set(p);
s->info.args.parse();

/* must be called after the args parsing */
if (int ret = allocate_formatter(s, default_formatter, configurable_format); ret < 0)
return ret;

if (*req_name != '/')
return 0;

req_name++;

if (!*req_name)
return 0;

req = req_name;
int pos = req.find('/');
if (pos >= 0) {
first = req.substr(0, pos);
} else {
first = req;
}

return 0;
}

RGWHandler_REST*
RGWRESTMgr_IAM::get_handler(struct req_state* const s,
const rgw::auth::StrategyRegistry& auth_registry,
const std::string& frontend_prefix)
{
return new RGWHandler_REST_IAM(auth_registry);
}
49 changes: 49 additions & 0 deletions src/rgw/rgw_rest_iam.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab

#ifndef CEPH_RGW_REST_IAM_H
#define CEPH_RGW_REST_IAM_H

#include "rgw_auth.h"
#include "rgw_auth_filters.h"

class RGWHandler_REST_IAM : public RGWHandler_REST {
const rgw::auth::StrategyRegistry& auth_registry;
const string& post_body;
RGWOp *op_post() override;
void rgw_iam_parse_input();
public:

static int init_from_header(struct req_state *s, int default_formatter, bool configurable_format);

RGWHandler_REST_IAM(const rgw::auth::StrategyRegistry& auth_registry, const string& post_body="")
: RGWHandler_REST(),
auth_registry(auth_registry),
post_body(post_body) {}
~RGWHandler_REST_IAM() override = default;

int init(RGWRados *store,
struct req_state *s,
rgw::io::BasicClient *cio) override;
int authorize(const DoutPrefixProvider* dpp) override;
int postauth_init() override { return 0; }
};

class RGWRESTMgr_IAM : public RGWRESTMgr {
public:
RGWRESTMgr_IAM() = default;
~RGWRESTMgr_IAM() override = default;

RGWRESTMgr *get_resource_mgr(struct req_state* const s,
const std::string& uri,
std::string* const out_uri) override {
return this;
}

RGWHandler_REST* get_handler(struct req_state*,
const rgw::auth::StrategyRegistry&,
const std::string&) override;
};

#endif /* CEPH_RGW_REST_STS_H */

Loading

0 comments on commit be4017e

Please sign in to comment.