Repository: qpid-dispatch Updated Branches: refs/heads/crolke-DISPATCH-188-1 2766ff113 -> 8f7deddf4
Add policy lookup function to return settings for (user, host, app) access. Add self tests to exercise the lookup using the example policy file. Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/8f7deddf Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/8f7deddf Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/8f7deddf Branch: refs/heads/crolke-DISPATCH-188-1 Commit: 8f7deddf406c63cefb47310abec88c4ae6e207d9 Parents: 2766ff1 Author: Chuck Rolke <[email protected]> Authored: Thu Dec 10 12:17:25 2015 -0500 Committer: Chuck Rolke <[email protected]> Committed: Thu Dec 10 12:17:25 2015 -0500 ---------------------------------------------------------------------- .../qpid_dispatch_internal/management/policy.py | 175 ++++++++++++++++++- tests/system_tests_policy.py | 58 ++++++ 2 files changed, 232 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/8f7deddf/python/qpid_dispatch_internal/management/policy.py ---------------------------------------------------------------------- diff --git a/python/qpid_dispatch_internal/management/policy.py b/python/qpid_dispatch_internal/management/policy.py index 74a3b0d..6cadb1d 100644 --- a/python/qpid_dispatch_internal/management/policy.py +++ b/python/qpid_dispatch_internal/management/policy.py @@ -647,7 +647,168 @@ class Policy(): # # Runtime query interface # - + def policy_aggregate_limits(self, upolicy, policy, settingname): + """ + Force a max count value into user policy + param[in,out] upolicy user policy receiving aggregations + param[in] policy Internal policy holding settings to be aggregated + param[in] settingname setting of interest + """ + if settingname in policy: + upolicy[settingname] = policy[settingname] + + def policy_aggregate_policy_int(self, upolicy, policy, roles, settingname): + """ + Pull int out of policy.policies[role] and install into upolicy if > existing + param[in,out] upolicy user policy receiving aggregations + param[in] policy Internal policy holding settings to be aggregated + param[in] settingname setting of interest + """ + if not 'policies' in policy: + return + policies = policy['policies'] + for role in roles: + if role in policies: + rpol = policies[role] + if settingname in rpol: + sp = rpol[settingname] + if settingname in upolicy: + up = upolicy[settingname] + if sp > up: + # policy bumps up user setting + upolicy[settingname] = sp + else: + # user policy is already better + pass + else: + # user policy doesn't have setting so force it + upolicy[settingname] = sp + else: + # no setting of this name in the role's policy + pass + else: + # no policy for this role + pass + + def policy_aggregate_policy_bool(self, upolicy, policy, roles, settingname): + """ + Pull bool out of policy and install into upolicy if true + param[in,out] upolicy user policy receiving aggregations + param[in] policy Internal policy holding settings to be aggregated + param[in] settingname setting of interest + """ + if not 'policies' in policy: + return + policies = policy['policies'] + for role in roles: + if role in policies: + rpol = policies[role] + if settingname in rpol: + if rpol[settingname]: + upolicy[settingname] = True + else: + # no setting of this name in the role's policy + pass + else: + # no policy for this role + pass + + def policy_aggregate_policy_list(self, upolicy, policy, roles, settingname): + """ + Pull list out of policy and append into upolicy + param[in,out] upolicy user policy receiving aggregations + param[in] policy Internal policy holding settings to be aggregated + param[in] settingname setting of interest + """ + if not 'policies' in policy: + return + policies = policy['policies'] + for role in roles: + if role in policies: + rpol = policies[role] + if settingname in rpol: + sp = rpol[settingname] + if settingname in upolicy: + upolicy[settingname].extend( sp ) + else: + # user policy doesn't have setting so force it + upolicy[settingname] = sp + else: + # no setting of this name in the role's policy + pass + else: + # no policy for this role + pass + + def policy_lookup(self, user, host, app, upolicy): + """ + Determine if a user on host accessing app is allowed. + @param[in] user connection authId + @param[in] host connection remote host numeric IP address + @param[in] app application user is accessing + @param[out] upolicy dict holding connection and policy values + @return if allowed by policy + # TODO: use lookaside list for precomputed (user, host, app) policy + # 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: + settings = self.data[app] + # User allowed to connect from host? + allowed = False + restricted = False + uhs = HostStruct(host) + uroles = [] + if 'roles' in settings: + for r in settings['roles']: + if user in settings['roles'][r]: + restricted = True + uroles.append(r) + #print "XXX user %s has roles %s " % (user, uroles) + uorigins = [] + if 'connectionPolicy' in settings: + for ur in uroles: + if ur in settings['connectionPolicy']: + uorigins.extend(settings['connectionPolicy'][ur]) + #print "XXX user %s has origins %s" % (user, uorigins) + if 'connectionOrigins' in settings: + for co in settings['connectionOrigins']: + if co in uorigins: + for cohost in settings['connectionOrigins'][co]: + if cohost.match_bin(uhs): + #print "XXX user %s passes origin test at %s" % (user, uhs.dump()) + allowed = True + break + if allowed: + break + if not allowed and not restricted: + if 'connectionAllowUnrestricted' in settings: + allowed = settings['connectionAllowUnrestricted'] + if not allowed: + return False + # Return connection limits and aggregation of role settings + uroles.append(user) # user roles also includes username directly + self.policy_aggregate_limits (upolicy, settings, "policyVersion") + self.policy_aggregate_limits (upolicy, settings, "maximumConnections") + self.policy_aggregate_limits (upolicy, settings, "maximumConnectionsPerUser") + self.policy_aggregate_limits (upolicy, settings, "maximumConnectionsPerHost") + self.policy_aggregate_policy_int (upolicy, settings, uroles, "max_frame_size") + self.policy_aggregate_policy_int (upolicy, settings, uroles, "max_message_size") + self.policy_aggregate_policy_int (upolicy, settings, uroles, "max_session_window") + self.policy_aggregate_policy_int (upolicy, settings, uroles, "max_sessions") + self.policy_aggregate_policy_int (upolicy, settings, uroles, "max_senders") + self.policy_aggregate_policy_int (upolicy, settings, uroles, "max_receivers") + self.policy_aggregate_policy_bool(upolicy, settings, uroles, "allow_dynamic_src") + self.policy_aggregate_policy_bool(upolicy, settings, uroles, "allow_anonymous_sender") + self.policy_aggregate_policy_list(upolicy, settings, uroles, "sources") + self.policy_aggregate_policy_list(upolicy, settings, uroles, "targets") + return True + except Exception, e: + #print str(e) + #pdb.set_trace() + return False + + # # HACK ALERT: Temporary # Functions related to main @@ -679,6 +840,18 @@ def main_except(argv): p = ("%s" % policy.policy_read(pname)) print(p.replace('\\n', '\n')) + # Lookups + upolicy = {} + res = policy.policy_lookup('zeke', '192.168.100.5', 'photoserver', upolicy) + print "Lookup zeke from 192.168.100.5. Expect true and max_frame_size 44444. Result is %s" % res + print "Resulting policy is: %s" % upolicy + + upolicy = {} + res = policy.policy_lookup('ellen', '72.135.2.9', 'photoserver', upolicy) + print "Lookup ellen from 72.135.2.9. Expect true and max_frame_size 666666. Result is %s" % res + print "Resulting policy is: %s" % upolicy + + def main(argv): try: main_except(argv) http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/8f7deddf/tests/system_tests_policy.py ---------------------------------------------------------------------- diff --git a/tests/system_tests_policy.py b/tests/system_tests_policy.py index 1661d22..e61e380 100644 --- a/tests/system_tests_policy.py +++ b/tests/system_tests_policy.py @@ -158,5 +158,63 @@ class PolicyHostAddrTest(TestCase): self.expect_deny( "::1,::2,::3", "arg count") self.expect_deny( "0:ff:0,0:fe:ffff:ffff::0", "a > b") +class PolicyFile(TestCase): + + policy = Policy("../../../tests/policy-1") + + def dict_compare(self, d1, d2): + d1_keys = set(d1.keys()) + d2_keys = set(d2.keys()) + intersect_keys = d1_keys.intersection(d2_keys) + added = d1_keys - d2_keys + removed = d2_keys - d1_keys + modified = {o : (d1[o], d2[o]) for o in intersect_keys if d1[o] != d2[o]} + same = set(o for o in intersect_keys if d1[o] == d2[o]) + return len(added) == 0 and len(removed) == 0 and len(modified) == 0 + + def test_policy1_test_zeke_ok(self): + upolicy = {} + self.assertTrue( + PolicyFile.policy.policy_lookup('zeke', '192.168.100.5', 'photoserver', upolicy) ) + self.assertTrue(upolicy['policyVersion'] == '1') + self.assertTrue(upolicy['maximumConnections'] == '10') + self.assertTrue(upolicy['maximumConnectionsPerUser'] == '5') + self.assertTrue(upolicy['maximumConnectionsPerHost'] == '5') + self.assertTrue(upolicy['max_frame_size'] == 444444) + self.assertTrue(upolicy['max_message_size'] == 444444) + self.assertTrue(upolicy['max_session_window'] == 444444) + self.assertTrue(upolicy['max_sessions'] == 4) + self.assertTrue(upolicy['max_senders'] == 44) + self.assertTrue(upolicy['max_receivers'] == 44) + self.assertTrue(upolicy['allow_anonymous_sender']) + self.assertTrue(upolicy['allow_dynamic_src']) + self.assertTrue(len(upolicy['targets']) == 1) + self.assertTrue('private' in upolicy['targets']) + self.assertTrue(len(upolicy['sources']) == 1) + self.assertTrue('private' in upolicy['sources']) + + def test_policy1_test_zeke_bad_IP(self): + upolicy = {} + self.assertFalse( + PolicyFile.policy.policy_lookup('zeke', '10.18.0.1', 'photoserver', upolicy) ) + self.assertFalse( + PolicyFile.policy.policy_lookup('zeke', '72.135.2.9', 'photoserver', upolicy) ) + self.assertFalse( + PolicyFile.policy.policy_lookup('zeke', '127.0.0.1', 'photoserver', upolicy) ) + + def test_policy1_test_zeke_bad_app(self): + upolicy = {} + self.assertFalse( + PolicyFile.policy.policy_lookup('zeke', '192.168.100.5','galleria', upolicy) ) + + def test_policy1_test_users_same_permissions(self): + zpolicy = {} + self.assertTrue( + PolicyFile.policy.policy_lookup('zeke', '192.168.100.5', 'photoserver', zpolicy) ) + ypolicy = {} + self.assertTrue( + PolicyFile.policy.policy_lookup('ynot', '10.48.255.254', 'photoserver', ypolicy) ) + self.assertTrue( self.dict_compare(zpolicy, ypolicy) ) + if __name__ == '__main__': unittest.main(main_module()) --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
