summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2011-08-17 11:49:49 -0400
committerRob Crittenden <rcritten@redhat.com>2011-08-29 17:14:54 -0400
commitdcc3ceb9cba1e747e18f12bcc2a511acf0c4d671 (patch)
tree8c77df36c4256c81f255bb3dd96c5d00c40f8b65
parentd32b44be6a1dd73e514a6063cad2c8c84aaed360 (diff)
downloadfreeipa-dcc3ceb9cba1e747e18f12bcc2a511acf0c4d671.zip
freeipa-dcc3ceb9cba1e747e18f12bcc2a511acf0c4d671.tar.gz
freeipa-dcc3ceb9cba1e747e18f12bcc2a511acf0c4d671.tar.xz
Add external source hosts to HBAC.
When adding/removing source hosts if the host isn't found in IPA it is considered external. The attribute externalhost is used to store external hosts. ticket https://fedorahosted.org/freeipa/ticket/1574
-rw-r--r--ipalib/plugins/baseldap.py3
-rw-r--r--ipalib/plugins/hbacrule.py55
-rw-r--r--tests/test_xmlrpc/test_hbac_plugin.py69
3 files changed, 125 insertions, 2 deletions
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 907d975..bd4f083 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -150,6 +150,9 @@ global_output_params = (
Str('externalhost?',
label=_('External host'),
),
+ Str('sourcehost',
+ label=_('Failed source hosts/hostgroups'),
+ ),
Str('memberhost',
label=_('Failed hosts/hostgroups'),
),
diff --git a/ipalib/plugins/hbacrule.py b/ipalib/plugins/hbacrule.py
index 8368a33..b7c0bca 100644
--- a/ipalib/plugins/hbacrule.py
+++ b/ipalib/plugins/hbacrule.py
@@ -117,7 +117,7 @@ class hbacrule(LDAPObject):
'description', 'usercategory', 'hostcategory',
'sourcehostcategory', 'servicecategory', 'ipaenabledflag',
'memberuser', 'sourcehost', 'memberhost', 'memberservice',
- 'memberhostgroup',
+ 'memberhostgroup', 'externalhost',
]
uuid_attribute = 'ipauniqueid'
rdn_attribute = 'ipauniqueid'
@@ -480,6 +480,34 @@ class hbacrule_add_sourcehost(LDAPAddMember):
raise errors.MutuallyExclusiveError(reason="source hosts cannot be added when sourcehost category='all'")
return dn
+ def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ completed_external = 0
+ # Sift through the host failures. We assume that these are all
+ # hosts that aren't stored in IPA, aka external hosts.
+ if 'sourcehost' in failed and 'host' in failed['sourcehost']:
+ (dn, entry_attrs_) = ldap.get_entry(dn, ['externalhost'])
+ members = entry_attrs.get('sourcehost', [])
+ external_hosts = entry_attrs_.get('externalhost', [])
+ failed_hosts = []
+ for host in failed['sourcehost']['host']:
+ hostname = host[0].lower()
+ host_dn = self.api.Object['host'].get_dn(hostname)
+ if hostname in external_hosts:
+ failed_hosts.append((hostname, unicode(errors.AlreadyGroupMember())))
+ elif hostname not in external_hosts and host_dn not in members:
+ external_hosts.append(hostname)
+ completed_external += 1
+ else:
+ failed_hosts.append((hostname, unicode(errors.NotFound())))
+ if completed_external:
+ try:
+ ldap.update_entry(dn, {'externalhost': external_hosts})
+ except errors.EmptyModlist:
+ pass
+ entry_attrs['externalhost'] = external_hosts
+ failed['sourcehost']['host'] = failed_hosts
+ return (completed + completed_external, dn)
+
api.register(hbacrule_add_sourcehost)
@@ -489,6 +517,31 @@ class hbacrule_remove_sourcehost(LDAPRemoveMember):
member_attributes = ['sourcehost']
member_count_out = ('%i object removed.', '%i objects removed.')
+ def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ # Run through the host failures and gracefully remove any defined as
+ # as an externalhost.
+ if 'sourcehost' in failed and 'host' in failed['sourcehost']:
+ (dn, entry_attrs_) = ldap.get_entry(dn, ['externalhost'])
+ external_hosts = entry_attrs_.get('externalhost', [])
+ failed_hosts = []
+ completed_external = 0
+ for host in failed['sourcehost']['host']:
+ hostname = host[0].lower()
+ if hostname in external_hosts:
+ external_hosts.remove(hostname)
+ completed_external += 1
+ else:
+ failed_hosts.append(hostname)
+ if completed_external:
+ try:
+ ldap.update_entry(dn, {'externalhost': external_hosts})
+ except errors.EmptyModlist:
+ pass
+ failed['sourcehost']['host'] = failed_hosts
+ entry_attrs['externalhost'] = external_hosts
+ return (completed + completed_external, dn)
+
+
api.register(hbacrule_remove_sourcehost)
diff --git a/tests/test_xmlrpc/test_hbac_plugin.py b/tests/test_xmlrpc/test_hbac_plugin.py
index fc673c2..f1c8c84 100644
--- a/tests/test_xmlrpc/test_hbac_plugin.py
+++ b/tests/test_xmlrpc/test_hbac_plugin.py
@@ -46,6 +46,7 @@ class test_hbac(XMLRPC_test):
test_sourcehost = u'hbacrule._test_src_host'
test_sourcehostgroup = u'hbacrule_test_src_hostgroup'
test_service = u'sshd'
+ test_host_external = u'notfound.example.com'
def test_0_hbacrule_add(self):
"""
@@ -333,7 +334,73 @@ class test_hbac(XMLRPC_test):
assert 'sourcehost host' not in entry
assert 'sourcehost hostgroup' not in entry
- def test_c_hbacrule_clear_testing_data(self):
+ def test_c_hbacrule_add_external_host(self):
+ """
+ Test adding an external host using `xmlrpc.hbacrule_add_host`.
+ """
+ ret = api.Command['hbacrule_add_sourcehost'](
+ self.rule_name, host=self.test_host_external
+ )
+ assert ret['completed'] == 1
+ failed = ret['failed']
+ assert 'sourcehost' in failed
+ assert 'host' in failed['sourcehost']
+ assert not failed['sourcehost']['host']
+ assert 'hostgroup' in failed['sourcehost']
+ assert not failed['sourcehost']['hostgroup']
+ entry = ret['result']
+ assert_attr_equal(entry, 'externalhost', self.test_host_external)
+
+ def test_c_hbacrule_add_same_external(self):
+ """
+ Test adding the same external host using `xmlrpc.hbacrule_add_host`.
+ """
+ ret = api.Command['hbacrule_add_sourcehost'](
+ self.rule_name, host=self.test_host_external
+ )
+ assert ret['completed'] == 0
+ failed = ret['failed']
+ assert 'sourcehost' in failed
+ assert 'host' in failed['sourcehost']
+ assert (self.test_host_external, unicode(errors.AlreadyGroupMember())) in failed['sourcehost']['host']
+ entry = ret['result']
+ assert_attr_equal(entry, 'externalhost', self.test_host_external)
+
+ def test_c_hbacrule_remove_external_host(self):
+ """
+ Test removing external source host using `xmlrpc.hbacrule_remove_host`.
+ """
+ ret = api.Command['hbacrule_remove_sourcehost'](
+ self.rule_name, host=self.test_host_external
+ )
+ assert ret['completed'] == 1
+ failed = ret['failed']
+ assert 'sourcehost' in failed
+ assert 'host' in failed['sourcehost']
+ assert not failed['sourcehost']['host']
+ assert 'hostgroup' in failed['sourcehost']
+ assert not failed['sourcehost']['hostgroup']
+ entry = ret['result']
+ assert 'sourcehost host' not in entry
+ assert 'sourcehost hostgroup' not in entry
+
+ def test_c_hbacrule_remove_nonexist_external(self):
+ """
+ Test removing non-existent external source host using `xmlrpc.hbacrule_remove_host`.
+ """
+ ret = api.Command['hbacrule_remove_sourcehost'](
+ self.rule_name, host=self.test_host_external
+ )
+ assert ret['completed'] == 0
+ failed = ret['failed']
+ assert 'sourcehost' in failed
+ assert 'host' in failed['sourcehost']
+ assert (self.test_host_external, unicode(errors.NotGroupMember())) in failed['sourcehost']['host']
+ assert 'hostgroup' in failed['sourcehost']
+ assert not failed['sourcehost']['hostgroup']
+ entry = ret['result']
+
+ def test_c_hbacrule_zap_testing_data(self):
"""
Clear data for HBAC plugin testing.
"""