Skip to content

Commit

Permalink
Merge pull request #14516 from smithfarm/wip-18909-kraken
Browse files Browse the repository at this point in the history
kraken: rgw: the swift container acl does not support field .ref

Reviewed-by: Orit Wasserman <owasserm@redhat.com>
Reviewed-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
  • Loading branch information
smithfarm committed Jul 7, 2017
2 parents d3a2417 + 935cc11 commit 1ed342d
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 95 deletions.
193 changes: 115 additions & 78 deletions src/rgw/rgw_acl_swift.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#include <vector>

#include <boost/algorithm/string/predicate.hpp>

#include "common/ceph_json.h"
#include "rgw_common.h"
#include "rgw_user.h"
Expand Down Expand Up @@ -43,6 +45,14 @@ static int parse_list(const std::string& uid_list,
return 0;
}

static bool is_referrer(const std::string& designator)
{
return designator.compare(".r") == 0 ||
designator.compare(".ref") == 0 ||
designator.compare(".referer") == 0 ||
designator.compare(".referrer") == 0;
}

static bool uid_is_public(const string& uid)
{
if (uid[0] != '.' || uid[1] != 'r')
Expand All @@ -58,103 +68,118 @@ static bool uid_is_public(const string& uid)
if (after.compare("*") != 0)
return false;

return sub.compare(".r") == 0 ||
sub.compare(".referer") == 0 ||
sub.compare(".referrer") == 0;
}

static bool extract_referer_urlspec(const std::string& uid,
std::string& url_spec)
{
const size_t pos = uid.find(':');
if (string::npos == pos) {
return false;
}

const auto sub = uid.substr(0, pos);
url_spec = uid.substr(pos + 1);

return sub.compare(".r") == 0 ||
sub.compare(".referer") == 0 ||
sub.compare(".referrer") == 0;
return is_referrer(sub);
}

