Repository: qpid-dispatch
Updated Branches:
  refs/heads/crolke-DISPATCH-188-1 db3e34c8d -> 04c9040f1


Retrieve settings from python
Count connection denials due to user policy.
Add disconnect test.


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

Branch: refs/heads/crolke-DISPATCH-188-1
Commit: 04c9040f1fbaaa3d3c37dea69bf3cf2e0b912688
Parents: db3e34c
Author: Chuck Rolke <[email protected]>
Authored: Fri Feb 12 12:08:34 2016 -0500
Committer: Chuck Rolke <[email protected]>
Committed: Fri Feb 12 12:08:34 2016 -0500

----------------------------------------------------------------------
 .../policy/policy_local.py                      | 19 ++++---
 .../policy/policy_manager.py                    | 14 +++--
 .../policy/policy_util.py                       |  7 +++
 src/policy.c                                    | 56 ++++++++++++++++++--
 tests/router_policy_test.py                     | 11 ++++
 5 files changed, 91 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/04c9040f/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 ef3d2e4..82854a8 100644
--- a/python/qpid_dispatch_internal/policy/policy_local.py
+++ b/python/qpid_dispatch_internal/policy/policy_local.py
@@ -396,6 +396,10 @@ class AppStats(object):
 
     def disconnect(self, conn_id, user, host):
         self.conn_mgr.disconnect(conn_id, user, host)
+
+    def count_other_denial(self):
+        self.conn_mgr.count_other_denial()
+
 #
 #
 class ConnectionFacts:
@@ -438,9 +442,7 @@ class PolicyLocal(object):
 
         # statsdb is a map
         #  key : <application name>
-        #  val : a map
-        #   key : stat name
-        #   val : stat value
+        #  val : AppStats object
         self.statsdb = {}
 
         # _policy_compiler is a function
@@ -554,6 +556,7 @@ class PolicyLocal(object):
                     self._manager.log_trace(
                         "lookup_user failed for user '%s', host '%s', 
application '%s': "
                         "User must be in a user group" % (user, host, app))
+                    stats.count_other_denial()
                     return ""
             # User in usergroup allowed to connect from host?
             if usergroup in ruleset[PolicyKeys.KW_CONNECTION_INGRESS_POLICIES]:
@@ -576,6 +579,7 @@ class PolicyLocal(object):
                 self._manager.log_trace(
                     "lookup_user failed for user '%s', host '%s', application 
'%s': "
                     "User is not allowed to connect from this host" % (user, 
host, app))
+                stats.count_other_denial()
                 return ""
 
             # This user passes administrative approval.
@@ -608,16 +612,15 @@ class PolicyLocal(object):
         @param[in] name: user group name
         @param[out] upolicy: dict holding policy values - the settings blob
                     TODO: make this a c struct
-        @return if allowed by policy
+        @return if lookup worked
         # Note: the upolicy output is a non-nested dict with settings of 
interest
-        # TODO: figure out decent defaults for upolicy settings that are 
undefined
         """
         try:
             if not appname in self.rulesetdb:
                 self._manager.log_trace(
                         "lookup_settings fail for application '%s', user group 
'%s': "
                         "No policy defined for this application" % (appname, 
name))
-                return ""
+                return False
 
             ruleset = self.rulesetdb[appname]
 
@@ -625,14 +628,14 @@ class PolicyLocal(object):
                 self._manager.log_trace(
                         "lookup_settings fail for application '%s', user group 
'%s': "
                         "This application has no settings for the user group" 
% (appname, name))
-                return ""
+                return False
 
             upolicy.update(ruleset[PolicyKeys.KW_SETTINGS][name])
             return True
         except Exception, e:
             #print str(e)
             #pdb.set_trace()
-            return ""
+            return False
 
     def close_connection(self, conn_id):
         """

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/04c9040f/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 20ac54c..2d48d58 100644
--- a/python/qpid_dispatch_internal/policy/policy_manager.py
+++ b/python/qpid_dispatch_internal/policy/policy_manager.py
@@ -100,10 +100,8 @@ class PolicyManager(object):
         Given a settings name, return the aggregated policy blob.
         @param[in] appname: application user is accessing
         @param[in] name: user group name
