Improve CNAME record validation

Refactor DNS RR conflict validator so that it is better extensible in
the future. Also check that there is only one CNAME defined for
a DNS record.

PTR+CNAME record combination is no longer allowed as we found out it
does not make sense to have this combination.

https://fedorahosted.org/freeipa/ticket/3450
This commit is contained in:
Martin Kosek 2013-04-02 11:58:31 +02:00
parent 81be28d6bd
commit 42c401a877
2 changed files with 43 additions and 42 deletions

View File

@ -2269,23 +2269,34 @@ class dnsrecord(LDAPObject):
def check_record_type_collisions(self, old_entry, entry_attrs):
# Test that only allowed combination of record types was created
attrs = set(attr for attr in entry_attrs.keys() if attr in _record_attributes
and entry_attrs[attr])
attrs.update(attr for attr in old_entry.keys() if attr not in entry_attrs)
try:
attrs.remove('cnamerecord')
except KeyError:
rec_has_cname = False
else:
rec_has_cname = True
# CNAME and PTR record combination is allowed
attrs.discard('ptrrecord')
rec_has_other_types = True if attrs else False
rrattrs = {}
if old_entry is not None:
old_rrattrs = dict((key, value) for key, value in old_entry.iteritems()
if key in self.params and
isinstance(self.params[key], DNSRecord))
rrattrs.update(old_rrattrs)
new_rrattrs = dict((key, value) for key, value in entry_attrs.iteritems()
if key in self.params and
isinstance(self.params[key], DNSRecord))
rrattrs.update(new_rrattrs)
if rec_has_cname and rec_has_other_types:
raise errors.ValidationError(name='cnamerecord',
error=_('CNAME record is not allowed to coexist with any other '
'records except PTR'))
# CNAME record validation
try:
cnames = rrattrs['cnamerecord']
except KeyError:
pass
else:
if cnames is not None:
if len(cnames) > 1:
raise errors.ValidationError(name='cnamerecord',
error=_('only one CNAME record is allowed per name '
'(RFC 2136, section 1.1.5)'))
if any(rrvalue is not None
and rrattr != 'cnamerecord'
for rrattr, rrvalue in rrattrs.iteritems()):
raise errors.ValidationError(name='cnamerecord',
error=_('CNAME record is not allowed to coexist '
'with any other record (RFC 1034, section 3.6.2)'))
api.register(dnsrecord)
@ -2435,7 +2446,7 @@ class dnsrecord_add(LDAPCreate):
try:
(dn_, old_entry) = ldap.get_entry(dn, _record_attributes)
except errors.NotFound:
pass
old_entry = None
else:
for attr in entry_attrs.keys():
if attr not in _record_attributes:
@ -2448,7 +2459,7 @@ class dnsrecord_add(LDAPCreate):
vals = list(entry_attrs[attr])
entry_attrs[attr] = list(set(old_entry.get(attr, []) + vals))
self.obj.check_record_type_collisions(old_entry, entry_attrs)
self.obj.check_record_type_collisions(old_entry, entry_attrs)
return dn
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):

View File

@ -773,7 +773,8 @@ class test_dns(Declarative):
desc='Try to add CNAME record to %r using dnsrecord_add' % (dnsres1),
command=('dnsrecord_add', [dnszone1, dnsres1], {'cnamerecord': u'foo-1.example.com.'}),
expected=errors.ValidationError(name='cnamerecord',
error=u'CNAME record is not allowed to coexist with any other records except PTR'),
error=u'CNAME record is not allowed to coexist with any other '
u'record (RFC 1034, section 3.6.2)'),
),
dict(
@ -784,6 +785,14 @@ class test_dns(Declarative):
u'are allowed. DNS label may not start or end with -'),
),
dict(
desc='Try to add multiple CNAME record %r using dnsrecord_add' % (dnsrescname),
command=('dnsrecord_add', [dnszone1, dnsrescname], {'cnamerecord':
[u'1.example.com.', u'2.example.com.']}),
expected=errors.ValidationError(name='cnamerecord',
error=u'only one CNAME record is allowed per name (RFC 2136, section 1.1.5)'),
),
dict(
desc='Add CNAME record to %r using dnsrecord_add' % (dnsrescname),
command=('dnsrecord_add', [dnszone1, dnsrescname], {'cnamerecord': u'foo-1.example.com.'}),
@ -803,14 +812,16 @@ class test_dns(Declarative):
desc='Try to add other record to CNAME record %r using dnsrecord_add' % (dnsrescname),
command=('dnsrecord_add', [dnszone1, dnsrescname], {'arecord': u'10.0.0.1'}),
expected=errors.ValidationError(name='cnamerecord',
error=u'CNAME record is not allowed to coexist with any other records except PTR'),
error=u'CNAME record is not allowed to coexist with any other '
u'record (RFC 1034, section 3.6.2)'),
),
dict(
desc='Try to add other record to CNAME record %r using dnsrecord_mod' % (dnsrescname),
command=('dnsrecord_mod', [dnszone1, dnsrescname], {'arecord': u'10.0.0.1'}),
expected=errors.ValidationError(name='cnamerecord',
error=u'CNAME record is not allowed to coexist with any other records except PTR'),
error=u'CNAME record is not allowed to coexist with any other '
u'record (RFC 1034, section 3.6.2)'),
),
dict(
@ -1062,22 +1073,6 @@ class test_dns(Declarative):
},
),
dict(
desc='Test that CNAME/PTR record type combination in record %r is allowed' % (dnsrev1),
command=('dnsrecord_add', [revdnszone1, dnsrev1], {'cnamerecord': u'foo-1.example.com.' }),
expected={
'value': dnsrev1,
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
'dn': dnsrev1_dn,
'idnsname': [dnsrev1],
'ptrrecord': [u'foo-1.example.com.'],
'cnamerecord': [u'foo-1.example.com.'],
},
},
),
dict(
desc='Show record %r in zone %r with --structured and --all options'\
% (dnsrev1, revdnszone1),
@ -1096,11 +1091,6 @@ class test_dns(Declarative):
'dnsdata': u'foo-1.example.com.',
'ptr_part_hostname': u'foo-1.example.com.'
},
{
'dnstype': u'CNAME',
'dnsdata': u'foo-1.example.com.',
'cname_part_hostname': u'foo-1.example.com.'
}
],
},
},