Author: chug Date: Wed Apr 4 19:09:31 2012 New Revision: 1309549 URL: http://svn.apache.org/viewvc?rev=1309549&view=rev Log: QPID-3918 Add management queries to ACL module. * Make queries available to self tests. * Exercise query interface during acl self tests.
Modified: qpid/trunk/qpid/cpp/src/qpid/acl/Acl.cpp qpid/trunk/qpid/cpp/src/qpid/acl/Acl.h qpid/trunk/qpid/cpp/src/qpid/acl/management-schema.xml qpid/trunk/qpid/cpp/src/qpid/broker/AclModule.h qpid/trunk/qpid/cpp/src/tests/acl.py qpid/trunk/qpid/tools/src/py/qpidtoollibs/broker.py Modified: qpid/trunk/qpid/cpp/src/qpid/acl/Acl.cpp URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpid/acl/Acl.cpp?rev=1309549&r1=1309548&r2=1309549&view=diff ============================================================================== --- qpid/trunk/qpid/cpp/src/qpid/acl/Acl.cpp (original) +++ qpid/trunk/qpid/cpp/src/qpid/acl/Acl.cpp Wed Apr 4 19:09:31 2012 @@ -26,6 +26,8 @@ #include "qpid/Options.h" #include "qpid/log/Logger.h" #include "qpid/types/Variant.h" +#include "qmf/org/apache/qpid/acl/ArgsAclLookup.h" +#include "qmf/org/apache/qpid/acl/ArgsAclLookupPublish.h" #include "qmf/org/apache/qpid/acl/Package.h" #include "qmf/org/apache/qpid/acl/EventAllow.h" #include "qmf/org/apache/qpid/acl/EventDeny.h" @@ -35,7 +37,6 @@ #include <map> #include <boost/shared_ptr.hpp> -#include <boost/utility/in_place_factory.hpp> using namespace std; using namespace qpid::acl; @@ -193,6 +194,79 @@ bool Acl::readAclFile(std::string& aclFi return true; } + +// +// management lookup function performs general query on acl engine +// +Manageable::status_t Acl::lookup(management::Args& args, std::string& text) +{ + _qmf::ArgsAclLookup& ioArgs = (_qmf::ArgsAclLookup&) args; + Manageable::status_t result(STATUS_USER); + + try { + ObjectType objType = AclHelper::getObjectType(ioArgs.i_object); + Action action = AclHelper::getAction( ioArgs.i_action); + std::map<Property, std::string> propertyMap; + for (::qpid::types::Variant::Map::const_iterator + iMapIter = ioArgs.i_propertyMap.begin(); + iMapIter != ioArgs.i_propertyMap.end(); + iMapIter++) + { + Property property = AclHelper::getProperty(iMapIter->first); + propertyMap.insert(make_pair(property, iMapIter->second)); + } + + boost::shared_ptr<AclData> dataLocal; + { + Mutex::ScopedLock locker(dataLock); + dataLocal = data; //rcu copy + } + AclResult aclResult = dataLocal->lookup( + ioArgs.i_userId, + action, + objType, + ioArgs.i_objectName, + &propertyMap); + + ioArgs.o_result = AclHelper::getAclResultStr(aclResult); + result = STATUS_OK; + + } catch (const std::exception& e) { + std::ostringstream oss; + oss << "AclLookup invalid name : " << e.what(); + ioArgs.o_result = oss.str(); + text = oss.str(); + } + + return result; +} + + +// +// management lookupPublish function performs fastpath +// PUBLISH EXCHANGE query on acl engine +// +Manageable::status_t Acl::lookupPublish(management::Args& args, std::string& /*text*/) +{ + _qmf::ArgsAclLookupPublish& ioArgs = (_qmf::ArgsAclLookupPublish&) args; + boost::shared_ptr<AclData> dataLocal; + { + Mutex::ScopedLock locker(dataLock); + dataLocal = data; //rcu copy + } + AclResult aclResult = dataLocal->lookup( + ioArgs.i_userId, + ACT_PUBLISH, + OBJ_EXCHANGE, + ioArgs.i_exchangeName, + ioArgs.i_routingKey); + + ioArgs.o_result = AclHelper::getAclResultStr(aclResult); + + return STATUS_OK; +} + + Acl::~Acl(){} ManagementObject* Acl::GetManagementObject(void) const @@ -200,7 +274,7 @@ ManagementObject* Acl::GetManagementObje return (ManagementObject*) mgmtObject; } -Manageable::status_t Acl::ManagementMethod (uint32_t methodId, Args& /*args*/, string& text) +Manageable::status_t Acl::ManagementMethod (uint32_t methodId, Args& args, string& text) { Manageable::status_t status = Manageable::STATUS_UNKNOWN_METHOD; QPID_LOG (debug, "ACL: Queue::ManagementMethod [id=" << methodId << "]"); @@ -214,6 +288,14 @@ Manageable::status_t Acl::ManagementMeth else status = Manageable::STATUS_USER; break; + + case _qmf::Acl::METHOD_LOOKUP : + status = lookup(args, text); + break; + + case _qmf::Acl::METHOD_LOOKUPPUBLISH : + status = lookupPublish(args, text); + break; } return status; Modified: qpid/trunk/qpid/cpp/src/qpid/acl/Acl.h URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpid/acl/Acl.h?rev=1309549&r1=1309548&r2=1309549&view=diff ============================================================================== --- qpid/trunk/qpid/cpp/src/qpid/acl/Acl.h (original) +++ qpid/trunk/qpid/cpp/src/qpid/acl/Acl.h Wed Apr 4 19:09:31 2012 @@ -71,8 +71,7 @@ public: const Action& action, const ObjectType& objType, const std::string& name, - std::map<Property, - std::string>* params=0); + std::map<Property, std::string>* params=0); virtual bool authorise( const std::string& id, @@ -91,6 +90,8 @@ private: const std::string& name); bool readAclFile(std::string& errorText); bool readAclFile(std::string& aclFile, std::string& errorText); + Manageable::status_t lookup (management::Args& args, std::string& text); + Manageable::status_t lookupPublish(management::Args& args, std::string& text); virtual qpid::management::ManagementObject* GetManagementObject(void) const; virtual management::Manageable::status_t ManagementMethod (uint32_t methodId, management::Args& args, std::string& text); Modified: qpid/trunk/qpid/cpp/src/qpid/acl/management-schema.xml URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpid/acl/management-schema.xml?rev=1309549&r1=1309548&r2=1309549&view=diff ============================================================================== --- qpid/trunk/qpid/cpp/src/qpid/acl/management-schema.xml (original) +++ qpid/trunk/qpid/cpp/src/qpid/acl/management-schema.xml Wed Apr 4 19:09:31 2012 @@ -25,6 +25,37 @@ <statistic name="aclDenyCount" type="count64" unit="request" desc="Number of ACL requests denied"/> <method name="reloadACLFile" desc="Reload the ACL file"/> + + <!-- + Lookup is a general object lookup + User Name + Action + Object + Object Name + Property Map consisting of <"name" "value"> string pairs. + --> + <method name="Lookup" desc="Lookup: user action object [objectName [propertyMap]]"> + <arg name="userId" dir="I" type="lstr"/> + <arg name="action" dir="I" type="lstr"/> + <arg name="object" dir="I" type="lstr"/> + <arg name="objectName" dir="I" type="lstr"/> + <arg name="propertyMap" dir="I" type="map"/> + <arg name="result" dir="O" type="lstr"/> + </method> + + <!-- + LookupPublish is a specific lookup for a PUBLISH EXCHANGE fastpath + User Name + Exchange Name + Routing Key + --> + <method name="LookupPublish" desc="Lookup PUBLISH EXCHANGE: user exchangeName routingKey"> + <arg name="userId" dir="I" type="lstr"/> + <arg name="exchangeName" dir="I" type="lstr"/> + <arg name="routingKey" dir="I" type="lstr"/> + <arg name="result" dir="O" type="lstr"/> + </method> + </class> <eventArguments> Modified: qpid/trunk/qpid/cpp/src/qpid/broker/AclModule.h URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpid/broker/AclModule.h?rev=1309549&r1=1309548&r2=1309549&view=diff ============================================================================== --- qpid/trunk/qpid/cpp/src/qpid/broker/AclModule.h (original) +++ qpid/trunk/qpid/cpp/src/qpid/broker/AclModule.h Wed Apr 4 19:09:31 2012 @@ -22,6 +22,7 @@ #include "qpid/RefCounted.h" +#include "qpid/Exception.h" #include <boost/shared_ptr.hpp> #include <map> #include <set> @@ -156,7 +157,7 @@ namespace acl { if (str.compare("broker") == 0) return OBJ_BROKER; if (str.compare("link") == 0) return OBJ_LINK; if (str.compare("method") == 0) return OBJ_METHOD; - throw str; + throw qpid::Exception(str); } static inline std::string getObjectTypeStr(const ObjectType o) { switch (o) { @@ -179,7 +180,7 @@ namespace acl { if (str.compare("delete") == 0) return ACT_DELETE; if (str.compare("purge") == 0) return ACT_PURGE; if (str.compare("update") == 0) return ACT_UPDATE; - throw str; + throw qpid::Exception(str); } static inline std::string getActionStr(const Action a) { switch (a) { @@ -212,7 +213,7 @@ namespace acl { if (str.compare("policytype") == 0) return PROP_POLICYTYPE; if (str.compare("maxqueuesize") == 0) return PROP_MAXQUEUESIZE; if (str.compare("maxqueuecount") == 0) return PROP_MAXQUEUECOUNT; - throw str; + throw qpid::Exception(str); } static inline std::string getPropertyStr(const Property p) { switch (p) { @@ -256,7 +257,7 @@ namespace acl { // Allow old names in ACL file as aliases for newly-named properties if (str.compare("maxqueuesize") == 0) return SPECPROP_MAXQUEUESIZEUPPERLIMIT; if (str.compare("maxqueuecount") == 0) return SPECPROP_MAXQUEUECOUNTUPPERLIMIT; - throw str; + throw qpid::Exception(str); } static inline std::string getPropertyStr(const SpecProperty p) { switch (p) { @@ -286,7 +287,7 @@ namespace acl { if (str.compare("allow-log") == 0) return ALLOWLOG; if (str.compare("deny") == 0) return DENY; if (str.compare("deny-log") == 0) return DENYLOG; - throw str; + throw qpid::Exception(str); } static inline std::string getAclResultStr(const AclResult r) { switch (r) { Modified: qpid/trunk/qpid/cpp/src/tests/acl.py URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/tests/acl.py?rev=1309549&r1=1309548&r2=1309549&view=diff ============================================================================== --- qpid/trunk/qpid/cpp/src/tests/acl.py (original) +++ qpid/trunk/qpid/cpp/src/tests/acl.py Wed Apr 4 19:09:31 2012 @@ -55,6 +55,24 @@ class ACLTests(TestBase010): result = str(e) return result + def acl_lookup(self, userName, action, aclObj, aclObjName, propMap): + result = {} + try: + result = self.broker_access.acl_lookup(userName, action, aclObj, aclObjName, propMap) + except Exception, e: + result['text'] = str(e) + result['result'] = str(e) + return result + + def acl_lookupPublish(self, userName, exchange, key): + result = {} + try: + result = self.broker_access.acl_lookupPublish(userName, exchange, key) + except Exception, e: + result['text'] = str(e) + result['result'] = str(e) + return result + def get_acl_file(self): return ACLFile(self.config.defines.get("policy-file", "data_dir/policy.acl")) @@ -73,6 +91,37 @@ class ACLTests(TestBase010): self.reload_acl() TestBase010.tearDown(self) + + def Lookup(self, userName, action, aclObj, aclObjName, propMap, expectedResult): + result = self.acl_lookup(userName, action, aclObj, aclObjName, propMap) + if (result['result'] != expectedResult): + suffix = ', [ERROR: Expected= ' + expectedResult + if (result['result'] is None): + suffix = suffix + ', Exception= ' + result['text'] + ']' + else: + suffix = suffix + ', Actual= ' + result['result'] + ']' + self.fail('Lookup: name=' + userName + ', action=' + action + ', aclObj=' + aclObj + ', aclObjName=' + aclObjName + ', propertyMap=' + str(propMap) + suffix) + + + def LookupPublish(self, userName, exchName, keyName, expectedResult): + result = self.acl_lookupPublish(userName, exchName, keyName) + if (result['result'] != expectedResult): + if (result['result'] is None): + suffix = suffix + ', Exception= ' + result['text'] + ']' + else: + suffix = suffix + ', Actual= ' + result['result'] + ']' + self.fail('LookupPublish: name=' + userName + ', exchange=' + exchName + ', key=' + keyName + suffix) + + def AllBut(self, allList, removeList): + tmpList = allList[:] + for item in removeList: + try: + tmpList.remove(item) + except Exception, e: + self.fail("ERROR in AllBut() \nallList = %s \nremoveList = %s \nerror = %s " \ + % (allList, removeList, e)) + return tmpList + #===================================== # ACL general tests #===================================== @@ -1278,6 +1327,151 @@ class ACLTests(TestBase010): admin.set_timestamp_cfg(ts) #should pass + + #===================================== + # QMF Functional tests + #===================================== + + def test_qmf_functional_tests(self): + """ + Test using QMF method hooks into ACL logic + """ + aclf = self.get_acl_file() + aclf.write('group admins m...@company.com \\\n') + aclf.write(' la...@company.com \\\n') + aclf.write(' cu...@company.com \\\n') + aclf.write(' sh...@company.com\n') + aclf.write('group auditors aau...@company.com bau...@company.com cau...@company.com \\\n') + aclf.write(' dau...@company.com ead...@company.com eau...@company.com\n') + aclf.write('group tatunghosts tatun...@company.com \\\n') + aclf.write(' tatung02/x86.build.company....@company.com \\\n') + aclf.write(' tatung03/x86.build.company....@company.com \\\n') + aclf.write(' tatung04/x86.build.company....@company.com \n') + aclf.write('group publishusers publ...@company.com x-p...@company.com\n') + aclf.write('acl allow-log admins all all\n') + aclf.write('# begin hack alert: allow anonymous to access the lookup debug functions\n') + aclf.write('acl allow-log anonymous create queue\n') + aclf.write('acl allow-log anonymous all exchange name=qmf.*\n') + aclf.write('acl allow-log anonymous all exchange name=amq.direct\n') + aclf.write('acl allow-log anonymous all exchange name=qpid.management\n') + aclf.write('acl allow-log anonymous access method name=*\n') + aclf.write('# end hack alert\n') + aclf.write('acl allow-log auditors all exchange name=company.topic routingkey=private.audit.*\n') + aclf.write('acl allow-log tatunghosts publish exchange name=company.topic routingkey=tatung.*\n') + aclf.write('acl allow-log tatunghosts publish exchange name=company.direct routingkey=tatung-service-queue\n') + aclf.write('acl allow-log publishusers create queue\n') + aclf.write('acl allow-log publishusers publish exchange name=qpid.management routingkey=broker\n') + aclf.write('acl allow-log publishusers publish exchange name=qmf.default.topic routingkey=*\n') + aclf.write('acl allow-log publishusers publish exchange name=qmf.default.direct routingkey=*\n') + aclf.write('acl allow-log all bind exchange name=company.topic routingkey=tatung.*\n') + aclf.write('acl allow-log all bind exchange name=company.direct routingkey=tatung-service-queue\n') + aclf.write('acl allow-log all consume queue\n') + aclf.write('acl allow-log all access exchange\n') + aclf.write('acl allow-log all access queue\n') + aclf.write('acl allow-log all create queue name=tmp.* durable=false autodelete=true exclusive=true policytype=ring\n') + aclf.write('acl allow mrQ create queue queuemaxsizelowerlimit=100 queuemaxsizeupperlimit=200 queuemaxcountlowerlimit=300 queuemaxcountupperlimit=400\n') + aclf.write('acl deny-log all all\n') + aclf.close() + + result = self.reload_acl() + if (result): + self.fail(result) + + # + # define some group lists + # + g_admins = ['m...@company.com', \ + 'la...@company.com', \ + 'cu...@company.com', \ + 'sh...@company.com'] + + g_auditors = [ 'aau...@company.com','bau...@company.com','cau...@company.com', \ + 'dau...@company.com','ead...@company.com','eau...@company.com'] + + g_tatunghosts = ['tatun...@company.com', \ + 'tatung02/x86.build.company....@company.com', \ + 'tatung03/x86.build.company....@company.com', \ + 'tatung04/x86.build.company....@company.com'] + + g_publishusers = ['publ...@company.com', 'x-p...@company.com'] + + g_public = ['jpub...@company.com', 'm...@yahoo.com'] + + g_all = g_admins + g_auditors + g_tatunghosts + g_publishusers + g_public + + action_all = ['consume','publish','create','access','bind','unbind','delete','purge','update'] + + # + # Run some tests verifying against users who are in and who are out of given groups. + # + + for u in g_admins: + self.Lookup(u, "create", "queue", "anything", {"durable":"true"}, "allow-log") + + uInTest = g_auditors + g_admins + uOutTest = self.AllBut(g_all, uInTest) + + for u in uInTest: + self.LookupPublish(u, "company.topic", "private.audit.This", "allow-log") + + for u in uInTest: + for a in action_all: + self.Lookup(u, a, "exchange", "company.topic", {"routingkey":"private.audit.This"}, "allow-log") + + for u in uOutTest: + self.LookupPublish(u, "company.topic", "private.audit.This", "deny-log") + self.Lookup(u, "bind", "exchange", "company.topic", {"routingkey":"private.audit.This"}, "deny-log") + + uInTest = g_admins + g_tatunghosts + uOutTest = self.AllBut(g_all, uInTest) + + for u in uInTest: + self.LookupPublish(u, "company.topic", "tatung.this2", "allow-log") + self.LookupPublish(u, "company.direct", "tatung-service-queue", "allow-log") + + for u in uOutTest: + self.LookupPublish(u, "company.topic", "tatung.this2", "deny-log") + self.LookupPublish(u, "company.direct", "tatung-service-queue", "deny-log") + + for u in uOutTest: + for a in ["bind", "access"]: + self.Lookup(u, a, "exchange", "company.topic", {"routingkey":"tatung.this2"}, "allow-log") + self.Lookup(u, a, "exchange", "company.direct", {"routingkey":"tatung-service-queue"}, "allow-log") + + uInTest = g_admins + g_publishusers + uOutTest = self.AllBut(g_all, uInTest) + + for u in uInTest: + self.LookupPublish(u, "qpid.management", "broker", "allow-log") + self.LookupPublish(u, "qmf.default.topic", "this3", "allow-log") + self.LookupPublish(u, "qmf.default.direct", "this4", "allow-log") + + for u in uOutTest: + self.LookupPublish(u, "qpid.management", "broker", "deny-log") + self.LookupPublish(u, "qmf.default.topic", "this3", "deny-log") + self.LookupPublish(u, "qmf.default.direct", "this4", "deny-log") + + for u in uOutTest: + for a in ["bind"]: + self.Lookup(u, a, "exchange", "qpid.management", {"routingkey":"broker"}, "deny-log") + self.Lookup(u, a, "exchange", "qmf.default.topic", {"routingkey":"this3"}, "deny-log") + self.Lookup(u, a, "exchange", "qmf.default.direct", {"routingkey":"this4"}, "deny-log") + for a in ["access"]: + self.Lookup(u, a, "exchange", "qpid.management", {"routingkey":"broker"}, "allow-log") + self.Lookup(u, a, "exchange", "qmf.default.topic", {"routingkey":"this3"}, "allow-log") + self.Lookup(u, a, "exchange", "qmf.default.direct", {"routingkey":"this4"}, "allow-log") + + # Test against queue size limits + + self.Lookup('mrQ', 'create', 'queue', 'abc', {"maxqueuesize":"150", "maxqueuecount":"350"}, "allow") + self.Lookup('mrQ', 'create', 'queue', 'def', {"maxqueuesize":"99", "maxqueuecount":"350"}, "deny") + self.Lookup('mrQ', 'create', 'queue', 'uvw', {"maxqueuesize":"201", "maxqueuecount":"350"}, "deny") + self.Lookup('mrQ', 'create', 'queue', 'xyz', {"maxqueuesize":"150", "maxqueuecount":"299"}, "deny") + self.Lookup('mrQ', 'create', 'queue', '', {"maxqueuesize":"150", "maxqueuecount":"401"}, "deny") + self.Lookup('mrQ', 'create', 'queue', '', {"maxqueuesize":"0", "maxqueuecount":"401"}, "deny") + self.Lookup('mrQ', 'create', 'queue', '', {"maxqueuesize":"150", "maxqueuecount":"0" }, "deny") + + class BrokerAdmin: def __init__(self, broker, username=None, password=None): self.connection = qpid.messaging.Connection(broker) Modified: qpid/trunk/qpid/tools/src/py/qpidtoollibs/broker.py URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/tools/src/py/qpidtoollibs/broker.py?rev=1309549&r1=1309548&r2=1309549&view=diff ============================================================================== --- qpid/trunk/qpid/tools/src/py/qpidtoollibs/broker.py (original) +++ qpid/trunk/qpid/tools/src/py/qpidtoollibs/broker.py Wed Apr 4 19:09:31 2012 @@ -268,6 +268,20 @@ class BrokerAgent(object): def reloadAclFile(self): self._method('reloadACLFile', {}, "org.apache.qpid.acl:acl:org.apache.qpid.broker:broker:amqp-broker") + def acl_lookup(self, userName, action, aclObj, aclObjName, propMap): + args = {'userId': userName, + 'action': action, + 'object': aclObj, + 'objectName': aclObjName, + 'propertyMap': propMap} + return self._method('Lookup', args, "org.apache.qpid.acl:acl:org.apache.qpid.broker:broker:amqp-broker") + + def acl_lookupPublish(self, userName, exchange, key): + args = {'userId': userName, + 'exchangeName': exchange, + 'routingKey': key} + return self._method('LookupPublish', args, "org.apache.qpid.acl:acl:org.apache.qpid.broker:broker:amqp-broker") + def create(self, _type, name, properties, strict): """Create an object of the specified type""" pass --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org