-        @param[out] upolicy: dict holding policy values - the settings blob
-                    TODO: make this a c struct
-        @return if allowed by policy
-        # Note: the upolicy output is a non-nested dict with settings of 
interest
+        @param[out] upolicy: map that receives the settings
+        @return settings were retrieved or not
         """
         return self._policy_local.lookup_settings(appname, name, upolicy)
 
@@ -142,4 +140,10 @@ def policy_close_connection(mgr, conn_id):
     @param conn_id:
     @return:
     """
-    mgr.close_connection(conn_id)
\ No newline at end of file
+    mgr.close_connection(conn_id)
+
+#
+#
+#
+def policy_lookup_settings(mgr, appname, name, upolicy):
+    return mgr.lookup_settings(appname, name, upolicy)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/04c9040f/python/qpid_dispatch_internal/policy/policy_util.py
----------------------------------------------------------------------
diff --git a/python/qpid_dispatch_internal/policy/policy_util.py 
b/python/qpid_dispatch_internal/policy/policy_util.py
index 000b638..71a42be 100644
--- a/python/qpid_dispatch_internal/policy/policy_util.py
+++ b/python/qpid_dispatch_internal/policy/policy_util.py
@@ -329,3 +329,10 @@ class PolicyAppConnectionMgr(object):
         self.per_user_state[user].remove(conn_id)
         self.per_host_state[host].remove(conn_id)
 
+
+    def count_other_denial(self):
+        """
+        Record the statistic for a connection denied by some other process
+        @return:
+        """
+        self.connections_denied += 1
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/04c9040f/src/policy.c
----------------------------------------------------------------------
diff --git a/src/policy.c b/src/policy.c
index 045ab33..53e46ef 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -226,6 +226,19 @@ void qd_policy_socket_close(void *context, const 
qd_connection_t *conn)
 }
 
 
+int _pyGetInt(PyObject *dict, const char *key)
+{
+    PyObject *pkey = PyString_FromString(key);
+    PyObject *val = PyObject_GetItem(dict, pkey);
+    long res = 0;
+    if (val) {
+        res = PyInt_AsLong(val);
+    }
+    Py_XDECREF(pkey);
+    Py_XDECREF(val);
+    return (int)res;
+}
+
 //
 // Functions related to authenticated connection denial.
 // An AMQP Open has been received over some connection.
