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]
