]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: Add the ability to set capabilities on namespaces
authorDavid Zafman <david.zafman@inktank.com>
Fri, 28 Jun 2013 22:45:27 +0000 (15:45 -0700)
committerDavid Zafman <david.zafman@inktank.com>
Tue, 9 Jul 2013 21:09:25 +0000 (14:09 -0700)
Parse namespace spec in osd caps and use in is_match()
Add test cases to unit test

feature: #4983 (OSD: namespaces pt 2 (caps))

Signed-off-by: David Zafman <david.zafman@inktank.com>
src/osd/OSDCap.cc
src/osd/OSDCap.h
src/osd/PG.cc
src/test/osd/osdcap.cc

index 268b06d75254dfa827f3a21aa4d95ee78a5f13b3..ee77f0ea43d0ea0b44c05ec45bb56441b2133f3c 100644 (file)
@@ -64,10 +64,18 @@ ostream& operator<<(ostream& out, const OSDCapMatch& m)
   if (m.pool_name.length()) {
     out << "pool " << m.pool_name << " ";
   }
+  if (m.is_nspace) {
+    out << "namespace ";
+    if (m.nspace.length() == 0)
+      out << "\"\"";
+    else
+      out << m.nspace;
+    out << " ";
+  }
   return out;
 }
 
-bool OSDCapMatch::is_match(const string& pn, int64_t pool_auid, const string& object) const
+bool OSDCapMatch::is_match(const string& pn, const string& ns, int64_t pool_auid, const string& object) const
 {
   if (auid >= 0) {
     if (auid != pool_auid)
@@ -77,6 +85,10 @@ bool OSDCapMatch::is_match(const string& pn, int64_t pool_auid, const string& ob
     if (pool_name != pn)
       return false;
   }
+  if (is_nspace) {
+    if (nspace != ns)
+      return false;
+  }
   if (object_prefix.length()) {
     if (object.find(object_prefix) != 0)
       return false;
@@ -90,6 +102,8 @@ bool OSDCapMatch::is_match_all() const
     return false;
   if (pool_name.length())
     return false;
+  if (is_nspace)
+    return false;
   if (object_prefix.length())
     return false;
   return true;
@@ -115,7 +129,7 @@ void OSDCap::set_allow_all()
   grants.push_back(OSDCapGrant(OSDCapMatch(), OSDCapSpec(OSD_CAP_ANY)));
 }
 
-bool OSDCap::is_capable(const string& pool_name, int64_t pool_auid,
+bool OSDCap::is_capable(const string& pool_name, const string& ns, int64_t pool_auid,
                        const string& object, bool op_may_read,
                        bool op_may_write, bool op_may_class_read,
                        bool op_may_class_write) const
@@ -123,7 +137,7 @@ bool OSDCap::is_capable(const string& pool_name, int64_t pool_auid,
   osd_rwxa_t allow = 0;
   for (vector<OSDCapGrant>::const_iterator p = grants.begin();
        p != grants.end(); ++p) {
-    if (p->match.is_match(pool_name, pool_auid, object)) {
+    if (p->match.is_match(pool_name, ns, pool_auid, object)) {
       allow = allow | p->spec.allow;
       if ((op_may_read && !(allow & OSD_CAP_R)) ||
          (op_may_write && !(allow & OSD_CAP_W)) ||
@@ -161,18 +175,24 @@ struct OSDCapParser : qi::grammar<Iterator, OSDCap()>
     quoted_string %=
       lexeme['"' >> +(char_ - '"') >> '"'] | 
       lexeme['\'' >> +(char_ - '\'') >> '\''];
+    equoted_string %=
+      lexeme['"' >> *(char_ - '"') >> '"'] |
+      lexeme['\'' >> *(char_ - '\'') >> '\''];
     unquoted_word %= +char_("a-zA-Z0-9_-");
     str %= quoted_string | unquoted_word;
+    estr %= equoted_string | unquoted_word;
 
     spaces = +lit(' ');
 
-    // match := [pool[=]<poolname> | auid <123>] [object_prefix <prefix>]
+    // match := [pool[=]<poolname> [namespace[=]<namespace>] | auid <123>] [object_prefix <prefix>]
     pool_name %= -(spaces >> lit("pool") >> (lit('=') | spaces) >> str);
+    nspace %= (spaces >> lit("namespace") >> (lit('=') | spaces) >> estr);
     auid %= (spaces >> lit("auid") >> spaces >> int_);
     object_prefix %= -(spaces >> lit("object_prefix") >> spaces >> str);
 
     match = ( (auid >> object_prefix)                 [_val = phoenix::construct<OSDCapMatch>(_1, _2)] |
-             (pool_name >> object_prefix)            [_val = phoenix::construct<OSDCapMatch>(_1, _2)]);
+             (pool_name >> nspace >> object_prefix)   [_val = phoenix::construct<OSDCapMatch>(_1, _2, _3)] |
+             (pool_name >> object_prefix)             [_val = phoenix::construct<OSDCapMatch>(_1, _2)]);
 
     // rwxa := * | [r][w][x] [class-read] [class-write]
     rwxa =
@@ -203,12 +223,13 @@ struct OSDCapParser : qi::grammar<Iterator, OSDCap()>
   }
   qi::rule<Iterator> spaces;
   qi::rule<Iterator, unsigned()> rwxa;
-  qi::rule<Iterator, string()> quoted_string;
+  qi::rule<Iterator, string()> quoted_string, equoted_string;
   qi::rule<Iterator, string()> unquoted_word;
-  qi::rule<Iterator, string()> str;
+  qi::rule<Iterator, string()> str, estr;
   qi::rule<Iterator, int()> auid;
   qi::rule<Iterator, OSDCapSpec()> capspec;
   qi::rule<Iterator, string()> pool_name;
+  qi::rule<Iterator, string()> nspace;
   qi::rule<Iterator, string()> object_prefix;
   qi::rule<Iterator, OSDCapMatch()> match;
   qi::rule<Iterator, OSDCapGrant()> grant;
index 9b2ac8865ae2be37ff56d1dd5b3d3666423bcb88..3fc7fb67953cfeb9150c509bddfacedda3759ef3 100644 (file)
@@ -73,26 +73,32 @@ ostream& operator<<(ostream& out, const OSDCapSpec& s);
 
 
 struct OSDCapMatch {
-  // auid and pool_name are mutually exclusive
+  // auid and pool_name/nspace are mutually exclusive
   int64_t auid;
   std::string pool_name;
+  bool is_nspace;      // true if nspace is defined; false if not constrained.
+  std::string nspace;
 
   std::string object_prefix;
 
-  OSDCapMatch() : auid(CEPH_AUTH_UID_DEFAULT) {}
-  OSDCapMatch(std::string pl, std::string pre) : auid(CEPH_AUTH_UID_DEFAULT), pool_name(pl), object_prefix(pre) {}
-  OSDCapMatch(uint64_t auid, std::string pre) : auid(auid), object_prefix(pre) {}
+  OSDCapMatch() : auid(CEPH_AUTH_UID_DEFAULT), is_nspace(false) {}
+  OSDCapMatch(std::string pl, std::string pre) :
+       auid(CEPH_AUTH_UID_DEFAULT), pool_name(pl), is_nspace(false), object_prefix(pre) {}
+  OSDCapMatch(std::string pl, std::string ns, std::string pre) :
+       auid(CEPH_AUTH_UID_DEFAULT), pool_name(pl), is_nspace(true), nspace(ns), object_prefix(pre) {}
+  OSDCapMatch(uint64_t auid, std::string pre) : auid(auid), is_nspace(false), object_prefix(pre) {}
 
   /**
    * check if given request parameters match our constraints
    *
    * @param auid requesting user's auid
    * @param pool_name pool name
+   * @param nspace_name namespace name
    * @param pool_auid pool's auid
    * @param object object name
    * @return true if we match, false otherwise
    */
-  bool is_match(const std::string& pool_name, int64_t pool_auid, const std::string& object) const;
+  bool is_match(const std::string& pool_name, const std::string& nspace_name, int64_t pool_auid, const std::string& object) const;
   bool is_match_all() const;
 };
 
@@ -128,6 +134,7 @@ struct OSDCap {
    * against pool, pool auid, and object name prefix.
    *
    * @param pool_name name of the pool we are accessing
+   * @param ns name of the namespace we are accessing
    * @param pool_auid owner of the pool we are accessing
    * @param object name of the object we are accessing
    * @param op_may_read whether the operation may need to read
@@ -138,7 +145,7 @@ struct OSDCap {
    *                          write class method
    * @return true if the operation is allowed, false otherwise
    */
-  bool is_capable(const string& pool_name, int64_t pool_auid,
+  bool is_capable(const string& pool_name, const string& ns, int64_t pool_auid,
                  const string& object, bool op_may_read, bool op_may_write,
                  bool op_may_class_read, bool op_may_class_write) const;
 };
index d925ff2472075316192495c245a3b36624d98333..e47a4d6212222ae481923c8326a57d5a97b842c6 100644 (file)
@@ -1337,13 +1337,15 @@ bool PG::op_has_sufficient_caps(OpRequestRef op)
   if (key.length() == 0)
     key = req->get_oid().name;
 
-  bool cap = caps.is_capable(pool.name, pool.auid, key,
+  bool cap = caps.is_capable(pool.name, req->get_object_locator().nspace,
+                             pool.auid, key,
                             op->need_read_cap(),
                             op->need_write_cap(),
                             op->need_class_read_cap(),
                             op->need_class_write_cap());
 
   dout(20) << "op_has_sufficient_caps pool=" << pool.id << " (" << pool.name
+                  << " " << req->get_object_locator().nspace
           << ") owner=" << pool.auid
           << " need_read_cap=" << op->need_read_cap()
           << " need_write_cap=" << op->need_write_cap()
index a26a843057ef04098332762e2873108346cfa2d8..5f7c607deec47c208db06f846901087436241362 100644 (file)
@@ -62,6 +62,12 @@ const char *parse_good[] = {
   "allow r   pool    foo    object_prefix   blah   ;   allow   w   auid  5",
   "allow class-read object_prefix rbd_children, allow pool libvirt-pool-test rwx",
   "allow class-read object_prefix rbd-children, allow pool libvirt_pool_test rwx",
+  "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 r",
+  "allow pool foo namespace=nfoo rwx; allow pool bar namespace nbar object_prefix rbd r",
+  "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",
   0
 };
 
@@ -89,6 +95,13 @@ const char *parse_bad[] = {
   "allow xrwx pool foo,, allow r pool bar",
   ";allow rwx pool foo rwx ; allow r pool bar",
   "allow rwx pool foo ;allow r pool bar gibberish",
+  "allow rwx auid 123 pool asdf namespace=foo",
+  "allow rwx auid 123 namespace",
+  "allow rwx namespace",
+  "allow namespace",
+  "allow namespace=foo",
+  "allow rwx auid 123 namespace asdf",
+  "allow wwx pool ''",
   0
 };
 
@@ -135,7 +148,10 @@ TEST(OSDCap, AllowAll) {
 
   ASSERT_TRUE(cap.parse("allow *", NULL));
   ASSERT_TRUE(cap.allow_all());
-  ASSERT_TRUE(cap.is_capable("foo", 0, "asdf", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "asdf", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "anamespace", 0, "asdf", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "asdf", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "anamespace", 0, "asdf", true, true, true, true));
 }
 
 TEST(OSDCap, AllowPool) {
@@ -143,8 +159,10 @@ TEST(OSDCap, AllowPool) {
   bool r = cap.parse("allow rwx pool foo", NULL);
   ASSERT_TRUE(r);
 
-  ASSERT_TRUE(cap.is_capable("foo", 0, "", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "", true, true, true, true));
 }
 
 TEST(OSDCap, AllowPools) {
@@ -152,10 +170,14 @@ TEST(OSDCap, AllowPools) {
   bool r = cap.parse("allow rwx pool foo, allow r pool bar", NULL);
   ASSERT_TRUE(r);
 
-  ASSERT_TRUE(cap.is_capable("foo", 0, "", true, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "", true, false, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "ns", 0, "", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("baz", "ns", 0, "", true, false, false, false));
 }
 
 TEST(OSDCap, AllowPools2) {
@@ -163,9 +185,9 @@ TEST(OSDCap, AllowPools2) {
   bool r = cap.parse("allow r, allow rwx pool foo", NULL);
   ASSERT_TRUE(r);
 
-  ASSERT_TRUE(cap.is_capable("foo", 0, "", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "", true, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "", true, false, false, false));
 }
 
 TEST(OSDCap, ObjectPrefix) {
@@ -173,13 +195,13 @@ TEST(OSDCap, ObjectPrefix) {
   bool r = cap.parse("allow rwx object_prefix foo", NULL);
   ASSERT_TRUE(r);
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "food", true, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo_bar", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "food", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo_bar", true, true, true, true));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "_foo", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, " foo ", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "fo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "_foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, " foo ", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "fo", true, true, true, true));
 }
 
 TEST(OSDCap, ObjectPoolAndPrefix) {
@@ -187,203 +209,324 @@ TEST(OSDCap, ObjectPoolAndPrefix) {
   bool r = cap.parse("allow rwx pool bar object_prefix foo", NULL);
   ASSERT_TRUE(r);
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "food", true, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo_bar", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "food", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo_bar", true, true, true, true));
 
-  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "food", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "fo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "food", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "fo", true, true, true, true));
 }
 
 TEST(OSDCap, BasicR) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow r", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, true, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false));
 }
 
 TEST(OSDCap, BasicW) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow w", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, true, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false));
 }
 
 TEST(OSDCap, BasicX) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow x", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, false, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false));
 }
 
 TEST(OSDCap, BasicRW) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow rw", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, false, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, false, false));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, true, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
 }
 
 TEST(OSDCap, BasicRX) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow rx", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, false, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, true));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false));
 }
 
 TEST(OSDCap, BasicWX) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow wx", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, false, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, false, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, true, true));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false));
 }
 
 TEST(OSDCap, BasicRWX) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow rwx", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, false, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, false, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, false));
 }
 
 TEST(OSDCap, BasicRWClassRClassW) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow rw class-read class-write", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, false, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, false, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, false));
 }
 
 TEST(OSDCap, ClassR) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow class-read", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, false, false, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, false, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
 }
 
 TEST(OSDCap, ClassW) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow class-write", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, true));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, false, true, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
 }
 
 TEST(OSDCap, ClassRW) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow class-read class-write", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, false, true));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
 }
 
 TEST(OSDCap, BasicRClassR) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow r class-read", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
 
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false));
+
+  ASSERT_TRUE(cap.is_capable("bar", "any", 0, "foo", false, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "any", 0, "foo", true, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "any", 0, "foo", true, false, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", "any", 0, "foo", false, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "any", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "any", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "any", 0, "foo", true, true, false, false));
 }
 
 TEST(OSDCap, PoolClassR) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow pool bar r class-read, allow pool foo rwx", NULL));
 
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true, false));
-  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false, false));
-
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false, false));
-  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false, false));
-
-  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", false, false, false, false));
-  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", false, false, true, true));
-  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", true, true, true, true));
-  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", false, true, true, true));
-  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", true, false, false, true));
-  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", true, false, false, false));
-  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", true, true, false, true));
-  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", true, true, true, false));
-
-  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", false, false, false, false));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", false, false, true, true));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, true, true, true));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", false, true, true, true));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, false, false, true));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, false, false, false));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, true, false, true));
-  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, true, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false));
+
+  ASSERT_TRUE(cap.is_capable("bar", "ns", 0, "foo", false, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "ns", 0, "foo", true, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "ns", 0, "foo", true, false, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", false, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", true, true, false, false));
+
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, false, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, false, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, true, false));
+
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, false, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, false, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, true, false));
+
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, false, false, false));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, false, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, true, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, false, false, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, false, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, false));
+}
+
+TEST(OSDCap, PoolClassRNS) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow pool bar namespace='' r class-read, allow pool foo namespace=ns rwx", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, "foo", true, true, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", false, false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", true, false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", "ns", 0, "foo", true, false, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", "other", 0, "foo", false, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "other", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "other", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", "other", 0, "foo", true, true, false, false));
+
+  ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", false, false, false, false));
+  ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", false, false, true, true));
+  ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", false, true, true, true));
+  ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, false, false, true));
+  ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, true, false, true));
+  ASSERT_FALSE(cap.is_capable("foo", "", 0, "foo", true, true, true, false));
+
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, false, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", false, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, false, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", "ns", 0, "foo", true, true, true, false));
+
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, false, false, false));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, false, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", false, true, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, false, false, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, false, true));
+  ASSERT_FALSE(cap.is_capable("baz", "", 0, "foo", true, true, true, false));
+}
+
+TEST(OSDCap, NSClassR) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow namespace '' rw class-read class-write, allow namespace test r", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", false, true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, "foo", true, true, true, false));
+
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, false, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", false, true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, false, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, false, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", "", 0, "foo", true, true, true, false));
+
+  ASSERT_TRUE(cap.is_capable("bar", "test", 0, "foo", true, false, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", false, true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", true, false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", false, true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", "test", 0, "foo", true, true, false, false));
+
+  ASSERT_TRUE(cap.is_capable("foo", "test", 0, "foo", true, false, false, false));
+
+  ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", false, true, false, true));
+  ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", true, false, true, false));
+  ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", true, true, true, true));
+  ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", false, true, false, true));
+  ASSERT_FALSE(cap.is_capable("foo", "test", 0, "foo", true, true, false, false));
+
+  ASSERT_FALSE(cap.is_capable("foo", "bad", 0, "foo", true, false, false, false));
+  ASSERT_FALSE(cap.is_capable("foo", "bad", 0, "foo", false, true, false, false));
+  ASSERT_FALSE(cap.is_capable("foo", "bad", 0, "foo", false, false, true, false));
+  ASSERT_FALSE(cap.is_capable("foo", "bad", 0, "foo", false, false, false, true));
 }
 
 TEST(OSDCap, OutputParsed)
@@ -419,6 +562,14 @@ TEST(OSDCap, OutputParsed)
      "osdcap[grant(pool images w)]"},
     {"allow pool images x",
      "osdcap[grant(pool images x)]"},
+    {"allow r pool images namespace ''",
+     "osdcap[grant(pool images namespace \"\" r)]"},
+    {"allow r pool images namespace foo",
+     "osdcap[grant(pool images namespace foo r)]"},
+    {"allow r pool images namespace \"\"",
+     "osdcap[grant(pool images namespace \"\" r)]"},
+    {"allow r namespace foo",
+     "osdcap[grant(namespace foo r)]"},
     {"allow pool images r; allow pool rbd rwx",
      "osdcap[grant(pool images r),grant(pool rbd rwx)]"},
     {"allow pool images r, allow pool rbd rwx",