@@ -253,17 +266,20 @@ bool qd_policy_open_lookup_user(
     const char *conn_name,
     char       *name_buf,
     int         name_buf_size,
-    uint64_t    conn_id)
+    uint64_t    conn_id,
+    qd_policy_settings_t *settings)
 {
+    memset(settings, 0, sizeof(*settings));
+    // Lookup the user/host/app for allow/deny and to get settings name
     qd_python_lock_state_t lock_state = qd_python_lock();
     PyObject *module = 
PyImport_ImportModule("qpid_dispatch_internal.policy.policy_manager");
     PyObject *lookup_user = module ? PyObject_GetAttrString(module, 
"policy_lookup_user") : NULL;
-    Py_XDECREF(module);
     PyObject *result = lookup_user ? PyObject_CallFunction(lookup_user, 
"(OssssK)", 
                                                            (PyObject 
*)policy->py_policy_manager, 
                                                            username, hostip, 
app, conn_name, conn_id) : NULL;
     Py_XDECREF(lookup_user);
     if (!result) {
+        Py_XDECREF(module);
         qd_python_unlock(lock_state);
         return false;
     }
@@ -271,6 +287,31 @@ bool qd_policy_open_lookup_user(
     strncpy(name_buf, res_string, name_buf_size);
     Py_XDECREF(result);
 
+    if (name_buf[0]) {
+        // Go get the settings
+        PyObject *upolicy = PyDict_New();
+        PyObject *lookup_settings = module ? PyObject_GetAttrString(module, 
"policy_lookup_settings") : NULL;
+        PyObject *result2 = lookup_settings ? 
PyObject_CallFunction(lookup_settings, "(OssO)", 
+                                                            (PyObject 
*)policy->py_policy_manager, 
+                                                            app, name_buf, 
upolicy) : NULL;
+        Py_XDECREF(lookup_settings);
+        if (!result2) {
+            Py_XDECREF(upolicy);
+            qd_python_unlock(lock_state);
+            return false;
+        }
+        Py_XDECREF(result2);
+        settings->maxFrameSize     = _pyGetInt(upolicy, "maxFrameSize");
+        settings->maxMessageSize   = _pyGetInt(upolicy, "maxMessageSize");
+        settings->maxSessionWindow = _pyGetInt(upolicy, "maxSessionWindow");
+        settings->maxSessions      = _pyGetInt(upolicy, "maxSessions");
+        settings->maxSenders       = _pyGetInt(upolicy, "maxSenders");
+        settings->maxReceivers     = _pyGetInt(upolicy, "maxReceivers");
+        settings->allowAnonymousSender = false; // TODO:
+        settings->allowDynamicSrc      = false; // TODO:
+        Py_XDECREF(upolicy);
+    }
+    Py_XDECREF(module);
     qd_python_unlock(lock_state);
 
     qd_log(policy->log_source, 
@@ -318,11 +359,20 @@ void qd_policy_amqp_open(void *context, bool discard)
 #define SETTINGS_NAME_SIZE 256
         char settings_name[SETTINGS_NAME_SIZE];
         uint32_t conn_id = qd_conn->connection_id;
+        qd_policy_settings_t settings;
 
         if (!policy->enableAccessRules ||
-            (qd_policy_open_lookup_user(policy, username, hostip, app, 
conn_name, settings_name, SETTINGS_NAME_SIZE, conn_id) &&
+            (qd_policy_open_lookup_user(policy, username, hostip, app, 
conn_name, 
+                                        settings_name, SETTINGS_NAME_SIZE, 
conn_id,
+                                        &settings) &&
              settings_name[0])) {
             // This connection is allowed.
+            // Apply received settings
+            if (settings.maxFrameSize > 0)
+                pn_transport_set_max_frame(pn_trans, settings.maxFrameSize);
+            if (settings.maxSessions > 0)
+                pn_transport_set_channel_max(pn_trans, settings.maxSessions);
+            // TODO: set the rest...
             if (pn_connection_state(conn) & PN_LOCAL_UNINIT)
                 pn_connection_open(conn);
             qd_connection_manager_connection_opened(qd_conn);

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/04c9040f/tests/router_policy_test.py
----------------------------------------------------------------------
diff --git a/tests/router_policy_test.py b/tests/router_policy_test.py
index 9da56eb..4125d80 100644
--- a/tests/router_policy_test.py
+++ b/tests/router_policy_test.py
@@ -238,6 +238,17 @@ class PolicyAppConnectionMgrTests(TestCase):
         stats.update(3, 2, 2)
         self.assertTrue(stats.can_connect('10.10.10.10:10001', 'chuck', 
'10.10.10.10', diags))
 
+    def test_policy_app_conn_mgr_disconnect(self):
+        stats = PolicyAppConnectionMgr(3, 1, 2)
+        diags = []
+        self.assertTrue(stats.can_connect('10.10.10.10:10000', 'chuck', 
'10.10.10.10', diags))
+        self.assertFalse(stats.can_connect('10.10.10.10:10001', 'chuck', 
'10.10.10.10', diags))
+        self.assertTrue(len(diags) == 1)
+        self.assertTrue('per user' in diags[0])
+        diags = []
+        stats.disconnect("10.10.10.10:10000", 'chuck', '10.10.10.10')
+        self.assertTrue(stats.can_connect('10.10.10.10:10001', 'chuck', 
'10.10.10.10', diags))
+
     def test_policy_app_conn_mgr_create_bad_settings(self):
         denied = False
         try:


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to