From e5c6fa5f1e4f210d311581bc0baae437c170b516 Mon Sep 17 00:00:00 2001 From: Douglas Fuller Date: Mon, 9 Oct 2017 15:18:43 -0400 Subject: [PATCH] OSD/OSDCap: Namespace globbing Permit the wildcard * at the end of namespace names to match any namespace starting with the given prefix. The wildcard is only allowed at the end of the namespace name. Example: allow rw namespace=foo* Signed-off-by: Douglas Fuller --- doc/man/8/ceph-authtool.rst | 3 ++- doc/rados/operations/user-management.rst | 5 +++++ src/osd/OSD.cc | 4 +++- src/osd/OSDCap.cc | 10 +++++++++- src/test/osd/osdcap.cc | 22 ++++++++++++++++++++++ 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/doc/man/8/ceph-authtool.rst b/doc/man/8/ceph-authtool.rst index f3e406b1ec279..a3e719e29b002 100644 --- a/doc/man/8/ceph-authtool.rst +++ b/doc/man/8/ceph-authtool.rst @@ -140,7 +140,8 @@ In general, an osd capability follows the grammar:: osdcap := grant[,grant...] grant := allow (match capspec | capspec match) match := [pool[=] | object_prefix - | tag = ] + | tag = + | namespace[=] ] capspec := * | [r][w][x] [class-read] [class-write] The capspec determines what kind of operations the entity can perform:: diff --git a/doc/rados/operations/user-management.rst b/doc/rados/operations/user-management.rst index aac6ef0c7149a..33b58c02252af 100644 --- a/doc/rados/operations/user-management.rst +++ b/doc/rados/operations/user-management.rst @@ -248,6 +248,11 @@ namespace to the object name with out the computational overhead of a separate pool. Rather than creating a separate pool for a user or set of users, you may use a namespace. **Note:** Only available using ``librados`` at this time. +Access may be restricted to specific RADOS namespaces using the ``namespace`` +capability. Limited globbing of namespaces is supported; if the last character +of the specified namespace is ``*``, then access is granted to any namespace +starting with the provided argument. + Managing Users ============== diff --git a/src/osd/OSD.cc b/src/osd/OSD.cc index 5603e675caa33..d868c2c2ee5c7 100644 --- a/src/osd/OSD.cc +++ b/src/osd/OSD.cc @@ -6701,11 +6701,13 @@ bool OSD::ms_verify_authorizer(Connection *con, int peer_type, catch (buffer::error& e) { isvalid = false; } - bool success = s->caps.parse(str); + stringstream ss; + bool success = s->caps.parse(str, &ss); if (success) dout(10) << " session " << s << " " << s->entity_name << " has caps " << s->caps << " '" << str << "'" << dendl; else { dout(10) << " session " << s << " " << s->entity_name << " failed to parse caps '" << str << "'" << dendl; + dout(20) << "parser returned " << ss.str() << dendl; isvalid = false; } } diff --git a/src/osd/OSDCap.cc b/src/osd/OSDCap.cc index fd0857336b108..e0d028d177042 100644 --- a/src/osd/OSDCap.cc +++ b/src/osd/OSDCap.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include "OSDCap.h" #include "common/config.h" @@ -109,6 +110,11 @@ bool OSDCapPoolNamespace::is_match(const std::string& pn, } } if (nspace) { + if ((*nspace)[nspace->length() - 1] == '*' && + boost::starts_with(ns, nspace->substr(0, nspace->length() - 1))) { + return true; + } + if (*nspace != ns) { return false; } @@ -388,7 +394,9 @@ struct OSDCapParser : qi::grammar spaces = +ascii::space; pool_name %= -(spaces >> lit("pool") >> (lit('=') | spaces) >> str); - nspace %= (spaces >> lit("namespace") >> (lit('=') | spaces) >> estr); + nspace %= (spaces >> lit("namespace") + >> (lit('=') | spaces) + >> estr >> -char_('*')); // match := [pool[=] [namespace[=]] | auid <123>] [object_prefix ] auid %= (spaces >> lit("auid") >> spaces >> int_); diff --git a/src/test/osd/osdcap.cc b/src/test/osd/osdcap.cc index dd5ea7accbff1..2fae9e3cf1d9a 100644 --- a/src/test/osd/osdcap.cc +++ b/src/test/osd/osdcap.cc @@ -68,6 +68,7 @@ const char *parse_good[] = { "allow pool foo namespace=nfoo rwx ; allow pool bar namespace=nbar r", "allow pool foo namespace nfoo rwx ;allow pool bar namespace nbar r", "allow pool foo namespace=nfoo rwx; allow pool bar namespace nbar object_prefix rbd r", + "allow pool foo namespace=nfoo* rwx", "allow pool foo namespace=\"\" rwx; allow pool bar namespace='' object_prefix rbd r", "allow pool foo namespace \"\" rwx; allow pool bar namespace '' object_prefix rbd r", "profile abc, profile abc pool=bar, profile abc pool=bar namespace=foo", @@ -108,6 +109,7 @@ const char *parse_bad[] = { "allow rwx namespace", "allow namespace", "allow namespace=foo", + "allow namespace=f*oo", "allow rwx auid 123 namespace asdf", "allow wwx pool ''", "allow rwx tag application key value", @@ -278,6 +280,26 @@ TEST(OSDCap, ObjectPoolAndPrefix) { ASSERT_FALSE(cap.is_capable("baz", "", 0, {}, "fo", true, true, {{"cls", true, true, true}})); } +TEST(OSDCap, Namespace) { + OSDCap cap; + ASSERT_TRUE(cap.parse("allow rw namespace=nfoo")); + + ASSERT_TRUE(cap.is_capable("bar", "nfoo", 0, {}, "foo", true, true, {})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", true, true, {})); + ASSERT_FALSE(cap.is_capable("bar", "nfoobar", 0, {}, "foo", true, true, {})); +} + +TEST(OSDCap, NamespaceGlob) { + OSDCap cap; + ASSERT_TRUE(cap.parse("allow rw namespace=nfoo*")); + + ASSERT_TRUE(cap.is_capable("bar", "nfoo", 0, {}, "foo", true, true, {})); + ASSERT_TRUE(cap.is_capable("bar", "nfoobar", 0, {}, "foo", true, true, {})); + + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", true, true, {})); + ASSERT_FALSE(cap.is_capable("bar", "nfo", 0, {}, "foo", true, true, {})); +} + TEST(OSDCap, BasicR) { OSDCap cap; ASSERT_TRUE(cap.parse("allow r", NULL)); -- 2.39.5