From 4b57dd91ac5400fdfd9b5a66f793492c4cf040fc Mon Sep 17 00:00:00 2001 From: "Charles E. Rolke" Date: Fri, 22 Mar 2013 14:59:38 +0000 Subject: QPID-4631: C++ Broker interbroker links protected by ACL This patch has the Acl code to observe CREATE LINK rules and the new link cration logic in the broker connection handler. Several self tests are broken by this patch and only ha_test.py has been repaired. The fix for these self tests are indicators of what customers must do to deal with this new feature. git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/qpid-4631@1459822 13f79535-47bb-0310-9956-ffa450edef68 --- qpid/cpp/src/qpid/acl/Acl.cpp | 10 ++++++++-- qpid/cpp/src/qpid/acl/Acl.h | 5 +++++ qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp | 2 +- qpid/cpp/src/qpid/acl/AclData.cpp | 2 ++ qpid/cpp/src/qpid/acl/AclData.h | 1 + qpid/cpp/src/qpid/acl/AclReader.cpp | 4 ++++ qpid/cpp/src/qpid/acl/management-schema.xml | 1 + qpid/cpp/src/qpid/broker/AclModule.h | 5 +++++ qpid/cpp/src/qpid/broker/ConnectionHandler.cpp | 20 +++++++++++++++++--- qpid/cpp/src/tests/ha_test.py | 11 +++++++++++ 10 files changed, 55 insertions(+), 6 deletions(-) diff --git a/qpid/cpp/src/qpid/acl/Acl.cpp b/qpid/cpp/src/qpid/acl/Acl.cpp index aeee42563c..bdec6791b8 100644 --- a/qpid/cpp/src/qpid/acl/Acl.cpp +++ b/qpid/cpp/src/qpid/acl/Acl.cpp @@ -53,7 +53,7 @@ using qpid::management::Manageable; using qpid::management::Args; namespace _qmf = qmf::org::apache::qpid::acl; -Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(false), +Acl::Acl (AclValues& av, Broker& b): aclValues(av), broker(&b), transferAcl(false), createlinkAcl(false), connectionCounter(new ConnectionCounter(*this, aclValues.aclMaxConnectPerUser, aclValues.aclMaxConnectPerIp, aclValues.aclMaxConnectTotal)), resourceCounter(new ResourceCounter(*this, aclValues.aclMaxQueuesPerUser)){ @@ -254,12 +254,17 @@ bool Acl::readAclFile(std::string& aclFile, std::string& errorText) { Mutex::ScopedLock locker(dataLock); data = d; } - transferAcl = data->transferAcl; // any transfer ACL + transferAcl = data->transferAcl; // any PUBLISH EXCHANGE transfer ACL + createlinkAcl = data->createlinkAcl; // any CREATE LINK ACL if (data->transferAcl){ QPID_LOG(debug,"ACL: Transfer ACL is Enabled!"); } + if (data->createlinkAcl){ + QPID_LOG(debug,"ACL: CREATE LINK ACL is Enabled!"); + } + if (data->enforcingConnectionQuotas()){ QPID_LOG(debug, "ACL: Connection quotas are Enabled."); } @@ -271,6 +276,7 @@ bool Acl::readAclFile(std::string& aclFile, std::string& errorText) { data->aclSource = aclFile; if (mgmtObject!=0){ mgmtObject->set_transferAcl(transferAcl?1:0); + mgmtObject->set_createLinkAcl(createlinkAcl?1:0); mgmtObject->set_policyFile(aclFile); sys::AbsTime now = sys::AbsTime::now(); int64_t ns = sys::Duration(sys::EPOCH, now); diff --git a/qpid/cpp/src/qpid/acl/Acl.h b/qpid/cpp/src/qpid/acl/Acl.h index ea3c6586a3..9721a60fba 100644 --- a/qpid/cpp/src/qpid/acl/Acl.h +++ b/qpid/cpp/src/qpid/acl/Acl.h @@ -61,6 +61,7 @@ private: acl::AclValues aclValues; broker::Broker* broker; bool transferAcl; + bool createlinkAcl; boost::shared_ptr data; qmf::org::apache::qpid::acl::Acl::shared_ptr mgmtObject; qpid::management::ManagementAgent* agent; @@ -81,6 +82,10 @@ public: return transferAcl; }; + inline virtual bool isCreatelinkAcl() { + return createlinkAcl; + }; + inline virtual uint16_t getMaxConnectTotal() { return aclValues.aclMaxConnectTotal; }; diff --git a/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp b/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp index 875137bf55..80a7a32790 100644 --- a/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp +++ b/qpid/cpp/src/qpid/acl/AclConnectionCounter.cpp @@ -288,7 +288,7 @@ std::string ConnectionCounter::getClientHost(const std::string mgmtId) } // no hyphen found - use whole string - assert(false); + //assert(false); return mgmtId; } diff --git a/qpid/cpp/src/qpid/acl/AclData.cpp b/qpid/cpp/src/qpid/acl/AclData.cpp index 922f65ba69..5ffd0462dc 100644 --- a/qpid/cpp/src/qpid/acl/AclData.cpp +++ b/qpid/cpp/src/qpid/acl/AclData.cpp @@ -46,6 +46,7 @@ namespace acl { AclData::AclData(): decisionMode(qpid::acl::DENY), transferAcl(false), + createlinkAcl(false), aclSource("UNKNOWN"), connQuotaRulesExist(false), connQuotaRuleSettings(new quotaRuleSet), @@ -74,6 +75,7 @@ namespace acl { delete[] actionList[cnt]; } transferAcl = false; + createlinkAcl = false; connQuotaRulesExist = false; connQuotaRuleSettings->clear(); queueQuotaRulesExist = false; diff --git a/qpid/cpp/src/qpid/acl/AclData.h b/qpid/cpp/src/qpid/acl/AclData.h index c561b95e09..ad8b741be5 100644 --- a/qpid/cpp/src/qpid/acl/AclData.h +++ b/qpid/cpp/src/qpid/acl/AclData.h @@ -118,6 +118,7 @@ public: aclAction* actionList[qpid::acl::ACTIONSIZE]; qpid::acl::AclResult decisionMode; // allow/deny[-log] if no matching rule found bool transferAcl; + bool createlinkAcl; std::string aclSource; AclResult lookup( diff --git a/qpid/cpp/src/qpid/acl/AclReader.cpp b/qpid/cpp/src/qpid/acl/AclReader.cpp index 1fd5445b52..f0974b8585 100644 --- a/qpid/cpp/src/qpid/acl/AclReader.cpp +++ b/qpid/cpp/src/qpid/acl/AclReader.cpp @@ -160,6 +160,10 @@ namespace acl { ocnt < acl::OBJECTSIZE; (*i)->objStatus != aclRule::VALUE ? ocnt++ : ocnt = acl::OBJECTSIZE) { + // Observe existance of CREATE LINK rules + if (acnt == acl::ACT_CREATE && ocnt == acl::OBJ_LINK) + d->createlinkAcl = true; + //find the Object, create if not exist if (d->actionList[acnt][ocnt] == NULL) d->actionList[acnt][ocnt] = diff --git a/qpid/cpp/src/qpid/acl/management-schema.xml b/qpid/cpp/src/qpid/acl/management-schema.xml index 2ac20bb324..e0368db96b 100644 --- a/qpid/cpp/src/qpid/acl/management-schema.xml +++ b/qpid/cpp/src/qpid/acl/management-schema.xml @@ -26,6 +26,7 @@ + diff --git a/qpid/cpp/src/qpid/broker/AclModule.h b/qpid/cpp/src/qpid/broker/AclModule.h index c01697ace9..1c138c62a8 100644 --- a/qpid/cpp/src/qpid/broker/AclModule.h +++ b/qpid/cpp/src/qpid/broker/AclModule.h @@ -132,6 +132,11 @@ namespace broker { // doTransferAcl pervents time consuming ACL calls on a per-message basis. virtual bool doTransferAcl()=0; + // Federation link creation is denied unless ACL module is loaded and + // at least one CREATE LINK rule is specified. + // This flag indicates that a CREATE LINK rule was processed. + virtual bool isCreatelinkAcl()=0; + virtual uint16_t getMaxConnectTotal()=0; virtual bool authorise( diff --git a/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp b/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp index 977c706ebd..39a8664aab 100644 --- a/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp +++ b/qpid/cpp/src/qpid/broker/ConnectionHandler.cpp @@ -201,11 +201,25 @@ void ConnectionHandler::Handler::startOk(const ConnectionStartOkBody& body) if (connection.isFederationLink()) { AclModule* acl = connection.getBroker().getAcl(); FieldTable properties; - if (acl && !acl->authorise(connection.getUserId(),acl::ACT_CREATE,acl::OBJ_LINK,"")){ + if (acl) { + if (acl->isCreatelinkAcl()) { + if (!acl->authorise(connection.getUserId(),acl::ACT_CREATE,acl::OBJ_LINK,"")){ + proxy.close(framing::connection::CLOSE_CODE_CONNECTION_FORCED, + QPID_MSG("ACL denied " << connection.getUserId() + << " creating a federation link")); + return; + } + } else { + proxy.close(framing::connection::CLOSE_CODE_CONNECTION_FORCED, + QPID_MSG("ACL denied " << connection.getUserId() + << ". Federation links require explicit CREATE LINK ACL rules")); + return; + } + } else { proxy.close(framing::connection::CLOSE_CODE_CONNECTION_FORCED, QPID_MSG("ACL denied " << connection.getUserId() - << " creating a federation link")); - return; + << ". Federation links require ACL module and explicit CREATE LINK ACL rules")); + return; } QPID_LOG(info, "Connection is a federation link"); } diff --git a/qpid/cpp/src/tests/ha_test.py b/qpid/cpp/src/tests/ha_test.py index f2ebb16ccc..5c42780f50 100755 --- a/qpid/cpp/src/tests/ha_test.py +++ b/qpid/cpp/src/tests/ha_test.py @@ -79,6 +79,17 @@ class HaBroker(Broker): if ha_replicate is not None: args += [ "--ha-replicate=%s"%ha_replicate ] if brokers_url: args += [ "--ha-brokers-url", brokers_url ] + # Set up default ACL file to allow all create link + acl=os.path.join(os.getcwd(), "unrestricted.acl") + if not os.path.exists(acl): + aclf=file(acl,"w") + aclf.write(""" +acl allow all create link +acl allow all all + """) + aclf.close() + if not "--acl-file" in args: + args += [ "--acl-file", acl, "--load-module", os.getenv("ACL_LIB") ] Broker.__init__(self, test, args, **kwargs) self.qpid_ha_path=os.path.join(os.getenv("PYTHON_COMMANDS"), "qpid-ha") assert os.path.exists(self.qpid_ha_path) -- cgit v1.2.1