static bool normalize_referer_urlspec(string& url_spec, bool& is_negative)
static boost::optional<ACLGrant> referrer_to_grant(std::string url_spec,
const uint32_t perm)
{
/* This function takes url_spec as non-ref std::string because of the trim
* operation that is essential to preserve compliance with Swift. It can't
* be easily accomplished with boost::string_ref. */
try {
bool is_negative;
ACLGrant grant;

if ('-' == url_spec[0]) {
is_negative = true;
url_spec = url_spec.substr(1);
boost::algorithm::trim(url_spec);

is_negative = true;
} else {
is_negative = false;
}
if (url_spec != "*" && '*' == url_spec[0]) {
url_spec = url_spec.substr(1);

/* We're specially handling the .r:* as the S3 API has a similar concept
* and thus we can have a small portion of compatibility here. */
if (url_spec == "*") {
grant.set_group(ACL_GROUP_ALL_USERS, is_negative ? 0 : perm);
} else {
if ('*' == url_spec[0]) {
url_spec = url_spec.substr(1);
boost::algorithm::trim(url_spec);
}

if (url_spec.empty() || url_spec == ".") {
return boost::none;
}

grant.set_referer(url_spec, is_negative ? 0 : perm);
}

return !url_spec.empty() && url_spec != ".";
return grant;
} catch (std::out_of_range) {
return false;
return boost::none;
}
}

void RGWAccessControlPolicy_SWIFT::add_grants(RGWRados * const store,
const std::vector<std::string>& uids,
const uint32_t perm)
static ACLGrant user_to_grant(CephContext* const cct,
RGWRados* const store,
const std::string& uid,
const uint32_t perm)
{
for (const auto& uid : uids) {
ldout(cct, 20) << "trying to add grant for ACL uid=" << uid << dendl;
ACLGrant grant;
string url_spec;
rgw_user user(uid);
RGWUserInfo grant_user;
ACLGrant grant;

if (rgw_get_user_info_by_uid(store, user, grant_user) < 0) {
ldout(cct, 10) << "grant user does not exist: " << uid << dendl;
/* skipping silently */
grant.set_canon(user, std::string(), perm);
} else {
grant.set_canon(user, grant_user.display_name, perm);
}

if (uid_is_public(uid)) {
grant.set_group(ACL_GROUP_ALL_USERS, perm);
acl.add_grant(&grant);
} else if (extract_referer_urlspec(uid, url_spec)) {
if (0 != (perm & SWIFT_PERM_WRITE)) {
ldout(cct, 10) << "cannot grant write access for referers" << dendl;
continue;
}
return grant;
}

bool is_negative = false;
if (false == normalize_referer_urlspec(url_spec, is_negative)) {
ldout(cct, 10) << "cannot normalize referer: " << url_spec << dendl;
continue;
} else {
ldout(cct, 10) << "normalized referer to url_spec=" << url_spec
<< ", is_negative=" << is_negative << dendl;
}
int RGWAccessControlPolicy_SWIFT::add_grants(RGWRados* const store,
const std::vector<std::string>& uids,
const uint32_t perm)
{
for (const auto& uid : uids) {
boost::optional<ACLGrant> grant;
ldout(cct, 20) << "trying to add grant for ACL uid=" << uid << dendl;

if (is_negative) {
/* Forbid access. */
grant.set_referer(url_spec, 0);
} else {
grant.set_referer(url_spec, perm);
/* Let's check whether the item has a separator potentially indicating
* a special meaning (like an HTTP referral-based grant). */
const size_t pos = uid.find(':');
if (std::string::npos == pos) {
/* No, it don't have -- we've got just a regular user identifier. */
grant = user_to_grant(cct, store, uid, perm);
} else {
/* Yes, *potentially* an HTTP referral. */
auto designator = uid.substr(0, pos);
auto designatee = uid.substr(pos + 1);

/* Swift strips whitespaces at both beginning and end. */
boost::algorithm::trim(designator);
boost::algorithm::trim(designatee);

if (! boost::algorithm::starts_with(designator, ".")) {
grant = user_to_grant(cct, store, uid, perm);
} else if ((perm & SWIFT_PERM_WRITE) == 0 && is_referrer(designator)) {
/* HTTP referrer-based ACLs aren't acceptable for writes. */
grant = referrer_to_grant(designatee, perm);
}
}

acl.add_grant(&grant);
if (grant) {
acl.add_grant(&*grant);
} else {
rgw_user user(uid);
RGWUserInfo grant_user;

if (rgw_get_user_info_by_uid(store, user, grant_user) < 0) {
ldout(cct, 10) << "grant user does not exist: " << uid << dendl;
/* skipping silently */
grant.set_canon(user, std::string(), perm);
acl.add_grant(&grant);
} else {
grant.set_canon(user, grant_user.display_name, perm);
acl.add_grant(&grant);
}
return -EINVAL;
}
}

return 0;
}

bool RGWAccessControlPolicy_SWIFT::create(RGWRados * const store,
const rgw_user& id,
const std::string& name,
const std::string& read_list,
const std::string& write_list)

int RGWAccessControlPolicy_SWIFT::create(RGWRados* const store,
const rgw_user& id,
const std::string& name,
const std::string& read_list,
const std::string& write_list)
{
acl.create_default(id, name);
owner.set_id(id);
Expand All @@ -164,23 +189,35 @@ bool RGWAccessControlPolicy_SWIFT::create(RGWRados * const store,
std::vector<std::string> uids;
int r = parse_list(read_list, uids);
if (r < 0) {
ldout(cct, 0) << "ERROR: parse_list returned r=" << r << dendl;
return false;
ldout(cct, 0) << "ERROR: parse_list for read returned r="
<< r << dendl;
return r;
}

add_grants(store, uids, SWIFT_PERM_READ);
r = add_grants(store, uids, SWIFT_PERM_READ);
if (r < 0) {
ldout(cct, 0) << "ERROR: add_grants for read returned r="
<< r << dendl;
return r;
}
}
if (write_list.size()) {
std::vector<std::string> uids;
int r = parse_list(write_list, uids);
if (r < 0) {
ldout(cct, 0) << "ERROR: parse_list returned r=" << r << dendl;
return false;
ldout(cct, 0) << "ERROR: parse_list for write returned r="
<< r << dendl;
return r;
}

add_grants(store, uids, SWIFT_PERM_WRITE);
r = add_grants(store, uids, SWIFT_PERM_WRITE);
if (r < 0) {
ldout(cct, 0) << "ERROR: add_grants for write returned r="
<< r << dendl;
return r;
}
}
return true;
return 0;
}

void RGWAccessControlPolicy_SWIFT::to_str(string& read, string& write)
Expand Down
21 changes: 11 additions & 10 deletions src/rgw/rgw_acl_swift.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@

class RGWAccessControlPolicy_SWIFT : public RGWAccessControlPolicy
{
int add_grants(RGWRados *store,
const std::vector<std::string>& uids,
uint32_t perm);

public:
explicit RGWAccessControlPolicy_SWIFT(CephContext * const cct)
explicit RGWAccessControlPolicy_SWIFT(CephContext* const cct)
: RGWAccessControlPolicy(cct) {
}
~RGWAccessControlPolicy_SWIFT() {}
~RGWAccessControlPolicy_SWIFT() = default;

void add_grants(RGWRados *store,
const std::vector<std::string>& uids,
uint32_t perm);
bool create(RGWRados *store,
const rgw_user& id,
const std::string& name,
const std::string& read_list,
const std::string& write_list);
int create(RGWRados *store,
const rgw_user& id,
const std::string& name,
const std::string& read_list,
const std::string& write_list);
void to_str(std::string& read, std::string& write);
};

Expand Down
14 changes: 7 additions & 7 deletions src/rgw/rgw_rest_swift.cc
Original file line number Diff line number Diff line change
Expand Up @@ -520,13 +520,13 @@ static int get_swift_container_settings(req_state * const s,

if (read_attr || write_attr) {
RGWAccessControlPolicy_SWIFT swift_policy(s->cct);
const bool r = swift_policy.create(store,
s->user->user_id,
s->user->display_name,
read_list,
write_list);
if (r != true) {
return -EINVAL;
const auto r = swift_policy.create(store,
s->user->user_id,
s->user->display_name,
read_list,
write_list);
if (r < 0) {
return r;
}

*policy = swift_policy;
Expand Down

0 comments on commit 1ed342d

Please sign in to comment.