On 07/11/2016 01:04 PM, Alexander Bokovoy wrote:
On Mon, 11 Jul 2016, Martin Babinsky wrote:
From 7742cab5aebb26b3a82baac379be01120c95c400 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 1 Jul 2016 18:09:04 +0200
Subject: [PATCH] Preserve user principal aliases during rename operation

When a MODRDN is performed on the user entry, the MODRDN plugin resets
both
krbPrincipalName and krbCanonicalName to the value constructed from
uid. In
doing so, hovewer, any principal aliases added to the krbPrincipalName
are
wiped clean. In this patch old aliases are fetched before the MODRDN
operation
takes place and inserted back after it is performed.

This also preserves previous user logins which can be used further for
authentication as aliases.

https://fedorahosted.org/freeipa/ticket/6028
---
ipaserver/plugins/baseuser.py | 49
+++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)

diff --git a/ipaserver/plugins/baseuser.py
b/ipaserver/plugins/baseuser.py
index
0052e718afe639bcc1c0a698ded39ea8407a0551..1d07284181e9db84609642cd61837fd8c23778af
100644
--- a/ipaserver/plugins/baseuser.py
+++ b/ipaserver/plugins/baseuser.py
@@ -498,6 +498,53 @@ class baseuser_mod(LDAPUpdate):
                            len =
int(config.get('ipamaxusernamelength')[0])
                        )
                    )
+
+    def preserve_krbprincipalname_pre(self, ldap, entry_attrs, *keys,
**options):
+        """
+        preserve user principal aliases during rename operation. This
is the
+        pre-callback part of this. Another method called during
post-callback
+        shall insert the principals back
+        """
+        if options.get('rename') is None:
+            return
+
+        try:
+            old_entry = ldap.get_entry(
+                entry_attrs.dn, attrs_list=(
+                    'krbprincipalname', 'krbcanonicalname'))
+
+            if 'krbcanonicalname' not in old_entry:
+                return
+        except errors.NotFound:
+            self.obj.handle_not_found(*keys)
+
+        self.context.krbprincipalname = old_entry.get(
+            'krbprincipalname', [])
+        self.log.critical(
+            "krbprincipalname pre:
{}".format(self.context.krbprincipalname))
+
+    def preserve_krbprincipalname_post(self, ldap, entry_attrs,
**options):
+        """
+        Insert the preserved aliases back to the user entry during
rename
+        operation
+        """
+        if options.get('rename') is None or not hasattr(
+                self.context, 'krbprincipalname'):
+            return
+
+        self.log.critical(
+            "krbprincipalname post:
{}".format(self.context.krbprincipalname))
+        new_aliases = entry_attrs.get('krbprincipalname', [])
+
+        new_aliases.extend(self.context.krbprincipalname)
+        entry_attrs['krbprincipalname'] = new_aliases
+        effective_rights = entry_attrs.pop('attributelevelrights', [])
+
+        ldap.update_entry(entry_attrs)
+
+        if effective_rights:
+            entry_attrs['attributelevelrights'] = effective_rights
Why do you need to mess with effective rights here?

Can you describe what happens on update that you need to drop them in
the entry_attrs?

+
    def check_mail(self, entry_attrs):
        if 'mail' in entry_attrs:
            entry_attrs['mail'] =
self.obj.normalize_and_validate_email(entry_attrs['mail'])
@@ -557,9 +604,11 @@ class baseuser_mod(LDAPUpdate):

        self.check_objectclass(ldap, dn, entry_attrs)
        self.obj.convert_usercertificate_pre(entry_attrs)
+        self.preserve_krbprincipalname_pre(ldap, entry_attrs, *keys,
**options)

    def post_common_callback(self, ldap, dn, entry_attrs, *keys,
**options):
        assert isinstance(dn, DN)
+        self.preserve_krbprincipalname_post(ldap, entry_attrs,
**options)
        if options.get('random', False):
            try:
                entry_attrs['randompassword'] =
unicode(getattr(context, 'randompassword'))
--
2.5.5




Shame on me for not using API written by myself for adding principal aliases back to the user! Shame!

I have rewritten the `preserve_krbprincipalname_post` to use 'user_add_principal' to inject the missing aliases back to the entry, hence no other obscure shenanigans are needed other than plugging the new values to the displayed result.

Also the code should be robust enough to handle renaming the user and back and keep all his aliases while changing canonical name to correct value.

--
Martin^3 Babinsky
From 185bde00a76459430d95ff207bf1fb3fe31e811a Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 1 Jul 2016 18:09:04 +0200
Subject: [PATCH] Preserve user principal aliases during rename operation

When a MODRDN is performed on the user entry, the MODRDN plugin resets both
krbPrincipalName and krbCanonicalName to the value constructed from uid. In
doing so, hovewer, any principal aliases added to the krbPrincipalName are
wiped clean. In this patch old aliases are fetched before the MODRDN operation
takes place and inserted back after it is performed.

This also preserves previous user logins which can be used further for
authentication as aliases.

https://fedorahosted.org/freeipa/ticket/6028
---
 ipaserver/plugins/baseuser.py | 46 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py
index 0052e718afe639bcc1c0a698ded39ea8407a0551..e4288a5a131157815ffb2452692a7edb342f6ac3 100644
--- a/ipaserver/plugins/baseuser.py
+++ b/ipaserver/plugins/baseuser.py
@@ -498,6 +498,50 @@ class baseuser_mod(LDAPUpdate):
                             len = int(config.get('ipamaxusernamelength')[0])
                         )
                     )
