URL: https://github.com/freeipa/freeipa/pull/134 Author: pspacek Title: #134: DNS URI support Action: opened
PR body: """ """ To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/134/head:pr134 git checkout pr134
From 4c1e3f92885d94dae0987e1922df56d27fb6b0a8 Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka <slazn...@redhat.com> Date: Thu, 22 Sep 2016 08:12:45 +0200 Subject: [PATCH 1/3] Pretty-print structures in assert_deepequal By default, ipa-run-tests will now pretty-print structures compared in the assert_deepequal function. This behaviour can be turned off by the --no-pretty-print option. https://fedorahosted.org/freeipa/ticket/6212 --- ipatests/pytest.ini | 1 + ipatests/pytest_plugins/additional_config.py | 8 +++++++ ipatests/util.py | 35 ++++++++++++++++++++++------ 3 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 ipatests/pytest_plugins/additional_config.py diff --git a/ipatests/pytest.ini b/ipatests/pytest.ini index 233cf43..5b89942 100644 --- a/ipatests/pytest.ini +++ b/ipatests/pytest.ini @@ -12,6 +12,7 @@ addopts = --doctest-modules -p ipatests.pytest_plugins.declarative -p ipatests.pytest_plugins.integration -p ipatests.pytest_plugins.beakerlib + -p ipatests.pytest_plugins.additional_config # Ignore files for doc tests. # TODO: ideally, these should all use __name__=='__main__' guards --ignore=setup.py diff --git a/ipatests/pytest_plugins/additional_config.py b/ipatests/pytest_plugins/additional_config.py new file mode 100644 index 0000000..06ae970 --- /dev/null +++ b/ipatests/pytest_plugins/additional_config.py @@ -0,0 +1,8 @@ +# +# Copyright (C) 2016 FreeIPA Contributors see COPYING for license +# + + +def pytest_addoption(parser): + parser.addoption("--no-pretty-print", action="store_false", + dest="pretty_print", help="Don't pretty-print structures") diff --git a/ipatests/util.py b/ipatests/util.py index 0b50f85..38a3f4b 100644 --- a/ipatests/util.py +++ b/ipatests/util.py @@ -28,7 +28,9 @@ import shutil import re import uuid +import pytest from contextlib import contextmanager +from pprint import pformat import six import ldap @@ -273,18 +275,29 @@ def __ne__(self, other): %s len(expected) = %r len(got) = %r - expected = %r - got = %r + expected = %s + got = %s path = %r""" KEYS = """assert_deepequal: dict keys mismatch. %s missing keys = %r extra keys = %r - expected = %r - got = %r + expected = %s + got = %s path = %r""" +EXPECTED_LEN = len(' expected = ') +GOT_LEN = len(' got = ') + + +def struct_to_string(struct, indent=1): + """ + Function to pretty-format a structure and optionally indent its lines + so they match the visual indention of the first line + """ + return pformat(struct).replace('\n', '\n' + ' ' * indent) + def assert_deepequal(expected, got, doc='', stack=tuple()): """ @@ -315,6 +328,13 @@ def assert_deepequal(expected, got, doc='', stack=tuple()): Note that lists and tuples are considered equivalent, and the order of their elements does not matter. """ + if pytest.config.getoption("pretty_print"): # pylint: disable=no-member + expected_str = struct_to_string(expected, EXPECTED_LEN) + got_str = struct_to_string(got, GOT_LEN) + else: + expected_str = repr(expected) + got_str = repr(got) + if isinstance(expected, tuple): expected = list(expected) if isinstance(got, tuple): @@ -329,7 +349,8 @@ def assert_deepequal(expected, got, doc='', stack=tuple()): if isinstance(expected, (list, tuple)): if len(expected) != len(got): raise AssertionError( - LEN % (doc, len(expected), len(got), expected, got, stack) + LEN % (doc, len(expected), len(got), expected_str, got_str, + stack) ) # Sort list elements, unless they are dictionaries if expected and isinstance(expected[0], dict): @@ -352,8 +373,8 @@ def assert_deepequal(expected, got, doc='', stack=tuple()): extra = set(got).difference(expected) if missing or extra: raise AssertionError(KEYS % ( - doc, sorted(missing), sorted(extra), expected, got, stack - ) + doc, sorted(missing), sorted(extra), expected_str, got_str, + stack) ) for key in sorted(expected): e_sub = expected[key] From 14b2722c69769e9b604a05dcd4640d323455f198 Mon Sep 17 00:00:00 2001 From: Petr Spacek <pspa...@redhat.com> Date: Wed, 28 Sep 2016 15:20:43 +0200 Subject: [PATCH 2/3] DNS: Support URI resource record type https://fedorahosted.org/freeipa/ticket/6344 --- ACI.txt | 4 +- API.txt | 19 +++++-- install/share/60ipadns.ldif | 3 +- install/share/dns.ldif | 2 +- install/ui/src/freeipa/dns.js | 18 ++++++- ipaserver/plugins/dns.py | 51 +++++++++++++++++-- ipatests/test_xmlrpc/test_dns_plugin.py | 89 +++++++++++++++++++++++++++++++++ 7 files changed, 173 insertions(+), 13 deletions(-) diff --git a/ACI.txt b/ACI.txt index fddd598..0b47489 100644 --- a/ACI.txt +++ b/ACI.txt @@ -73,13 +73,13 @@ aci: (targetattr = "ipaprivatekey || ipapublickey || ipasecretkey || ipasecretke dn: dc=ipa,dc=example aci: (targetattr = "cn || idnssecalgorithm || idnsseckeyactivate || idnsseckeycreated || idnsseckeydelete || idnsseckeyinactive || idnsseckeypublish || idnsseckeyref || idnsseckeyrevoke || idnsseckeysep || idnsseckeyzone || objectclass")(target = "ldap:///cn=dns,dc=ipa,dc=example")(targetfilter = "(objectclass=idnsSecKey)")(version 3.0;acl "permission:System: Manage DNSSEC metadata";allow (all) groupdn = "ldap:///cn=System: Manage DNSSEC metadata,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: dc=ipa,dc=example -aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || createtimestamp || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsdefaultttl || dnsttl || dsrecord || entryusn || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnstemplateattribute || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || modifytimestamp || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || objectclass || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord")(target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read DNS Entries";allow (compare,read,search) groupdn = "ldap:///cn=System: Read DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";) +aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || createtimestamp || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsdefaultttl || dnsttl || dsrecord || entryusn || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnstemplateattribute || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || modifytimestamp || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || objectclass || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord || urirecord")(target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read DNS Entries";allow (compare,read,search) groupdn = "ldap:///cn=System: Read DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: dc=ipa,dc=example aci: (targetattr = "cn || createtimestamp || entryusn || idnssecalgorithm || idnsseckeyactivate || idnsseckeycreated || idnsseckeydelete || idnsseckeyinactive || idnsseckeypublish || idnsseckeyref || idnsseckeyrevoke || idnsseckeysep || idnsseckeyzone || modifytimestamp || objectclass")(target = "ldap:///cn=dns,dc=ipa,dc=example")(targetfilter = "(objectclass=idnsSecKey)")(version 3.0;acl "permission:System: Read DNSSEC metadata";allow (compare,read,search) groupdn = "ldap:///cn=System: Read DNSSEC metadata,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: dc=ipa,dc=example aci: (target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example")(version 3.0;acl "permission:System: Remove DNS Entries";allow (delete) groupdn = "ldap:///cn=System: Remove DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: dc=ipa,dc=example -aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsdefaultttl || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnstemplateattribute || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || objectclass || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord")(target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example")(version 3.0;acl "permission:System: Update DNS Entries";allow (write) groupdn = "ldap:///cn=System: Update DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";) +aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsdefaultttl || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnstemplateattribute || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || objectclass || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord || urirecord")(target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example")(version 3.0;acl "permission:System: Update DNS Entries";allow (write) groupdn = "ldap:///cn=System: Update DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=groups,cn=accounts,dc=ipa,dc=example aci: (targetfilter = "(|(objectclass=ipausergroup)(objectclass=posixgroup))")(version 3.0;acl "permission:System: Add Groups";allow (add) groupdn = "ldap:///cn=System: Add Groups,cn=permissions,cn=pbac,dc=ipa,dc=example";) dn: cn=groups,cn=accounts,dc=ipa,dc=example diff --git a/API.txt b/API.txt index 1e02ac2..bad3b92 100644 --- a/API.txt +++ b/API.txt @@ -1238,7 +1238,7 @@ output: Entry('result') output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) output: PrimaryKey('value') command: dnsrecord_add/1 -args: 2,95,3 +args: 2,99,3 arg: DNSNameParam('dnszoneidnsname', cli_name='dnszone') arg: DNSNameParam('idnsname', cli_name='name') option: Str('a6_part_data?', cli_name='a6_data', option_group=u'A6 Record') @@ -1335,12 +1335,16 @@ option: Int('tlsa_part_selector?', cli_name='tlsa_selector', option_group=u'TLSA option: TLSARecord('tlsarecord*', cli_name='tlsa_rec', option_group=u'TLSA Record') option: Str('txt_part_data?', cli_name='txt_data', option_group=u'TXT Record') option: TXTRecord('txtrecord*', cli_name='txt_rec', option_group=u'TXT Record') +option: Int('uri_part_priority?', cli_name='uri_priority', option_group=u'URI Record') +option: Str('uri_part_target?', cli_name='uri_target', option_group=u'URI Record') +option: Int('uri_part_weight?', cli_name='uri_weight', option_group=u'URI Record') +option: URIRecord('urirecord*', cli_name='uri_rec', option_group=u'URI Record') option: Str('version?') output: Entry('result') output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) output: PrimaryKey('value') command: dnsrecord_del/1 -args: 2,35,3 +args: 2,36,3 arg: DNSNameParam('dnszoneidnsname', cli_name='dnszone') arg: DNSNameParam('idnsname', cli_name='name') option: A6Record('a6record*', autofill=False, cli_name='a6_rec') @@ -1377,6 +1381,7 @@ option: SSHFPRecord('sshfprecord*', autofill=False, cli_name='sshfp_rec') option: Flag('structured', autofill=True, default=False) option: TLSARecord('tlsarecord*', autofill=False, cli_name='tlsa_rec') option: TXTRecord('txtrecord*', autofill=False, cli_name='txt_rec') +option: URIRecord('urirecord*', autofill=False, cli_name='uri_rec') option: Str('version?') output: Output('result', type=[<type 'dict'>]) output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) @@ -1391,7 +1396,7 @@ output: Output('result', type=[<type 'dict'>]) output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) output: ListOfPrimaryKeys('value') command: dnsrecord_find/1 -args: 2,39,4 +args: 2,40,4 arg: DNSNameParam('dnszoneidnsname', cli_name='dnszone') arg: Str('criteria?') option: A6Record('a6record*', autofill=False, cli_name='a6_rec') @@ -1432,13 +1437,14 @@ option: Flag('structured', autofill=True, default=False) option: Int('timelimit?', autofill=False) option: TLSARecord('tlsarecord*', autofill=False, cli_name='tlsa_rec') option: TXTRecord('txtrecord*', autofill=False, cli_name='txt_rec') +option: URIRecord('urirecord*', autofill=False, cli_name='uri_rec') option: Str('version?') output: Output('count', type=[<type 'int'>]) output: ListOfEntries('result') output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) output: Output('truncated', type=[<type 'bool'>]) command: dnsrecord_mod/1 -args: 2,95,3 +args: 2,99,3 arg: DNSNameParam('dnszoneidnsname', cli_name='dnszone') arg: DNSNameParam('idnsname', cli_name='name') option: Str('a6_part_data?', autofill=False, cli_name='a6_data', option_group=u'A6 Record') @@ -1535,6 +1541,10 @@ option: Int('tlsa_part_selector?', autofill=False, cli_name='tlsa_selector', opt option: TLSARecord('tlsarecord*', autofill=False, cli_name='tlsa_rec', option_group=u'TLSA Record') option: Str('txt_part_data?', autofill=False, cli_name='txt_data', option_group=u'TXT Record') option: TXTRecord('txtrecord*', autofill=False, cli_name='txt_rec', option_group=u'TXT Record') +option: Int('uri_part_priority?', autofill=False, cli_name='uri_priority', option_group=u'URI Record') +option: Str('uri_part_target?', autofill=False, cli_name='uri_target', option_group=u'URI Record') +option: Int('uri_part_weight?', autofill=False, cli_name='uri_weight', option_group=u'URI Record') +option: URIRecord('urirecord*', autofill=False, cli_name='uri_rec', option_group=u'URI Record') option: Str('version?') output: Entry('result') output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) @@ -6385,6 +6395,7 @@ default: dnssrvrecord/1 default: dnssshfprecord/1 default: dnstlsarecord/1 default: dnstxtrecord/1 +default: dnsurirecord/1 default: dnszone/1 default: dnszone_add/1 default: dnszone_add_permission/1 diff --git a/install/share/60ipadns.ldif b/install/share/60ipadns.ldif index 6f62394..b1ee006 100644 --- a/install/share/60ipadns.ldif +++ b/install/share/60ipadns.ldif @@ -35,6 +35,7 @@ attributeTypes: (1.3.6.1.4.1.2428.20.1.51 NAME 'nSEC3PARAMRecord' DESC 'RFC 5155 attributeTypes: (1.3.6.1.4.1.2428.20.1.52 NAME 'TLSARecord' DESC 'DNS-Based Authentication of Named Entities - Transport Layer Security Protocol, RFC 6698' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.55 NAME 'HIPRecord' DESC 'Host Identity Protocol (HIP) Domain Name System (DNS) Extension, RFC 5205' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.99 NAME 'SPFRecord' DESC 'Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, RFC 7208' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +attributeTypes: (1.3.6.1.4.1.2428.20.1.256 NAME 'URIRecord' DESC 'URI, RFC 7553' EQUALITY caseExactIA5Match SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.32769 NAME 'DLVRecord' DESC 'DNSSEC Lookaside Validation, RFC 4431' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.4 NAME 'UnknownRecord' DESC 'unknown DNS record, RFC 3597' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch ) attributeTypes: (0.9.2342.19200300.100.1.26 NAME 'aRecord' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) @@ -77,7 +78,7 @@ attributeTypes: ( 2.16.840.1.113730.3.8.11.74 NAME 'ipaDNSVersion' DESC 'IPA DNS attributeTypes: ( 2.16.840.1.113730.3.8.5.31 NAME 'idnsServerId' DESC 'DNS server identifier' EQUALITY caseIgnoreMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.4' ) attributeTypes: ( 2.16.840.1.113730.3.8.5.32 NAME 'ipaLocation' DESC 'Reference to IPA location' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'IPA v4.4' ) attributeTypes: ( 2.16.840.1.113730.3.8.5.33 NAME 'ipaServiceWeight' DESC 'Weight for the server in IPA location' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v4.4' ) -objectClasses: ( 2.16.840.1.113730.3.8.6.0 NAME 'idnsRecord' DESC 'dns Record, usually a host' SUP top STRUCTURAL MUST idnsName MAY ( cn $ idnsAllowDynUpdate $ dNSTTL $ dNSClass $ aRecord $ aAAARecord $ a6Record $ nSRecord $ cNAMERecord $ pTRRecord $ sRVRecord $ tXTRecord $ mXRecord $ mDRecord $ hInfoRecord $ mInfoRecord $ aFSDBRecord $ SigRecord $ KeyRecord $ LocRecord $ nXTRecord $ nAPTRRecord $ kXRecord $ certRecord $ dNameRecord $ dSRecord $ sSHFPRecord $ rRSIGRecord $ nSECRecord $ DLVRecord $ TLSARecord $ UnknownRecord $ RPRecord $ APLRecord $ IPSECKEYRecord $ DHCIDRecord $ HIPRecord $ SPFRecord ) ) +objectClasses: ( 2.16.840.1.113730.3.8.6.0 NAME 'idnsRecord' DESC 'dns Record, usually a host' SUP top STRUCTURAL MUST idnsName MAY ( cn $ idnsAllowDynUpdate $ dNSTTL $ dNSClass $ aRecord $ aAAARecord $ a6Record $ nSRecord $ cNAMERecord $ pTRRecord $ sRVRecord $ tXTRecord $ mXRecord $ mDRecord $ hInfoRecord $ mInfoRecord $ aFSDBRecord $ SigRecord $ KeyRecord $ LocRecord $ nXTRecord $ nAPTRRecord $ kXRecord $ certRecord $ dNameRecord $ dSRecord $ sSHFPRecord $ rRSIGRecord $ nSECRecord $ DLVRecord $ TLSARecord $ UnknownRecord $ RPRecord $ APLRecord $ IPSECKEYRecord $ DHCIDRecord $ HIPRecord $ SPFRecord $ URIRecord ) ) objectClasses: ( 2.16.840.1.113730.3.8.6.1 NAME 'idnsZone' DESC 'Zone class' SUP idnsRecord STRUCTURAL MUST ( idnsZoneActive $ idnsSOAmName $ idnsSOArName $ idnsSOAserial $ idnsSOArefresh $ idnsSOAretry $ idnsSOAexpire $ idnsSOAminimum ) MAY ( idnsUpdatePolicy $ idnsAllowQuery $ idnsAllowTransfer $ idnsAllowSyncPTR $ idnsForwardPolicy $ idnsForwarders $ idnsSecInlineSigning $ nSEC3PARAMRecord $ dNSdefaultTTL ) ) objectClasses: ( 2.16.840.1.113730.3.8.6.2 NAME 'idnsConfigObject' DESC 'DNS global config options' STRUCTURAL MAY ( idnsForwardPolicy $ idnsForwarders $ idnsAllowSyncPTR $ idnsZoneRefresh $ idnsPersistentSearch ) ) objectClasses: ( 2.16.840.1.113730.3.8.12.18 NAME 'ipaDNSZone' SUP top AUXILIARY MUST idnsName MAY managedBy X-ORIGIN 'IPA v3' ) diff --git a/install/share/dns.ldif b/install/share/dns.ldif index 6a8524b..6dfcb29 100644 --- a/install/share/dns.ldif +++ b/install/share/dns.ldif @@ -11,7 +11,7 @@ ipaDNSVersion: 2 aci: (targetattr = "*")(version 3.0; acl "Allow read access"; allow (read,search,compare) groupdn = "ldap:///cn=Read DNS Entries,cn=permissions,cn=pbac,$SUFFIX" or userattr = "parent[0,1].managedby#GROUPDN";) aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";) aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";) -aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || mdrecord || minforecord || mxrecord || naptrrecord || nsecrecord || nsec3paramrecord || nsrecord || nxtrecord || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) +aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || mdrecord || minforecord || mxrecord || naptrrecord || nsecrecord || nsec3paramrecord || nsrecord || nxtrecord || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || urirecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) dn: cn=servers,cn=dns,$SUFFIX changetype: add diff --git a/install/ui/src/freeipa/dns.js b/install/ui/src/freeipa/dns.js index 2d424ae..51a0984 100644 --- a/install/ui/src/freeipa/dns.js +++ b/install/ui/src/freeipa/dns.js @@ -1226,7 +1226,21 @@ IPA.dns.get_record_metadata = function() { ], adder_attributes: [], columns: ['txt_part_data'] - } + }, + { + name: 'urirecord', + attributes: [ + 'uri_part_priority', + 'uri_part_weight', + 'uri_part_target' + ], + adder_attributes: [], + columns: [ + 'uri_part_priority', 'uri_part_weight', + 'uri_part_target' + ] + }, + ]; //set required flags for attributes based on 'dnsrecord_optional' flag @@ -1608,7 +1622,7 @@ IPA.dns_record_types = function() { //only supported var attrs = ['A', 'AAAA', 'A6', 'AFSDB', 'CERT', 'CNAME', 'DNAME', 'DS', 'DLV', 'KX', 'LOC', 'MX', 'NAPTR', 'NS', - 'PTR', 'SRV', 'SSHFP', 'TLSA', 'TXT']; + 'PTR', 'SRV', 'SSHFP', 'TLSA', 'TXT', 'URI']; var record_types = []; for (var i=0; i<attrs.length; i++) { var attr = attrs[i]; diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py index e1c4e24..68272fa 100644 --- a/ipaserver/plugins/dns.py +++ b/ipaserver/plugins/dns.py @@ -28,6 +28,7 @@ import dns.name import dns.exception +import dns.rdata import dns.rdatatype import dns.resolver import six @@ -320,7 +321,7 @@ u'A', u'AAAA', u'A6', u'AFSDB', u'APL', u'CERT', u'CNAME', u'DHCID', u'DLV', u'DNAME', u'DS', u'HIP', u'HINFO', u'IPSECKEY', u'KEY', u'KX', u'LOC', u'MD', u'MINFO', u'MX', u'NAPTR', u'NS', u'NSEC', u'NXT', u'PTR', u'RRSIG', - u'RP', u'SIG', u'SPF', u'SRV', u'SSHFP', u'TLSA', u'TXT', + u'RP', u'SIG', u'SPF', u'SRV', u'SSHFP', u'TLSA', u'TXT', u"URI" ) # DNS zone record identificator @@ -1438,6 +1439,48 @@ def _get_part_values(self, value): # ignore any space in TXT record return (value,) + +def _normalize_uri_target(uri_target): + """DNS-escape "\ characters and double-quote target.""" + # is user-provided string is already quoted? + if uri_target[0:1] == uri_target[-1:] == '"': + uri_target = uri_target[1:-1] + # RFC 7553 section 4.4: The Target MUST NOT be an empty URI (""). + # minlength in param will detect this + if not uri_target: + return + return u'"{0}"'.format(uri_target) + + +class URIRecord(DNSRecord): + rrtype = 'URI' + rfc = 7553 + parts = ( + Int('priority', + label=_('Priority (order)'), + doc=_('Lower number means higher priority. Clients will attempt ' + 'to contact the URI with the lowest-numbered priority ' + 'they can reach.'), + minvalue=0, + maxvalue=65535, + ), + Int('weight', + label=_('Weight'), + doc=_('Relative weight for entries with the same priority.'), + minvalue=0, + maxvalue=65535, + ), + Str('target', + label=_('Target Uniform Resource Identifier'), + doc=_('Target Uniform Resource Identifier according to RFC 3986'), + minlength=1, + # This field holds the URI of the target, enclosed in double-quote + # characters (e.g. "uri:"). + normalizer=_normalize_uri_target, + ), + ) + + _dns_records = ( ARecord(), AAAARecord(), @@ -1468,8 +1511,10 @@ def _get_part_values(self, value): SSHFPRecord(), TLSARecord(), TXTRecord(), + URIRecord(), ) + def __dns_record_options_iter(): for opt in (Any('dnsrecords?', label=_('Records'), @@ -2510,7 +2555,7 @@ class dnszone(DNSZoneBase): 'mxrecord', 'naptrrecord', 'nsecrecord', 'nsec3paramrecord', 'nsrecord', 'nxtrecord', 'ptrrecord', 'rprecord', 'rrsigrecord', 'sigrecord', 'spfrecord', 'srvrecord', 'sshfprecord', - 'tlsarecord', 'txtrecord', 'unknownrecord', + 'tlsarecord', 'txtrecord', 'urirecord', 'unknownrecord', }, 'replaces_system': ['Read DNS Entries'], 'default_privileges': {'DNS Administrators', 'DNS Servers'}, @@ -2547,7 +2592,7 @@ class dnszone(DNSZoneBase): 'mxrecord', 'naptrrecord', 'nsecrecord', 'nsec3paramrecord', 'nsrecord', 'nxtrecord', 'ptrrecord', 'rprecord', 'rrsigrecord', 'sigrecord', 'spfrecord', 'srvrecord', 'sshfprecord', - 'tlsarecord', 'txtrecord', 'unknownrecord', + 'tlsarecord', 'txtrecord', 'urirecord', 'unknownrecord', }, 'replaces': [ '(targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:update dns entries";allow (write) groupdn = "ldap:///cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX";)', diff --git a/ipatests/test_xmlrpc/test_dns_plugin.py b/ipatests/test_xmlrpc/test_dns_plugin.py index a02b4a9..487e792 100644 --- a/ipatests/test_xmlrpc/test_dns_plugin.py +++ b/ipatests/test_xmlrpc/test_dns_plugin.py @@ -6085,3 +6085,92 @@ def setup_class(cls): zone6_unresolvable_ns_dnsname,), ), ] + + +@pytest.mark.tier1 +class test_dns_type_uri(test_dns): + """Test behavior specific for URI RR type.""" + + @classmethod + def setup_class(cls): + super(test_dns_type_uri, cls).setup_class() + try: + api.Command['dnszone_add'](zone1, idnssoarname=zone1_rname) + except errors.DuplicateEntry: + pass + + cleanup_commands = [ + ('dnszone_del', [zone1], {'continue': True}), + ] + + uri_priority = 1 + uri_weight = 2 + uri_target = 'http://example.com/' + uri_raw_value = u'{0} {1} "{2}"'.format( + uri_priority, uri_weight, uri_target) + tests = [ + dict( + desc='Create URI record under %s zone %r' % (name1_dnsname, zone1), + command=('dnsrecord_add', [zone1, name1_dnsname], + {'urirecord': uri_raw_value}), + expected={ + 'value': name1_dnsname, + 'summary': None, + 'result': { + 'dn': name1_dn, + 'idnsname': [name1_dnsname], + 'objectclass': objectclasses.dnsrecord, + 'urirecord': [uri_raw_value], + }, + }, + ), + dict( + desc='URI record is case sensitive on delete (one record)', + command=('dnsrecord_del', [zone1, name1_dnsname], + {'urirecord': uri_raw_value.upper()}), + expected=errors.AttrValueNotFound(attr='URI record', + value=uri_raw_value.upper()), + ), + dict( + desc='URI record is case sensitive on add', + command=('dnsrecord_add', [zone1, name1_dnsname], + {'urirecord': uri_raw_value.upper()}), + expected={ + 'value': name1_dnsname, + 'summary': None, + 'result': { + 'dn': name1_dn, + 'idnsname': [name1_dnsname], + 'objectclass': objectclasses.dnsrecord, + 'urirecord': [uri_raw_value, uri_raw_value.upper()], + }, + }, + ), + dict( + desc='URI record is case sensitive on delete (two records)', + command=('dnsrecord_del', [zone1, name1_dnsname], + {'urirecord': [uri_raw_value, uri_raw_value.upper()]}), + expected={ + 'value': [name1_dnsname], + 'summary': u'Deleted record "%s"' % name1_dnsname, + 'result': {'failed': []}, + }, + ), + dict( + desc='URI record normalization does not double "" around target', + command=('dnsrecord_add', [zone1, name1_dnsname], + {'uri_part_target': u'"{0}"'.format(uri_target), + 'uri_part_priority': uri_priority, + 'uri_part_weight': uri_weight}), + expected={ + 'value': name1_dnsname, + 'summary': None, + 'result': { + 'dn': name1_dn, + 'idnsname': [name1_dnsname], + 'objectclass': objectclasses.dnsrecord, + 'urirecord': [uri_raw_value], + }, + }, + ), + ] From 7c7c7db2fe93b8c24005716eb71a61bbc08151fd Mon Sep 17 00:00:00 2001 From: Petr Spacek <pspa...@redhat.com> Date: Tue, 4 Oct 2016 17:18:05 +0200 Subject: [PATCH 3/3] DNS: Improve field descriptions for SRV records --- ipaserver/plugins/dns.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py index 68272fa..7ebfb1a 100644 --- a/ipaserver/plugins/dns.py +++ b/ipaserver/plugins/dns.py @@ -1332,12 +1332,16 @@ class SRVRecord(DNSRecord): rfc = 2782 parts = ( Int('priority', - label=_('Priority'), + label=_('Priority (order)'), + doc=_('Lower number means higher priority. Clients will attempt ' + 'to contact the server with the lowest-numbered priority ' + 'they can reach.'), minvalue=0, maxvalue=65535, ), Int('weight', label=_('Weight'), + doc=_('Relative weight for entries with the same priority.'), minvalue=0, maxvalue=65535, ),
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code