You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ch...@apache.org on 2016/05/11 21:21:25 UTC

qpid-dispatch git commit: DISPATCH-331: Define a default policy for when Open hostname policy is absent or is to be ignored

Repository: qpid-dispatch
Updated Branches:
  refs/heads/master 2138da722 -> 590d79ef9


DISPATCH-331: Define a default policy for when Open hostname policy is absent or is to be ignored


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/590d79ef
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/590d79ef
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/590d79ef

Branch: refs/heads/master
Commit: 590d79ef9e3472c5fc1376e52b3574eedc442fb9
Parents: 2138da7
Author: Chuck Rolke <cr...@redhat.com>
Authored: Wed May 11 17:19:23 2016 -0400
Committer: Chuck Rolke <cr...@redhat.com>
Committed: Wed May 11 17:19:23 2016 -0400

----------------------------------------------------------------------
 python/qpid_dispatch/management/qdrouter.json   | 14 ++++++
 .../qpid_dispatch_internal/management/config.py |  5 ++
 .../policy/policy_local.py                      | 51 +++++++++++++++++---
 .../policy/policy_manager.py                    | 12 +++++
 tests/router_policy_test.py                     | 44 +++++++++++++++++
 5 files changed, 118 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/590d79ef/python/qpid_dispatch/management/qdrouter.json
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch/management/qdrouter.json b/python/qpid_dispatch/management/qdrouter.json
index e977438..9eafdbf 100644
--- a/python/qpid_dispatch/management/qdrouter.json
+++ b/python/qpid_dispatch/management/qdrouter.json
@@ -1328,6 +1328,20 @@
                     "required": false,
                     "create": true
                 },
+                "defaultApplication": {
+                    "type": "string",
+                    "default": "",
+                    "description": "Application policyRuleset to use for connections with no open.hostname or a hostname that does not match any existing policy. For users that don't wish to use open.hostname or any multi-tennancy feature, this default policy can be the only policy in effect for the network.",
+                    "required": false,
+                    "create": true
+                },
+                "defaultApplicationEnabled": {
+                    "type": "boolean",
+                    "default": false,
+                    "description": "Enable defaultApplication policy fallback logic.",
+                    "required": false,
+                    "create": true
+                },
                 "connectionsProcessed": {"type": "integer", "graph": true},
                 "connectionsDenied": {"type": "integer", "graph": true},
                 "connectionsCurrent": {"type": "integer", "graph": true}

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/590d79ef/python/qpid_dispatch_internal/management/config.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/management/config.py b/python/qpid_dispatch_internal/management/config.py
index 6a5e741..c95d1f3 100644
--- a/python/qpid_dispatch_internal/management/config.py
+++ b/python/qpid_dispatch_internal/management/config.py
@@ -183,6 +183,8 @@ def configure_dispatch(dispatch, lib_handle, filename):
     from qpid_dispatch_internal.display_name.display_name import DisplayNameService
     displayname_service = DisplayNameService("$displayname")
     policyFolder = config.by_type('policy')[0]['policyFolder']
+    policyDefaultApplication = config.by_type('policy')[0]['defaultApplication']
+    policyDefaultApplicationEnabled = config.by_type('policy')[0]['defaultApplicationEnabled']
     # Remaining configuration
     for t in "fixedAddress", "listener", "connector", "waypoint", "linkRoutePattern", \
              "router.config.address", "router.config.linkRoute", "router.config.autoLink", \
@@ -207,3 +209,6 @@ def configure_dispatch(dispatch, lib_handle, filename):
                 pconfig = PolicyConfig(os.path.join(apath, i))
                 for a in pconfig.by_type("policyRuleset"):
                     agent.configure(a)
+
+    # Set policy default application after all rulesets loaded
+    agent.policy.set_default_application(policyDefaultApplication, policyDefaultApplicationEnabled)

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/590d79ef/python/qpid_dispatch_internal/policy/policy_local.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/policy/policy_local.py b/python/qpid_dispatch_internal/policy/policy_local.py
index b690c52..cb62896 100644
--- a/python/qpid_dispatch_internal/policy/policy_local.py
+++ b/python/qpid_dispatch_internal/policy/policy_local.py
@@ -486,6 +486,16 @@ class PolicyLocal(object):
         # Entries created as connection AMQP Opens arrive
         # Entries destroyed as sockets closed
         self._connections = {}
+
+        # _default_application is a string
+        #  holds the name of the policyRuleset to use when the
+        #  open.hostname is not found in the rulesetdb
+        self._default_application = ""
+
+        # _default_application_enabled is a boolean
+        #  controls default application fallback logic
+        self._default_application_enabled = False
+
     #
     # Service interfaces
     #
@@ -549,11 +559,27 @@ class PolicyLocal(object):
         """
         return self.rulesetdb.keys()
 
+    def set_default_application(self, name, enabled):
+        """
+        Set the default application name and control its enablement.
+        Raise PolicyError if the named application is enabled but absent.
+        @param name: the name of the default application
+        @param enabled: default application ruleset logic is active
+        @return: none
+        """
+        self._default_application = name
+        self._default_application_enabled = enabled
+        if enabled:
+            if not name in self.policy_db_get_names():
+                raise PolicyError("Policy fallback defaultApplication '%s' does not exist" % name)
+            self._manager.log_info("Policy fallback defaultApplication is enabled: '%s'" % name)
+        else:
+            self._manager.log_info("Policy fallback defaultApplication is disabled")
 
     #
     # Runtime query interface
     #
-    def lookup_user(self, user, host, app, conn_name, conn_id):
+    def lookup_user(self, user, host, app_in, conn_name, conn_id):
         """
         Lookup function called from C.
         Determine if a user on host accessing app through AMQP Open is allowed
