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 f0a86bd9885128a169834fcf9085dbc23727c1bf 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 +++++-
 ipaserver/plugins/dns.py                | 51 +++++++++++++++++--
 ipatests/test_xmlrpc/test_dns_plugin.py | 89 +++++++++++++++++++++++++++++++++
 7 files changed, 171 insertions(+), 12 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/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 07cf9e11f9114fe688d09887f1ac5e4874cb7e30 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 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,
         ),

From 38e3eb8139e1125c4c2d8bf7e712b79031052fb1 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 | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/install/ui/src/freeipa/dns.js b/install/ui/src/freeipa/dns.js
index 2e8a71e..2872453 100644
--- a/install/ui/src/freeipa/dns.js
+++ b/install/ui/src/freeipa/dns.js
@@ -1526,6 +1526,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