summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAna Krivokapic <akrivoka@redhat.com>2013-04-12 15:20:07 +0200
committerMartin Kosek <mkosek@redhat.com>2013-04-16 15:50:24 +0200
commita730b6e7b5e4eca754022fd3e0112ef597888c3b (patch)
tree224bb29ab953d696fe7eb8b9ea106d60c47a3a0f
parente736e75ce9724ae8298a5b69d093313cd6e62b60 (diff)
downloadfreeipa.git-a730b6e7b5e4eca754022fd3e0112ef597888c3b.tar.gz
freeipa.git-a730b6e7b5e4eca754022fd3e0112ef597888c3b.tar.xz
freeipa.git-a730b6e7b5e4eca754022fd3e0112ef597888c3b.zip
Integrate realmdomains with IPA DNS
Add an entry to realmdomains when a DNS zone is added to IPA. Delete the related entry from realmdomains when the DNS zone is deleted from IPA. Add _kerberos TXT record to DNS zone when a new realmdomain is added. Delete _kerberos TXT record from DNS zone when realmdomain is deleted. Add unit tests to cover new functionality. https://fedorahosted.org/freeipa/ticket/3544
-rw-r--r--ipalib/plugins/dns.py23
-rw-r--r--ipalib/plugins/realmdomains.py50
-rw-r--r--tests/test_xmlrpc/test_dns_plugin.py8
-rw-r--r--tests/test_xmlrpc/test_dns_realmdomains_integration.py168
4 files changed, 248 insertions, 1 deletions
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index becec142..d59df59a 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -1841,6 +1841,18 @@ class dnszone_add(LDAPCreate):
dns_record,
nameserver_ip_address)
+ # Add entry to realmdomains
+ # except for our own domain, forwarded zones and reverse zones
+ zone = keys[0]
+
+ if (zone != api.env.domain
+ and not options.get('idnsforwarders')
+ and not zone_is_reverse(zone)):
+ try:
+ api.Command['realmdomains_mod'](add_domain=zone, force=True)
+ except errors.EmptyModlist:
+ pass
+
return dn
api.register(dnszone_add)
@@ -1857,6 +1869,17 @@ class dnszone_del(LDAPDelete):
force=True)
except errors.NotFound:
pass
+
+ # Delete entry from realmdomains
+ # except for our own domain
+ zone = keys[0]
+
+ if zone != api.env.domain:
+ try:
+ api.Command['realmdomains_mod'](del_domain=zone, force=True)
+ except errors.AttrValueNotFound:
+ pass
+
return True
api.register(dnszone_del)
diff --git a/ipalib/plugins/realmdomains.py b/ipalib/plugins/realmdomains.py
index f3dbf8da..cff193f2 100644
--- a/ipalib/plugins/realmdomains.py
+++ b/ipalib/plugins/realmdomains.py
@@ -49,6 +49,10 @@ EXAMPLES:
""")
+def _domain_name_normalizer(d):
+ return d.lower().rstrip('.')
+
+
class realmdomains(LDAPObject):
"""
List of domains associated with IPA realm.
@@ -64,16 +68,19 @@ class realmdomains(LDAPObject):
takes_params = (
Str('associateddomain+',
_domain_name_validator,
+ normalizer=_domain_name_normalizer,
cli_name='domain',
label=_('Domain'),
),
Str('add_domain?',
_domain_name_validator,
+ normalizer=_domain_name_normalizer,
cli_name='add_domain',
label=_('Add domain'),
),
Str('del_domain?',
_domain_name_validator,
+ normalizer=_domain_name_normalizer,
cli_name='del_domain',
label=_('Delete domain'),
),
@@ -133,6 +140,49 @@ class realmdomains_mod(LDAPUpdate):
entry_attrs['associateddomain'] = domains
return dn
+ def execute(self, *keys, **options):
+ dn = self.obj.get_dn(*keys, **options)
+ ldap = self.obj.backend
+
+ domains_old = set(ldap.get_entry(dn)[1]['associateddomain'])
+ result = super(realmdomains_mod, self).execute(*keys, **options)
+ domains_new = set(ldap.get_entry(dn)[1]['associateddomain'])
+
+ domains_added = domains_new - domains_old
+ domains_deleted = domains_old - domains_new
+
+ # Add a _kerberos TXT record for zones that correspond with
+ # domains which were added
+ for d in domains_added:
+ # Skip our own domain
+ if d == api.env.domain:
+ continue
+ try:
+ api.Command['dnsrecord_add'](
+ unicode(d),
+ u'_kerberos',
+ txtrecord=api.env.realm
+ )
+ except (errors.EmptyModlist, errors.NotFound):
+ pass
+
+ # Delete _kerberos TXT record from zones that correspond with
+ # domains which were deleted
+ for d in domains_deleted:
+ # Skip our own domain
+ if d == api.env.domain:
+ continue
+ try:
+ api.Command['dnsrecord_del'](
+ unicode(d),
+ u'_kerberos',
+ txtrecord=api.env.realm
+ )
+ except (errors.AttrValueNotFound, errors.NotFound):
+ pass
+
+ return result
+
api.register(realmdomains_mod)
diff --git a/tests/test_xmlrpc/test_dns_plugin.py b/tests/test_xmlrpc/test_dns_plugin.py
index 7b14fc67..24fc7ecc 100644
--- a/tests/test_xmlrpc/test_dns_plugin.py
+++ b/tests/test_xmlrpc/test_dns_plugin.py
@@ -34,6 +34,7 @@ dnszone1_rname = u'root.%s.' % dnszone1
dnszone1_permission = u'Manage DNS zone %s' % dnszone1
dnszone1_permission_dn = DN(('cn',dnszone1_permission),
api.env.container_permission,api.env.basedn)
+dnszone1_txtrec_dn = DN(('idnsname', '_kerberos'), dnszone1_dn)
dnszone2 = u'dnszone2.test'
dnszone2_dn = DN(('idnsname', dnszone2), api.env.container_dns, api.env.basedn)
dnszone2_mname = u'ns1.%s.' % dnszone2
@@ -526,7 +527,7 @@ class test_dns(Declarative):
command=('dnsrecord_find', [dnszone1], {}),
expected={
'summary': None,
- 'count': 3,
+ 'count': 4,
'truncated': False,
'result': [
{
@@ -535,6 +536,11 @@ class test_dns(Declarative):
'idnsname': [u'@'],
},
{
+ 'dn': dnszone1_txtrec_dn,
+ 'txtrecord': [api.env.realm],
+ 'idnsname': [u'_kerberos'],
+ },
+ {
'dn': dnszone1_mname_dn,
'idnsname': [u'ns1'],
'arecord': [u'1.2.3.4'],
diff --git a/tests/test_xmlrpc/test_dns_realmdomains_integration.py b/tests/test_xmlrpc/test_dns_realmdomains_integration.py
new file mode 100644
index 00000000..c4660a57
--- /dev/null
+++ b/tests/test_xmlrpc/test_dns_realmdomains_integration.py
@@ -0,0 +1,168 @@
+# Authors:
+# Ana Krivokapic <akrivoka@redhat.com>
+#
+# Copyright (C) 2013 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""
+Test integration of DNS and realmdomains.
+1. dnszone_{add,del} should create/delete appropriate entry in realmdomains.
+2. realmdomains_mod should add a _kerberos TXT record in the DNS zone.
+"""
+
+from ipalib import api, errors
+from ipapython.dn import DN
+from tests.test_xmlrpc import objectclasses
+from xmlrpc_test import Declarative, fuzzy_digits
+
+
+cn = u'Realm Domains'
+dn = DN(('cn', cn), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
+our_domain = api.env.domain
+dnszone_1 = u'dnszone.test'
+dnszone_1_dn = DN(('idnsname', dnszone_1), api.env.container_dns,
+ api.env.basedn)
+idnssoamname = u'ns1.%s.' % dnszone_1
+idnssoarname = u'root.%s.' % dnszone_1
+dnszone_2 = u'dnszone2.test'
+dnszone_2_dn = DN(('idnsname', dnszone_2), api.env.container_dns,
+ api.env.basedn)
+
+
+def assert_realmdomain_and_txt_record_present(response):
+ zone = response['value']
+
+ r = api.Command['realmdomains_show']()
+ assert zone in r['result']['associateddomain']
+
+ r = api.Command['dnsrecord_show'](zone, u'_kerberos')
+ assert api.env.realm in r['result']['txtrecord']
+
+ return True
+
+
+def assert_realmdomain_and_txt_record_not_present(response):
+ zone = response['value']
+
+ r = api.Command['realmdomains_show']()
+ assert zone not in r['result']['associateddomain']
+
+ try:
+ api.Command['dnsrecord_show'](zone, u'_kerberos')
+ except errors.NotFound:
+ return True
+
+
+class test_dns_realmdomains_integration(Declarative):
+ cleanup_commands = [
+ ('realmdomains_mod', [], {'associateddomain': [our_domain]}),
+ ('dnszone_del', [dnszone_1, dnszone_2], {'continue': True}),
+ ]
+
+ tests = [
+ dict(
+ desc='Check realmdomain and TXT record get created '
+ 'during dnszone_add',
+ command=(
+ 'dnszone_add', [dnszone_1], {
+ 'idnssoamname': idnssoamname,
+ 'idnssoarname': idnssoarname,
+ 'ip_address': u'1.2.3.4',
+ }
+ ),
+ expected={
+ 'value': dnszone_1,
+ 'summary': None,
+ 'result': {
+ 'dn': dnszone_1_dn,
+ 'idnsname': [dnszone_1],
+ 'idnszoneactive': [u'TRUE'],
+ 'idnssoamname': [idnssoamname],
+ 'nsrecord': [idnssoamname],
+ 'idnssoarname': [idnssoarname],
+ 'idnssoaserial': [fuzzy_digits],
+ 'idnssoarefresh': [fuzzy_digits],
+ 'idnssoaretry': [fuzzy_digits],
+ 'idnssoaexpire': [fuzzy_digits],
+ 'idnssoaminimum': [fuzzy_digits],
+ 'idnsallowdynupdate': [u'FALSE'],
+ 'idnsupdatepolicy': [u'grant %(realm)s krb5-self * A; '
+ u'grant %(realm)s krb5-self * AAAA; '
+ u'grant %(realm)s krb5-self * SSHFP;'
+ % dict(realm=api.env.realm)],
+ 'idnsallowtransfer': [u'none;'],
+ 'idnsallowquery': [u'any;'],
+ 'objectclass': objectclasses.dnszone,
+
+ },
+ },
+ extra_check=assert_realmdomain_and_txt_record_present,
+ ),
+
+ dict(
+ desc='Check realmdomain and TXT record do not get created '
+ 'during dnszone_add for forwarded zone',
+ command=(
+ 'dnszone_add', [dnszone_2], {
+ 'idnssoamname': idnssoamname,
+ 'idnssoarname': idnssoarname,
+ 'idnsforwarders': u'1.2.3.4',
+ 'idnsforwardpolicy': u'only',
+ 'force': True,
+ }
+ ),
+ expected={
+ 'value': dnszone_2,
+ 'summary': None,
+ 'result': {
+ 'dn': dnszone_2_dn,
+ 'idnsname': [dnszone_2],
+ 'idnszoneactive': [u'TRUE'],
+ 'idnssoamname': [idnssoamname],
+ 'idnsforwarders': [u'1.2.3.4'],
+ 'idnsforwardpolicy': [u'only'],
+ 'nsrecord': [idnssoamname],
+ 'idnssoarname': [idnssoarname],
+ 'idnssoaserial': [fuzzy_digits],
+ 'idnssoarefresh': [fuzzy_digits],
+ 'idnssoaretry': [fuzzy_digits],
+ 'idnssoaexpire': [fuzzy_digits],
+ 'idnssoaminimum': [fuzzy_digits],
+ 'idnsallowdynupdate': [u'FALSE'],
+ 'idnsupdatepolicy': [u'grant %(realm)s krb5-self * A; '
+ u'grant %(realm)s krb5-self * AAAA; '
+ u'grant %(realm)s krb5-self * SSHFP;'
+ % dict(realm=api.env.realm)],
+ 'idnsallowtransfer': [u'none;'],
+ 'idnsallowquery': [u'any;'],
+ 'objectclass': objectclasses.dnszone,
+
+ },
+ },
+ extra_check=assert_realmdomain_and_txt_record_not_present,
+ ),
+
+ dict(
+ desc='Check realmdomain and TXT record get deleted '
+ 'during dnszone_del',
+ command=('dnszone_del', [dnszone_1], {}),
+ expected={
+ 'value': dnszone_1,
+ 'summary': u'Deleted DNS zone "%s"' % dnszone_1,
+ 'result': {'failed': u''},
+ },
+ extra_check=assert_realmdomain_and_txt_record_not_present,
+ ),
+ ]