URL: https://github.com/freeipa/freeipa/pull/573
Author: martbab
 Title: #573: Provide centralized management of user short name resolution
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/573/head:pr573
git checkout pr573
From 5e9291aaf7dfd92c5983f0bcd80976b1f597ac58 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Thu, 9 Mar 2017 14:24:21 +0100
Subject: [PATCH 1/4] Short name resolution: introduce the required schema

Add ipaDomainResolutionOrder and ipaNameResolutionData to IPAv3 schema.
Extend ipaConfig object with ipaNameResolutionData objectclass during
update.

https://pagure.io/freeipa/issue/6372
---
 install/share/60basev3.ldif         | 2 ++
 install/updates/50-ipaconfig.update | 1 +
 2 files changed, 3 insertions(+)

diff --git a/install/share/60basev3.ldif b/install/share/60basev3.ldif
index 059174b..efc6c8a 100644
--- a/install/share/60basev3.ldif
+++ b/install/share/60basev3.ldif
@@ -57,6 +57,7 @@ attributeTypes: (2.16.840.1.113730.3.8.11.65 NAME 'ipaWrappingMech' DESC 'PKCS#1
 attributeTypes: (2.16.840.1.113730.3.8.11.70 NAME 'ipaPermTargetTo' DESC 'Destination location to move an entry IPA permission ACI' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'IPA v4.0' )
 attributeTypes: (2.16.840.1.113730.3.8.11.71 NAME 'ipaPermTargetFrom' DESC 'Source location from where moving an entry IPA permission ACI' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'IPA v4.0' )
 attributeTypes: ( 2.16.840.1.113730.3.8.11.75 NAME 'ipaNTAdditionalSuffixes' DESC 'Suffix for the user principal name associated with the domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
+attributeTypes: (2.16.840.1.113730.3.8.11.77 NAME 'ipaDomainResolutionOrder' DESC 'List of domains used to resolve a short name' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v4.5')
 attributeTypes: (2.16.840.1.113730.3.8.18.2.1 NAME 'ipaVaultType' DESC 'IPA vault type' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.2')
 attributeTypes: (2.16.840.1.113730.3.8.18.2.2 NAME 'ipaVaultSalt' DESC 'IPA vault salt' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'IPA v4.2' )
 # FIXME: https://bugzilla.redhat.com/show_bug.cgi?id=1267782
@@ -84,5 +85,6 @@ objectClasses: (2.16.840.1.113730.3.8.12.24 NAME 'ipaPublicKeyObject' DESC 'Wrap
 objectClasses: (2.16.840.1.113730.3.8.12.25 NAME 'ipaPrivateKeyObject' DESC 'Wrapped private keys' SUP top AUXILIARY MUST ( ipaPrivateKey $ ipaWrappingKey $ ipaWrappingMech ) X-ORIGIN 'IPA v4.1' )
 objectClasses: (2.16.840.1.113730.3.8.12.26 NAME 'ipaSecretKeyObject' DESC 'Wrapped secret keys' SUP top AUXILIARY MUST ( ipaSecretKey $ ipaWrappingKey $ ipaWrappingMech ) X-ORIGIN 'IPA v4.1' )
 objectClasses: (2.16.840.1.113730.3.8.12.34 NAME 'ipaSecretKeyRefObject' DESC 'Indirect storage for encoded key material' SUP top AUXILIARY MUST ( ipaSecretKeyRef ) X-ORIGIN 'IPA v4.1' )
+objectClasses: (2.16.840.1.113730.3.8.12.39 NAME 'ipaNameResolutionData' DESC 'Data used to resolve short names to fully-qualified form' SUP top AUXILIARY MAY ( ipaDomainResolutionOrder ) X-ORIGIN 'IPA v4.5')
 objectClasses: (2.16.840.1.113730.3.8.18.1.1 NAME 'ipaVault' DESC 'IPA vault' SUP top STRUCTURAL MUST ( cn ) MAY ( description $ ipaVaultType $ ipaVaultSalt $ ipaVaultPublicKey $ owner $ member ) X-ORIGIN 'IPA v4.2' )
 objectClasses: (2.16.840.1.113730.3.8.18.1.2 NAME 'ipaVaultContainer' DESC 'IPA vault container' SUP top STRUCTURAL MUST ( cn ) MAY ( description $ owner ) X-ORIGIN 'IPA v4.2' )
diff --git a/install/updates/50-ipaconfig.update b/install/updates/50-ipaconfig.update
index 89a1726..23d2919 100644
--- a/install/updates/50-ipaconfig.update
+++ b/install/updates/50-ipaconfig.update
@@ -4,3 +4,4 @@ add:ipaSELinuxUserMapDefault: unconfined_u:s0-s0:c0.c1023
 add:ipaUserObjectClasses: ipasshuser
 remove:ipaConfigString:AllowLMhash
 add:objectClass: ipaUserAuthTypeClass
+add:objectClass: ipaNameResolutionData

From f1affc6f2ca6f892e7ea8b49a070fb398daa88f2 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Thu, 9 Mar 2017 18:14:52 +0100
Subject: [PATCH 2/4] ipaconfig: add the ability to manipulate domain
 resolution order

optional attribute was added to config object along with validator that
check for valid domain names and also checks whether the specified
domains exist in FreeIPA or in trusted forests and, in case of trusted
domains, are not disabled.

Part of http://www.freeipa.org/page/V4/AD_User_Short_Names

https://pagure.io/freeipa/issue/6372
---
 ACI.txt                     |   2 +-
 API.txt                     |   3 +-
 VERSION.m4                  |   4 +-
 ipaserver/plugins/config.py | 115 +++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 118 insertions(+), 6 deletions(-)

diff --git a/ACI.txt b/ACI.txt
index a36d460..c648c14 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -61,7 +61,7 @@ aci: (targetattr = "cn || description || ipacertprofilestoreissued")(targetfilte
 dn: cn=certprofiles,cn=ca,dc=ipa,dc=example
 aci: (targetattr = "cn || createtimestamp || description || entryusn || ipacertprofilestoreissued || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipacertprofile)")(version 3.0;acl "permission:System: Read Certificate Profiles";allow (compare,read,search) userdn = "ldap:///all";;)
 dn: cn=ipaconfig,cn=etc,dc=ipa,dc=example
-aci: (targetattr = "cn || createtimestamp || entryusn || ipacertificatesubjectbase || ipaconfigstring || ipacustomfields || ipadefaultemaildomain || ipadefaultloginshell || ipadefaultprimarygroup || ipagroupobjectclasses || ipagroupsearchfields || ipahomesrootdir || ipakrbauthzdata || ipamaxusernamelength || ipamigrationenabled || ipapwdexpadvnotify || ipasearchrecordslimit || ipasearchtimelimit || ipaselinuxusermapdefault || ipaselinuxusermaporder || ipauserauthtype || ipauserobjectclasses || ipausersearchfields || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaguiconfig)")(version 3.0;acl "permission:System: Read Global Configuration";allow (compare,read,search) userdn = "ldap:///all";;)
+aci: (targetattr = "cn || createtimestamp || entryusn || ipacertificatesubjectbase || ipaconfigstring || ipacustomfields || ipadefaultemaildomain || ipadefaultloginshell || ipadefaultprimarygroup || ipadomainresolutionorder || ipagroupobjectclasses || ipagroupsearchfields || ipahomesrootdir || ipakrbauthzdata || ipamaxusernamelength || ipamigrationenabled || ipapwdexpadvnotify || ipasearchrecordslimit || ipasearchtimelimit || ipaselinuxusermapdefault || ipaselinuxusermaporder || ipauserauthtype || ipauserobjectclasses || ipausersearchfields || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaguiconfig)")(version 3.0;acl "permission:System: Read Global Configuration";allow (compare,read,search) userdn = "ldap:///all";;)
 dn: cn=costemplates,cn=accounts,dc=ipa,dc=example
 aci: (targetfilter = "(objectclass=costemplate)")(version 3.0;acl "permission:System: Add Group Password Policy costemplate";allow (add) groupdn = "ldap:///cn=System: Add Group Password Policy costemplate,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: cn=costemplates,cn=accounts,dc=ipa,dc=example
diff --git a/API.txt b/API.txt
index 90cda74..77351bd 100644
--- a/API.txt
+++ b/API.txt
@@ -1059,7 +1059,7 @@ args: 0,1,1
 option: Str('version?')
 output: Output('result')
 command: config_mod/1
-args: 0,26,3
+args: 0,27,3
 option: Str('addattr*', cli_name='addattr')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('ca_renewal_master_server?', autofill=False)
@@ -1068,6 +1068,7 @@ option: StrEnum('ipaconfigstring*', autofill=False, cli_name='ipaconfigstring',
 option: Str('ipadefaultemaildomain?', autofill=False, cli_name='emaildomain')
 option: Str('ipadefaultloginshell?', autofill=False, cli_name='defaultshell')
 option: Str('ipadefaultprimarygroup?', autofill=False, cli_name='defaultgroup')
+option: Str('ipadomainresolutionorder?', autofill=False, cli_name='domain_resolution_order')
 option: Str('ipagroupobjectclasses*', autofill=False, cli_name='groupobjectclasses')
 option: IA5Str('ipagroupsearchfields?', autofill=False, cli_name='groupsearch')
 option: IA5Str('ipahomesrootdir?', autofill=False, cli_name='homedirectory')
diff --git a/VERSION.m4 b/VERSION.m4
index f943566..4ea8976 100644
--- a/VERSION.m4
+++ b/VERSION.m4
@@ -73,8 +73,8 @@ define(IPA_DATA_VERSION, 20100614120000)
 #                                                      #
 ########################################################
 define(IPA_API_VERSION_MAJOR, 2)
-define(IPA_API_VERSION_MINOR, 220)
-# Last change: Add whoami command
+define(IPA_API_VERSION_MINOR, 221)
+# Last change: Add domain resolution order to ipaconfig
 
 
 ########################################################
diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py
index 5d57465..232c881 100644
--- a/ipaserver/plugins/config.py
+++ b/ipaserver/plugins/config.py
@@ -22,6 +22,7 @@
 from ipalib import Bool, Int, Str, IA5Str, StrEnum, DNParam
 from ipalib import errors
 from ipalib.plugable import Registry
+from ipalib.util import validate_domain_name
 from .baseldap import (
     LDAPObject,
     LDAPUpdate,
@@ -34,6 +35,8 @@
 OPERATIONAL_ATTRIBUTES = ('nsaccountlock', 'member', 'memberof',
     'memberindirect', 'memberofindirect',)
 
+DOMAIN_RESOLUTION_ORDER_SEPARATOR = u':'
+
 __doc__ = _("""
 Server configuration
 
@@ -95,7 +98,7 @@ class config(LDAPObject):
         'ipamigrationenabled', 'ipacertificatesubjectbase',
         'ipapwdexpadvnotify', 'ipaselinuxusermaporder',
         'ipaselinuxusermapdefault', 'ipaconfigstring', 'ipakrbauthzdata',
-        'ipauserauthtype'
+        'ipauserauthtype', 'ipadomainresolutionorder'
     ]
     container_dn = DN(('cn', 'ipaconfig'), ('cn', 'etc'))
     permission_filter_objectclasses = ['ipaguiconfig']
@@ -108,7 +111,8 @@ class config(LDAPObject):
                 'cn', 'objectclass',
                 'ipacertificatesubjectbase', 'ipaconfigstring',
                 'ipadefaultemaildomain', 'ipadefaultloginshell',
-                'ipadefaultprimarygroup', 'ipagroupobjectclasses',
+                'ipadefaultprimarygroup', 'ipadomainresolutionorder',
+                'ipagroupobjectclasses',
                 'ipagroupsearchfields', 'ipahomesrootdir',
                 'ipakrbauthzdata', 'ipamaxusernamelength',
                 'ipamigrationenabled', 'ipapwdexpadvnotify',
@@ -250,6 +254,13 @@ class config(LDAPObject):
             label=_('IPA CA renewal master'),
             doc=_('Renewal master for IPA certificate authority'),
             flags={'virtual_attribute', 'no_create'}
+        ),
+        Str(
+            'ipadomainresolutionorder?',
+            cli_name='domain_resolution_order',
+            label=_('Domain resolution order'),
+            doc=_('colon-separated list of domains used for short name'
+                  ' qualification')
         )
     )
 
@@ -266,6 +277,104 @@ def show_servroles_attributes(self, entry_attrs, **options):
             config = backend.config_retrieve(role)
             entry_attrs.update(config)
 
+    def gather_trusted_domains(self):
+        """
+        Aggregate all trusted domains into a dict keyed by domain names with
+        values corresponding to domain status (enabled/disabled)
+        """
+        command = self.api.Command
+        try:
+            ad_forests = command.trust_find(sizelimit=0)['result']
+        except errors.NotFound:
+            return {}
+
+        trusted_domains = {}
+        for forest_name in [a['cn'][0] for a in ad_forests]:
+            forest_domains = command.trustdomain_find(
+                forest_name, sizelimit=0)['result']
+
+            trusted_domains.update(
+                {
+                    dom['cn'][0]: dom['domain_enabled'][0]
+                    for dom in forest_domains if 'domain_enabled' in dom
+                }
+            )
+
+        return trusted_domains
+
+    def _validate_single_domain(self, attr_name, domain, known_domains):
+        """
+        Validate a single domain from domain resolution order
+
+        :param attr_name: name of attribute that holds domain resolution order
+        :param domain: domain name
+        :param known_domains: dict of domains known to IPA keyed by domain name
+            and valued by boolean value corresponding to domain status
+            (enabled/disabled)
+
+        :raises: ValidationError if the domain name is empty, syntactically
+            invalid or corresponds to a disable domain
+                 NotFound if a syntactically correct domain name unknown to IPA
+                 is supplied (not IPA domain and not any of trusted domains)
+        """
+        if not domain:
+            raise errors.ValidationError(
+                name=attr_name,
+                error=_("Empty domain is not allowed")
+            )
+
+        try:
+            validate_domain_name(domain)
+        except ValueError as e:
+            raise errors.ValidationError(
+                name=attr_name,
+                error=_("Invalid domain name '%(domain)s': %(e)s")
+                % dict(domain=domain, e=e))
+
+        if domain not in known_domains:
+            raise errors.NotFound(
+                reason=_("Server has no information about domain '%(domain)s'")
+                % dict(domain=domain)
+            )
+
+        if not known_domains[domain]:
+            raise errors.ValidationError(
+                name=attr_name,
+                error=_("Disabled domain '%(domain)s' is not allowed")
+                % dict(domain=domain)
+            )
+
+    def validate_domain_resolution_order(self, entry_attrs):
+        """
+        Validate domain resolution order, e.g. split by the delimiter (colon)
+        and check each domain name for non-emptiness, syntactic correctness,
+        and status (enabled/disabled).
+
+        supplying empty order (':') bypasses validations and allows to specify
+        empty attribute value.
+        """
+        attr_name = 'ipadomainresolutionorder'
+        if attr_name not in entry_attrs:
+            return
+
+        domain_resolution_order = entry_attrs[attr_name]
+
+        # empty resolution order is signalized by single separator, do nothing
+        # and let it pass
+        if domain_resolution_order == DOMAIN_RESOLUTION_ORDER_SEPARATOR:
+            return
+
+        submitted_domains = domain_resolution_order.split(
+                DOMAIN_RESOLUTION_ORDER_SEPARATOR)
+
+        known_domains = self.gather_trusted_domains()
+
+        # add FreeIPA domain to the list of domains. This one is always enabled
+        known_domains.update({self.api.env.domain: True})
+
+        for domain in submitted_domains:
+            self._validate_single_domain(attr_name, domain, known_domains)
+
 
 @register()
 class config_mod(LDAPUpdate):
@@ -396,6 +505,8 @@ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
             backend = self.api.Backend.serverroles
             backend.config_update(ca_renewal_master_server=new_master)
 
+        self.obj.validate_domain_resolution_order(entry_attrs)
+
         return dn
 
     def exc_callback(self, keys, options, exc, call_func,

From cd920327d53b4e98a8ede8c2280e64524dbc615c Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Thu, 9 Mar 2017 19:02:49 +0100
Subject: [PATCH 3/4] idview: add domain_resolution_order attribute

`idview-add` and `idview-mod` can now set and validate the attribute.
The required objectclass is added on-demand after modification

https://pagure.io/freeipa/issue/6372
---
 ACI.txt                      |  2 +-
 API.txt                      |  6 ++++--
 VERSION.m4                   |  4 ++--
 ipaserver/plugins/idviews.py | 33 +++++++++++++++++++++++++++++++--
 4 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/ACI.txt b/ACI.txt
index c648c14..02c4821 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -179,7 +179,7 @@ aci: (targetattr = "createtimestamp || description || entryusn || gecos || gidnu
 dn: cn=ranges,cn=etc,dc=ipa,dc=example
 aci: (targetattr = "cn || createtimestamp || entryusn || ipabaseid || ipabaserid || ipaidrangesize || ipanttrusteddomainsid || iparangetype || ipasecondarybaserid || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaidrange)")(version 3.0;acl "permission:System: Read ID Ranges";allow (compare,read,search) userdn = "ldap:///all";;)
 dn: cn=views,cn=accounts,dc=ipa,dc=example
-aci: (targetattr = "cn || createtimestamp || description || entryusn || modifytimestamp || objectclass")(targetfilter = "(objectclass=nsContainer)")(version 3.0;acl "permission:System: Read ID Views";allow (compare,read,search) userdn = "ldap:///all";;)
+aci: (targetattr = "cn || createtimestamp || description || entryusn || ipadomainresolutionorder || modifytimestamp || objectclass")(targetfilter = "(objectclass=nsContainer)")(version 3.0;acl "permission:System: Read ID Views";allow (compare,read,search) userdn = "ldap:///all";;)
 dn: cn=IPA.EXAMPLE,cn=kerberos,dc=ipa,dc=example
 aci: (targetattr = "createtimestamp || entryusn || krbdefaultencsalttypes || krbmaxrenewableage || krbmaxticketlife || krbsupportedencsalttypes || modifytimestamp || objectclass")(targetfilter = "(objectclass=krbticketpolicyaux)")(version 3.0;acl "permission:System: Read Default Kerberos Ticket Policy";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Default Kerberos Ticket Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: cn=users,cn=accounts,dc=ipa,dc=example
diff --git a/API.txt b/API.txt
index 77351bd..180478c 100644
--- a/API.txt
+++ b/API.txt
@@ -3036,11 +3036,12 @@ output: Entry('result')
 output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
 output: PrimaryKey('value')
 command: idview_add/1
-args: 1,6,3
+args: 1,7,3
 arg: Str('cn', cli_name='name')
 option: Str('addattr*', cli_name='addattr')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('description?', cli_name='desc')
+option: Str('ipadomainresolutionorder?', cli_name='domain_resolution_order')
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Str('setattr*', cli_name='setattr')
 option: Str('version?')
@@ -3081,12 +3082,13 @@ output: ListOfEntries('result')
 output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
 output: Output('truncated', type=[<type 'bool'>])
 command: idview_mod/1
-args: 1,9,3
+args: 1,10,3
 arg: Str('cn', cli_name='name')
 option: Str('addattr*', cli_name='addattr')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('delattr*', cli_name='delattr')
 option: Str('description?', autofill=False, cli_name='desc')
+option: Str('ipadomainresolutionorder?', autofill=False, cli_name='domain_resolution_order')
 option: Flag('raw', autofill=True, cli_name='raw', default=False)
 option: Str('rename?', cli_name='rename')
 option: Flag('rights', autofill=True, default=False)
diff --git a/VERSION.m4 b/VERSION.m4
index 4ea8976..685271a 100644
--- a/VERSION.m4
+++ b/VERSION.m4
@@ -73,8 +73,8 @@ define(IPA_DATA_VERSION, 20100614120000)
 #                                                      #
 ########################################################
 define(IPA_API_VERSION_MAJOR, 2)
-define(IPA_API_VERSION_MINOR, 221)
-# Last change: Add domain resolution order to ipaconfig
+define(IPA_API_VERSION_MINOR, 222)
+# Last change: Add domain resolution order to ID views
 
 
 ########################################################
diff --git a/ipaserver/plugins/idviews.py b/ipaserver/plugins/idviews.py
index b38a4ad..7320432 100644
--- a/ipaserver/plugins/idviews.py
+++ b/ipaserver/plugins/idviews.py
@@ -95,7 +95,8 @@ class idview(LDAPObject):
     object_name = _('ID View')
     object_name_plural = _('ID Views')
     object_class = ['ipaIDView', 'top']
-    default_attributes = ['cn', 'description']
+    possible_objectclasses = ['ipaNameResolutionData']
+    default_attributes = ['cn', 'description', 'ipadomainresolutionorder']
     rdn_is_primary_key = True
 
     label = _('ID Views')
@@ -123,6 +124,14 @@ class idview(LDAPObject):
             label=_('Hosts the view applies to'),
             flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
         ),
+        Str(
+            'ipadomainresolutionorder?',
+            cli_name='domain_resolution_order',
+            label=_('Domain resolution order'),
+            doc=_('colon-separated list of domains used for short name'
+                  ' qualification'),
+            flags={'no_search'}
+        )
     )
 
     permission_filter_objectclasses = ['nsContainer']
@@ -131,17 +140,34 @@ class idview(LDAPObject):
             'ipapermbindruletype': 'all',
             'ipapermright': {'read', 'search', 'compare'},
             'ipapermdefaultattr': {
-                'cn', 'description', 'objectClass',
+                'cn', 'description', 'ipadomainresolutionorder', 'objectClass',
             },
         },
     }
 
+    def ensure_possible_objectclasses(self, ldap, dn, entry_attrs):
+        orig_entry_attrs = ldap.get_entry(dn, ['objectclass'])
+
+        orig_objectclasses = {
+            o.lower() for o in orig_entry_attrs.get('objectclass', [])}
+
+        entry_attrs['objectclass'] = orig_entry_attrs['objectclass']
+
+        for obj_class_name in self.possible_objectclasses:
+            if obj_class_name.lower() not in orig_objectclasses:
+                entry_attrs['objectclass'].append(obj_class_name)
+
 
 @register()
 class idview_add(LDAPCreate):
     __doc__ = _('Add a new ID View.')
     msg_summary = _('Added ID View "%(value)s"')
 
+    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+        self.api.Object.config.validate_domain_resolution_order(entry_attrs)
+
+        return dn
+
 
 @register()
 class idview_del(LDAPDelete):
@@ -166,6 +192,9 @@ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
             if key.lower() == DEFAULT_TRUST_VIEW_NAME:
                 raise protected_default_trust_view_error
 
+        self.api.Object.config.validate_domain_resolution_order(entry_attrs)
+        self.obj.ensure_possible_objectclasses(ldap, dn, entry_attrs)
+
         return dn
 
 

From a6158e9f8bc0f5c2842d3f46140f300a04a24f0e Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Tue, 14 Mar 2017 13:57:43 +0100
Subject: [PATCH 4/4] Re-use trust domain retrieval code in certmap validators

https://pagure.io/freeipa/issue/6372
---
 ipaserver/plugins/certmap.py | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/ipaserver/plugins/certmap.py b/ipaserver/plugins/certmap.py
index e28b397..917463f 100644
--- a/ipaserver/plugins/certmap.py
+++ b/ipaserver/plugins/certmap.py
@@ -100,16 +100,11 @@ def check_associateddomain_is_trusted(api_inst, options):
     """
     domains = options.get('associateddomain')
     if domains:
-        trust_suffix_namespace = set()
+        trusted_domains = api_inst.Object.config.gather_trusted_domains()
+        trust_suffix_namespace = {dom_name.lower() for dom_name in
+                                  trusted_domains}
         trust_suffix_namespace.add(api_inst.env.domain.lower())
 
-        trust_objects = api_inst.Command.trust_find(sizelimit=0)['result']
-        for obj in trust_objects:
-            trustdomains = api_inst.Command.trustdomain_find(
-                obj['cn'][0], sizelimit=0)['result']
-            for domain in trustdomains:
-                trust_suffix_namespace.add(domain['cn'][0].lower())
-
         for dom in domains:
             if not str(dom).lower() in trust_suffix_namespace:
                 raise errors.ValidationError(
-- 
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