Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rgw: respect Swift's negative, HTTP referer-based ACL grants. #14344

Merged
merged 2 commits into from Jun 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 20 additions & 15 deletions src/rgw/rgw_acl.cc
Expand Up @@ -24,6 +24,12 @@ void RGWAccessControlList::_add_grant(ACLGrant *grant)
switch (type.get_type()) {
case ACL_TYPE_REFERER:
referer_list.emplace_back(grant->get_referer(), perm.get_permissions());

/* We're specially handling the Swift's .r:* as the S3 API has a similar
* concept and thus we can have a small portion of compatibility here. */
if (grant->get_referer() == RGW_REFERER_WILDCARD) {
acl_group_map[ACL_GROUP_ALL_USERS] |= perm.get_permissions();
}
break;
case ACL_TYPE_GROUP:
acl_group_map[grant->get_group()] |= perm.get_permissions();
Expand Down Expand Up @@ -71,27 +77,26 @@ uint32_t RGWAccessControlList::get_group_perm(ACLGroupTypeEnum group,
return 0;
}

uint32_t RGWAccessControlList::get_referer_perm(const std::string http_referer,
uint32_t RGWAccessControlList::get_referer_perm(const uint32_t current_perm,
const std::string http_referer,
const uint32_t perm_mask)
{
ldout(cct, 5) << "Searching permissions for referer=" << http_referer
<< " mask=" << perm_mask << dendl;

/* FIXME: C++11 doesn't have std::rbegin nor std::rend. We would like to
* switch when C++14 becomes available. */
const auto iter = std::find_if(referer_list.crbegin(), referer_list.crend(),
[&http_referer](const ACLReferer& r) -> bool {
return r.is_match(http_referer);
/* This function is bacically a transformation from current perm to
* a new one that takes into consideration the Swift's HTTP referer-
* based ACLs. We need to go through all items to respect negative
* grants. */
uint32_t referer_perm = current_perm;
for (const auto& r : referer_list) {
Copy link
Contributor

@Jing-Scott Jing-Scott Apr 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a question that if set .r:-.exmple.com,.r:*.example.com on container read acl, the www.example.com have the access in SWIFT and in this change without finding from the rear of referer_list, is it worked as expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The case of .r:-.example.com,.r:*.example.com:

  • RadosGW:
rgw$ curl -i "${publicURL}/cont" -X POST -H "X-Auth-Token: ${token}"  -H "X-Container-Read: .r:-.example.com,.r:*.example.com"
HTTP/1.1 204 No Content
X-Trans-Id: tx00000000000000000000b-0058e644b2-1024-default
Content-Type: text/plain; charset=utf-8
Date: Thu, 06 Apr 2017 13:37:54 GMT

rgw$ curl -i "${publicURL}/cont/aaa10" -X GET -H "Referer: https://www.example.com"
HTTP/1.1 200 OK
Content-Length: 3
Accept-Ranges: bytes
Last-Modified: Thu, 06 Apr 2017 13:37:03 GMT
X-Timestamp: 1491485823.30361
etag: 202cb962ac59075b964b07152d234b70
X-Trans-Id: tx00000000000000000000c-0058e64512-1024-default
Content-Type: application/x-www-form-urlencoded
Date: Thu, 06 Apr 2017 13:39:30 GMT

123
  • Swift:
swift$ curl -i "${publicURL}/cont" -X POST -H "X-Auth-Token: ${token}"  -H "X-Container-Read: .r:-.example.com,.r:*.example.com"
HTTP/1.1 204 No Content
Content-Length: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txb9790199c6684ab9931f6-0058e64524
Date: Thu, 06 Apr 2017 13:39:48 GMT

swift$ curl -i "${publicURL}/cont/aaa10" -X GET -H "Referer: https://www.example.com"
HTTP/1.1 200 OK
Content-Length: 3
Accept-Ranges: bytes
Last-Modified: Wed, 25 Jan 2017 18:50:32 GMT
Etag: 202cb962ac59075b964b07152d234b70
X-Timestamp: 1485370231.32458
Content-Type: application/x-www-form-urlencoded
X-Trans-Id: txfe59ab709d004f5ca6acf-0058e6452e
Date: Thu, 06 Apr 2017 13:39:58 GMT

123

The case of .r:-.exmple.com,.r:*.example.com (original, without a in the first item):

  • RadosGW:
rgw$ curl -i "${publicURL}/cont" -X POST -H "X-Auth-Token: ${token}"  -H "X-Container-Read: .r:-.exmple.com,.r:*.example.com"
HTTP/1.1 204 No Content
X-Trans-Id: tx00000000000000000000d-0058e6460e-1024-default
Content-Type: text/plain; charset=utf-8
Date: Thu, 06 Apr 2017 13:43:42 GMT

rgw$ curl -i "${publicURL}/cont/aaa10" -X GET -H "Referer: https://www.example.com"
HTTP/1.1 200 OK
Content-Length: 3
Accept-Ranges: bytes
Last-Modified: Thu, 06 Apr 2017 13:37:03 GMT
X-Timestamp: 1491485823.30361
etag: 202cb962ac59075b964b07152d234b70
X-Trans-Id: tx00000000000000000000e-0058e64616-1024-default
Content-Type: application/x-www-form-urlencoded
Date: Thu, 06 Apr 2017 13:43:50 GMT

123
  • Swift:
swift$ curl -i "${publicURL}/cont" -X POST -H "X-Auth-Token: ${token}"  -H "X-Container-Read: .r:-.exmple.com,.r:*.example.com"
HTTP/1.1 204 No Content
Content-Length: 0
Content-Type: text/html; charset=UTF-8
X-Trans-Id: txf89be419de33481191fea-0058e64637
Date: Thu, 06 Apr 2017 13:44:23 GMT

swift$ curl -i "${publicURL}/cont/aaa10" -X GET -H "Referer: https://www.example.com"
HTTP/1.1 200 OK
Content-Length: 3
Accept-Ranges: bytes
Last-Modified: Wed, 25 Jan 2017 18:50:32 GMT
Etag: 202cb962ac59075b964b07152d234b70
X-Timestamp: 1485370231.32458
Content-Type: application/x-www-form-urlencoded
X-Trans-Id: tx3ea6d1f8b6fe4e4fbdbfd-0058e6463a
Date: Thu, 06 Apr 2017 13:44:26 GMT

123

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, this is a typo. i've lost a. :-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, thanks!

if (r.is_match(http_referer)) {
referer_perm = r.perm;
}
);

if (referer_list.crend() == iter) {
ldout(cct, 5) << "Permissions for referer not found" << dendl;
return 0;
} else {
ldout(cct, 5) << "Found referer permission=" << iter->perm << dendl;
return iter->perm & perm_mask;
}

ldout(cct, 5) << "Found referer permission=" << referer_perm << dendl;
return referer_perm & perm_mask;
}

uint32_t RGWAccessControlPolicy::get_perm(const rgw::auth::Identity& auth_identity,
Expand Down Expand Up @@ -123,7 +128,7 @@ uint32_t RGWAccessControlPolicy::get_perm(const rgw::auth::Identity& auth_identi

/* Should we continue looking up even deeper? */
if (nullptr != http_referer && (perm & perm_mask) != perm_mask) {
perm |= acl.get_referer_perm(http_referer, perm_mask);
perm = acl.get_referer_perm(perm, http_referer, perm_mask);
}

ldout(cct, 5) << "-- Getting permissions done for identity=" << auth_identity
Expand Down
10 changes: 9 additions & 1 deletion src/rgw/rgw_acl.h
Expand Up @@ -29,6 +29,8 @@ using namespace std;
#define RGW_PERM_ALL_S3 RGW_PERM_FULL_CONTROL
#define RGW_PERM_INVALID 0xFF00

static constexpr char RGW_REFERER_WILDCARD[] = "*";

enum ACLGranteeTypeEnum {
/* numbers are encoded, should not change */
ACL_TYPE_CANON_USER = 0,
Expand Down Expand Up @@ -223,6 +225,10 @@ struct ACLReferer {
return false;
}

if ("*" == url_spec) {
return true;
}

if (http_host->compare(url_spec) == 0) {
return true;
}
Expand Down Expand Up @@ -302,7 +308,9 @@ class RGWAccessControlList
uint32_t get_perm(const rgw::auth::Identity& auth_identity,
uint32_t perm_mask);
uint32_t get_group_perm(ACLGroupTypeEnum group, uint32_t perm_mask);
uint32_t get_referer_perm(const std::string http_referer, uint32_t perm_mask);
uint32_t get_referer_perm(uint32_t current_perm,
std::string http_referer,
uint32_t perm_mask);
void encode(bufferlist& bl) const {
ENCODE_START(4, 3, bl);
bool maps_initialized = true;
Expand Down
13 changes: 6 additions & 7 deletions src/rgw/rgw_acl_swift.cc
Expand Up @@ -90,11 +90,7 @@ static boost::optional<ACLGrant> referrer_to_grant(std::string url_spec,
is_negative = false;
}

/* 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 != RGW_REFERER_WILDCARD) {
if ('*' == url_spec[0]) {
url_spec = url_spec.substr(1);
boost::algorithm::trim(url_spec);
Expand All @@ -103,10 +99,13 @@ static boost::optional<ACLGrant> referrer_to_grant(std::string url_spec,
if (url_spec.empty() || url_spec == ".") {
return boost::none;
}

grant.set_referer(url_spec, is_negative ? 0 : perm);
} else {
/* Please be aware we're specially handling the .r:* in _add_grant()
* of RGWAccessControlList as the S3 API has a similar concept, and
* thus we can have a small portion of compatibility. */
}

grant.set_referer(url_spec, is_negative ? 0 : perm);
return grant;
} catch (std::out_of_range) {
return boost::none;
Expand Down