@@ -562,19 +588,24 @@ class PolicyLocal(object):
         returns true then it has registered and counted the connection.
         @param[in] user connection authId
         @param[in] host connection remote host numeric IP address as string
-        @param[in] app application user is accessing
+        @param[in] app_in application user is accessing
         @param[in] conn_name connection name used for tracking reports
         @param[in] conn_id internal connection id
         @return settings user-group name if allowed; "" if not allowed
         """
         try:
-            if not app in self.rulesetdb:
-                self._manager.log_info(
-                    "DENY AMQP Open for user '%s', host '%s', application '%s': "
-                    "No policy defined for application" % (user, host, app))
-                return ""
+            app = app_in
+            if not app_in in self.rulesetdb:
+                if self._default_application_enabled:
+                    app = self._default_application
+                else:
+                    self._manager.log_info(
+                        "DENY AMQP Open for user '%s', host '%s', application '%s': "
+                        "No policy defined for application" % (user, host, app))
+                    return ""
 
             ruleset = self.rulesetdb[app]
+
             if not app in self.statsdb:
                 msg = (
                     "DENY AMQP Open for user '%s', host '%s', application '%s': "
@@ -641,7 +672,7 @@ class PolicyLocal(object):
             # return failure
             return ""
 
-    def lookup_settings(self, appname, name, upolicy):
+    def lookup_settings(self, appname_in, name, upolicy):
         """
         Given a settings name, return the aggregated policy blob.
         @param[in] appname: application user is accessing
@@ -652,6 +683,10 @@ class PolicyLocal(object):
         # Note: the upolicy output is a non-nested dict with settings of interest
         """
         try:
+            appname = appname_in
+            if not appname in self.rulesetdb and self._default_application_enabled:
+                appname = self._default_application
+
             if not appname in self.rulesetdb:
                 self._manager.log_info(
                         "lookup_settings fail for application '%s', user group '%s': "

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/590d79ef/python/qpid_dispatch_internal/policy/policy_manager.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/policy/policy_manager.py b/python/qpid_dispatch_internal/policy/policy_manager.py
index a2823c8..7cb72fb 100644
--- a/python/qpid_dispatch_internal/policy/policy_manager.py
+++ b/python/qpid_dispatch_internal/policy/policy_manager.py
@@ -78,6 +78,18 @@ class PolicyManager(object):
         self._policy_local.create_ruleset(attributes)
 
     #
+    # Management interface to set the default application
+    #
+    def set_default_application(self, name, enabled):
+        """
+        Set default application
+        @param name:
+        @param enabled
+        @return:
+        """
+        self._policy_local.set_default_application(name, enabled)
+
+    #
     # Runtime query interface
     #
     def lookup_user(self, user, host, app, conn_name, conn_id):

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/590d79ef/tests/router_policy_test.py
----------------------------------------------------------------------
diff --git a/tests/router_policy_test.py b/tests/router_policy_test.py
index 9b37567..c2359f2 100644
--- a/tests/router_policy_test.py
+++ b/tests/router_policy_test.py
@@ -190,6 +190,50 @@ class PolicyFile(TestCase):
             PolicyFile.policy.lookup_settings('photoserver', 'unknown', upolicy)
         )
 
+class PolicyFileApplicationFallback(TestCase):
+    manager = MockPolicyManager()
+    policy = PolicyLocal(manager)
+    policy.test_load_config()
+
+    def test_bad_app_fallback(self):
+        # Show that with no fallback the user cannot connect
+        self.assertTrue(
+            self.policy.lookup_user('zeke', '192.168.100.5', 'galleria', "connid", 5) == '')
+
+        # Enable the fallback defaultApplication and show the same user can now connect
+        self.policy.set_default_application('photoserver', True)
+        settingsname = self.policy.lookup_user('zeke', '192.168.100.5', 'galleria', "connid", 5)
+        self.assertTrue(settingsname == 'test')
+
+        # Show that the fallback settings are returned
+        upolicy = {}
+        self.assertTrue(
+            self.policy.lookup_settings('phony*app*name', settingsname, upolicy)
+        )
+        self.assertTrue(upolicy['maxFrameSize']            == 444444)
+        self.assertTrue(upolicy['maxMessageSize']          == 444444)
+        self.assertTrue(upolicy['maxSessionWindow']        == 444444)
+        self.assertTrue(upolicy['maxSessions']              == 4)
+        self.assertTrue(upolicy['maxSenders']               == 44)
+        self.assertTrue(upolicy['maxReceivers']             == 44)
+        self.assertTrue(upolicy['allowAnonymousSender'])
+        self.assertTrue(upolicy['allowDynamicSrc'])
+        self.assertTrue(upolicy['targets'] == 'private')
+        self.assertTrue(upolicy['sources'] == 'private')
+
+        # Disable fallback and show failure again
+        self.policy.set_default_application('', False)
+        self.assertTrue(
+            self.policy.lookup_user('zeke', '192.168.100.5', 'galleria', "connid", 5) == '')
+
+        # Configuration will not allow default application to point to bogus app ruleset
+        was_allowed = True
+        try:
+            self.policy.set_default_application('foobar', True)
+        except:
+            was_allowed = False
+        self.assertTrue(was_allowed == False)
+
 class PolicyAppConnectionMgrTests(TestCase):
 
     def test_policy_app_conn_mgr_fail_by_total(self):


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org