URL: https://github.com/freeipa/freeipa/pull/420
Author: martbab
 Title: #420: WIP: Allow login to WebUI using Kerberos aliases/enterprise 
principals
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/420/head:pr420
git checkout pr420
From 0061ffcdd28c86106f71f5fb20c1715593229bd4 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Thu, 22 Sep 2016 09:58:47 +0200
Subject: [PATCH] Allow login to WebUI using Kerberos aliases/enterprise
 principals

The logic of the extraction/validation of principal from the request and
subsequent authentication was simplified and most of the guesswork will
be done by KDC during kinit. This also allows principals from trusted
domains to login via rpcserver.

https://fedorahosted.org/freeipa/ticket/6343
---
 ipalib/krb_utils.py    | 14 --------------
 ipaserver/rpcserver.py | 50 ++++++++++++++++----------------------------------
 2 files changed, 16 insertions(+), 48 deletions(-)

diff --git a/ipalib/krb_utils.py b/ipalib/krb_utils.py
index 47d24c9..471009c 100644
--- a/ipalib/krb_utils.py
+++ b/ipalib/krb_utils.py
@@ -79,20 +79,6 @@ def krb5_parse_ccache(ccache_name):
 def krb5_unparse_ccache(scheme, name):
     return '%s:%s' % (scheme.upper(), name)
 
-def krb5_format_principal_name(user, realm):
-    '''
-    Given a Kerberos user principal name and a Kerberos realm
-    return the Kerberos V5 user principal name.
-
-    :parameters:
-      user
-        User principal name.
-      realm
-        The Kerberos realm the user exists in.
-    :returns:
-      Kerberos V5 user principal name.
-    '''
-    return '%s@%s' % (user, realm)
 
 def krb5_format_service_principal_name(service, host, realm):
     '''
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index 25f2740..983ab62 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -50,13 +50,12 @@
 from ipalib.request import context, destroy_context
 from ipalib.rpc import (xml_dumps, xml_loads,
     json_encode_binary, json_decode_binary)
-from ipalib.util import normalize_name
 from ipapython.dn import DN
 from ipaserver.plugins.ldap2 import ldap2
 from ipalib.backend import Backend
 from ipalib.krb_utils import (
-    krb5_format_principal_name,
     get_credentials_if_valid)
+from ipapython import kerberos
 from ipapython import ipautil
 from ipaplatform.paths import paths
 from ipapython.version import VERSION
@@ -872,33 +871,15 @@ def __call__(self, environ, start_response):
             return self.bad_request(environ, start_response, "no user specified")
 
         # allows login in the form user@SERVER_REALM or user@server_realm
-        # FIXME: uppercasing may be removed when better handling of UPN
-        #        is introduced
-
-        parts = normalize_name(user)
-
-        if "domain" in parts:
-            # username is of the form user@SERVER_REALM or user@server_realm
-
-            # check whether the realm is server's realm
-            # Users from other realms are not supported
-            # (they do not have necessary LDAP entry, LDAP connect will fail)
-
-            if parts["domain"].upper()==self.api.env.realm:
-                user=parts["name"]
-            else:
-                return self.unauthorized(environ, start_response, '', 'denied')
-
-        elif "flatname" in parts:
-            # username is of the form NetBIOS\user
-            return self.unauthorized(environ, start_response, '', 'denied')
-
-        else:
+        try:
+            user_principal = kerberos.Principal(user)
+        except Exception:
             # username is of the form user or of some wild form, e.g.
-            # user@REALM1@REALM2 or NetBIOS1\NetBIOS2\user (see normalize_name)
+            # user@REALM1@REALM2 or NetBIOS1\NetBIOS2\user
+            return self.unauthorized(environ, start_response, '', 'denied')
 
-            # wild form username will fail at kinit, so nothing needs to be done
-            pass
+        if not (user_principal.is_user or user_principal.is_enterprise):
+            return self.unauthorized(environ, start_response, '', 'denied')
 
         password = query_dict.get('password', None)
         if password is not None:
@@ -918,7 +899,7 @@ def __call__(self, environ, start_response):
         except OSError:
             pass
         try:
-            self.kinit(user, self.api.env.realm, password, ipa_ccache_name)
+            self.kinit(unicode(user_principal), password, ipa_ccache_name)
         except PasswordExpired as e:
             return self.unauthorized(environ, start_response, str(e), 'password-expired')
         except InvalidSessionPassword as e:
@@ -944,7 +925,7 @@ def __call__(self, environ, start_response):
             pass
         return result
 
-    def kinit(self, user, realm, password, ccache_name):
+    def kinit(self, principal, password, ccache_name):
         # get anonymous ccache as an armor for FAST to enable OTP auth
         armor_path = os.path.join(paths.IPA_CCACHES,
                                   "armor_{}".format(os.getpid()))
@@ -958,12 +939,13 @@ def kinit(self, user, realm, password, ccache_name):
             # We try to continue w/o armor, 2FA will be impacted
             armor_path = None
 
-        # Format the user as a kerberos principal
-        principal = krb5_format_principal_name(user, realm)
-
         try:
-            kinit_password(principal, password, ccache_name,
-                           armor_ccache_name=armor_path)
+            kinit_password(
+                unicode(principal),
+                password,
+                ccache_name,
+                armor_ccache_name=armor_path,
+                enterprise=True)
 
             if armor_path:
                 self.debug('Cleanup the armor ccache')
-- 
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