+
+    def preserve_krbprincipalname_pre(self, ldap, entry_attrs, *keys, **options):
+        """
+        preserve user principal aliases during rename operation. This is the
+        pre-callback part of this. Another method called during post-callback
+        shall insert the principals back
+        """
+        if options.get('rename', None) is None:
+            return
+
+        try:
+            old_entry = ldap.get_entry(
+                entry_attrs.dn, attrs_list=(
+                    'krbprincipalname', 'krbcanonicalname'))
+
+            if 'krbcanonicalname' not in old_entry:
+                return
+        except errors.NotFound:
+            self.obj.handle_not_found(*keys)
+
+        self.context.krbprincipalname = old_entry.get(
+            'krbprincipalname', [])
+
+    def preserve_krbprincipalname_post(self, ldap, entry_attrs, **options):
+        """
+        Insert the preserved aliases back to the user entry during rename
+        operation
+        """
+        if options.get('rename', None) is None or not hasattr(
+                self.context, 'krbprincipalname'):
+            return
+
+        obj_pkey = self.obj.get_primary_key_from_dn(entry_attrs.dn)
+        canonical_name = entry_attrs['krbcanonicalname'][0]
+
+        principals_to_add = tuple(p for p in self.context.krbprincipalname if
+                                  p != canonical_name)
+
+        if principals_to_add:
+            result = self.api.Command.user_add_principal(
+                obj_pkey, principals_to_add)['result']
+
+            entry_attrs['krbprincipalname'] = result.get('krbprincipalname', [])
+
     def check_mail(self, entry_attrs):
         if 'mail' in entry_attrs:
             entry_attrs['mail'] = self.obj.normalize_and_validate_email(entry_attrs['mail'])
@@ -557,9 +601,11 @@ class baseuser_mod(LDAPUpdate):
 
         self.check_objectclass(ldap, dn, entry_attrs)
         self.obj.convert_usercertificate_pre(entry_attrs)
+        self.preserve_krbprincipalname_pre(ldap, entry_attrs, *keys, **options)
 
     def post_common_callback(self, ldap, dn, entry_attrs, *keys, **options):
         assert isinstance(dn, DN)
+        self.preserve_krbprincipalname_post(ldap, entry_attrs, **options)
         if options.get('random', False):
             try:
                 entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword'))
-- 
2.5.5

-- 
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