From: Jason Dillaman Date: Thu, 4 Jan 2018 21:52:00 +0000 (-0500) Subject: osd: caps now support whitelisting execution of class methods X-Git-Tag: v13.0.2~615^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=8ced644ccfd96c7d6fc5def0dc1e16eb3d705d1c;p=ceph-ci.git osd: caps now support whitelisting execution of class methods Signed-off-by: Jason Dillaman --- diff --git a/src/osd/OSDCap.cc b/src/osd/OSDCap.cc index 3ab02878921..cd1b747d692 100644 --- a/src/osd/OSDCap.cc +++ b/src/osd/OSDCap.cc @@ -49,8 +49,12 @@ ostream& operator<<(ostream& out, const OSDCapSpec& s) { if (s.allow) return out << s.allow; - if (s.class_name.length()) - return out << "class '" << s.class_name << "' '" << s.class_allow << "'"; + if (s.class_name.length()) { + out << "class '" << s.class_name << "'"; + if (!s.method_name.empty()) { + out << " '" << s.method_name << "'"; + } + } return out; } @@ -271,9 +275,11 @@ bool OSDCapGrant::is_capable(const string& pool_name, const string& ns, // compare this grant to each class in the operation for (size_t i = 0; i < classes.size(); ++i) { - // check 'allow class foo' + // check 'allow class foo [method_name]' if (!spec.class_name.empty() && - classes[i].class_name == spec.class_name) { + classes[i].class_name == spec.class_name && + (spec.method_name.empty() || + classes[i].method_name == spec.method_name)) { (*class_allowed)[i] = true; continue; } @@ -434,12 +440,12 @@ struct OSDCapParser : qi::grammar ( (spaces >> lit("class-read")[_val |= OSD_CAP_CLS_R]) || (spaces >> lit("class-write")[_val |= OSD_CAP_CLS_W]) )); - // capspec := * | rwx | class [classcap] + // capspec := * | rwx | class [] class_name %= (spaces >> lit("class") >> spaces >> str); - class_cap %= -(spaces >> str); + method_name %= -(spaces >> str); capspec = ( - (rwxa) [_val = phoenix::construct(_1)] | - (class_name >> class_cap) [_val = phoenix::construct(_1, _2)]); + (rwxa) [_val = phoenix::construct(_1)] | + (class_name >> method_name) [_val = phoenix::construct(_1, _2)]); // profile := profile [pool[=] [namespace[=]]] profile_name %= (lit("profile") >> (lit('=') | spaces) >> str); @@ -465,7 +471,7 @@ struct OSDCapParser : qi::grammar qi::rule wildcard; qi::rule auid; qi::rule class_name; - qi::rule class_cap; + qi::rule method_name; qi::rule capspec; qi::rule pool_name; qi::rule nspace; diff --git a/src/osd/OSDCap.h b/src/osd/OSDCap.h index 59b8392f67e..eeb3835aa14 100644 --- a/src/osd/OSDCap.h +++ b/src/osd/OSDCap.h @@ -64,13 +64,13 @@ ostream& operator<<(ostream& out, const osd_rwxa_t& p); struct OSDCapSpec { osd_rwxa_t allow; std::string class_name; - std::string class_allow; + std::string method_name; OSDCapSpec() : allow(0) {} explicit OSDCapSpec(osd_rwxa_t v) : allow(v) {} - explicit OSDCapSpec(std::string n) : allow(0), class_name(std::move(n)) {} - OSDCapSpec(std::string n, std::string a) : - allow(0), class_name(std::move(n)), class_allow(std::move(a)) {} + OSDCapSpec(std::string class_name, std::string method_name) + : allow(0), class_name(std::move(class_name)), + method_name(std::move(method_name)) {} bool allow_all() const { return allow == OSD_CAP_ANY; diff --git a/src/test/osd/osdcap.cc b/src/test/osd/osdcap.cc index 5b6ccd4a92c..2a06eb4702e 100644 --- a/src/test/osd/osdcap.cc +++ b/src/test/osd/osdcap.cc @@ -947,6 +947,33 @@ TEST(OSDCap, AllowClass) { ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, true, false}})); } +TEST(OSDCap, AllowClassMethod) { + OSDCap cap; + ASSERT_TRUE(cap.parse("allow class foo xyz", NULL)); + + // can call the xyz method on class foo regardless of whitelist status + ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", true, false, true}})); + ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", false, true, true}})); + ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", true, true, true}})); + ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", true, false, false}})); + ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", false, true, false}})); + ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", true, true, false}})); + + // does not permit invoking class bar + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, false, true}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", false, true, true}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, true, true}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, false, false}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", false, true, false}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, true, false}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", true, false, true}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", false, true, true}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", true, true, true}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", true, false, false}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", false, true, false}})); + ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", true, true, false}})); +} + TEST(OSDCap, AllowClass2) { OSDCap cap; ASSERT_TRUE(cap.parse("allow class foo, allow class bar", NULL));