URL: https://github.com/freeipa/freeipa/pull/134
Author: pspacek
 Title: #134: DNS URI support
Action: synchronized

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 a35fe8f72d3c905d6338bce8a7f682b8f3e228e7 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Wed, 28 Sep 2016 15:20:43 +0200
Subject: [PATCH 1/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           | 15 +++++-
 install/updates/40-dns.update           |  3 +-
 ipaserver/plugins/dns.py                | 50 ++++++++++++++++--
 ipatests/test_xmlrpc/test_dns_plugin.py | 89 +++++++++++++++++++++++++++++++++
 8 files changed, 172 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..1e24c01 100644
--- a/install/ui/src/freeipa/dns.js
+++ b/install/ui/src/freeipa/dns.js
@@ -1226,6 +1226,19 @@ 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'
+            ]
         }
     ];
 
@@ -1608,7 +1621,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/install/updates/40-dns.update b/install/updates/40-dns.update
index 4c0824b..14e56fd 100644
--- a/install/updates/40-dns.update
+++ b/install/updates/40-dns.update
@@ -4,7 +4,7 @@ dn: cn=dns, $SUFFIX
 addifexist: objectClass: idnsConfigObject
 addifexist: aci:(target = "ldap:///idnsname=*,cn=dns,$SUFFIX";)(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";)
 addifexist: aci:(target = "ldap:///idnsname=*,cn=dns,$SUFFIX";)(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";)
-addifexist: 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";)
+addifexist: 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";)
 
 
 # replace DNS tree deny rule with managedBy enhanced allow rule
@@ -17,6 +17,7 @@ dn: cn=dns, $SUFFIX
 remove:aci:(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 || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX";)(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";)
 remove:aci:(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 || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders || dlvrecord || idnssecinlinesigning || nsec3paramrecord || tlsarecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX";)(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";)
 remove:aci:(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 || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders || dlvrecord || idnssecinlinesigning || nsec3paramrecord || tlsarecord || 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";)
+remove: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";)
 
 # add DNS plugin
 dn: cn=IPA DNS,cn=plugins,cn=config
diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py
index e1c4e24..929706b 100644
--- a/ipaserver/plugins/dns.py
+++ b/ipaserver/plugins/dns.py
@@ -320,7 +320,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 +1438,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 +1510,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 +2554,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 +2591,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 5b0e7911c895db494b95a0f0931c8a60c395e30b Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Tue, 4 Oct 2016 17:18:05 +0200
Subject: [PATCH 2/3] DNS: Improve field descriptions for SRV records

---
 install/ui/src/freeipa/dns.js | 8 ++++----
 ipaserver/plugins/dns.py      | 6 +++++-
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/install/ui/src/freeipa/dns.js b/install/ui/src/freeipa/dns.js
index 1e24c01..2e8a71e 100644
--- a/install/ui/src/freeipa/dns.js
+++ b/install/ui/src/freeipa/dns.js
@@ -1180,10 +1180,10 @@ IPA.dns.get_record_metadata = function() {
         {
             name: 'srvrecord',
             attributes: [
-                'srv_part_priority',
-                'srv_part_weight',
-                'srv_part_port',
-                'srv_part_target'
+               'srv_part_priority',
+               'srv_part_weight',
+               'srv_part_port',
+               'srv_part_target'
             ],
             adder_attributes: [],
             columns: ['srv_part_priority', 'srv_part_weight', 'srv_part_port',
diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py
index 929706b..2522b52 100644
--- a/ipaserver/plugins/dns.py
+++ b/ipaserver/plugins/dns.py
@@ -1331,12 +1331,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,
         ),

From 7068753a11c31d460d561df4b2a1a18e31fbe1de Mon Sep 17 00:00:00 2001
From: Pavel Vomacka <pvoma...@redhat.com>
Date: Thu, 6 Oct 2016 13:05:05 +0200
Subject: [PATCH 3/3] Add tooltip to all fields in DNS record adder dialog

In case that option is not documented or the doc string is the same as label, then no tooltip is shown.
---
 install/ui/src/freeipa/dns.js | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/install/ui/src/freeipa/dns.js b/install/ui/src/freeipa/dns.js
index 2e8a71e..f0ec1e3 100644
--- a/install/ui/src/freeipa/dns.js
+++ b/install/ui/src/freeipa/dns.js
@@ -975,6 +975,16 @@ IPA.dns.record_search_deleter_dialog = function(spec) {
     return that;
 };
 
+/**
+ * This definition of records attributes is used for generating adder dialog.
+ *
+ * HOW TO EDIT ADDER DIALOG:
+ * In case you want to edit fields or widgets in adder dialog, you have to
+ * create object from attribute, then the attribute will be the name property
+ * of object. Then most of the widget or fields attributes have to be added in
+ * widget_opt (field_opt). Check the IPA.dns.record_prepare_editor_for_type
+ * method.
+ */
 IPA.dns.record_metadata = null;
 IPA.dns.get_record_metadata = function() {
 
@@ -1526,6 +1536,11 @@ IPA.dns.record_prepare_editor_for_type = function(type, fields, widgets, update)
             widget.name = attribute;
         } else {
             widget.name = attribute.name;
+            if (metadata) {
+                var doc = metadata.doc;
+                var label = metadata.label;
+                if (doc !== label) widget.tooltip = doc;
+            }
             set_defined(attribute.$type, widget, '$type');
             set_defined(attribute.options, widget, 'options');
             copy_obj(widget, attribute.widget_opt);
-- 
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

Reply via email to