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

PR body:
"""
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 allows for using principal aliases/enterprise
principals to log into WebUI and also lays foundation for enabling logons from
users from trusted domains.

https://fedorahosted.org/freeipa/ticket/6343
"""

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 ca157deb6206221267f2136d455a9cfae9382599 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Thu, 22 Sep 2016 09:58:47 +0200
Subject: [PATCH] WIP: 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.

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

diff --git a/ipalib/krb_utils.py b/ipalib/krb_utils.py
index d005a87..14b1ccb 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 1da4ec4..5048f63 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -51,7 +51,7 @@
 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 parse_time_duration, normalize_name
+from ipalib.util import parse_time_duration
 from ipapython.dn import DN
 from ipaserver.plugins.ldap2 import ldap2
 from ipaserver.session import (
@@ -60,8 +60,9 @@
     default_max_session_duration, krbccache_dir, krbccache_prefix)
 from ipalib.backend import Backend
 from ipalib.krb_utils import (
-    krb_ticket_expiration_threshold, krb5_format_principal_name,
+    krb_ticket_expiration_threshold,
     krb5_format_service_principal_name, get_credentials, get_credentials_if_valid)
+from ipapython import kerberos
 from ipapython import ipautil
 from ipaplatform.paths import paths
 from ipapython.version import VERSION
@@ -937,33 +938,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:
@@ -977,7 +960,7 @@ def __call__(self, environ, start_response):
         # Get the ccache we'll use and attempt to get credentials in it with user,password
         ipa_ccache_name = get_ipa_ccache_name()
         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:
@@ -995,12 +978,12 @@ def __call__(self, environ, start_response):
 
         return self.finalize_kerberos_acquisition('login_password', ipa_ccache_name, environ, start_response)
 
-    def kinit(self, user, realm, password, ccache_name):
+    def kinit(self, principal, password, ccache_name):
         # get http service ccache as an armor for FAST to enable OTP authentication
         armor_principal = str(krb5_format_service_principal_name(
-            'HTTP', self.api.env.host, realm))
+            'HTTP', self.api.env.host, self.api.env.realm))
         keytab = paths.IPA_KEYTAB
-        armor_name = "%sA_%s" % (krbccache_prefix, user)
+        armor_name = "%sA_%s" % (krbccache_prefix, principal)
         armor_path = os.path.join(krbccache_dir, armor_name)
 
         self.debug('Obtaining armor ccache: principal=%s keytab=%s ccache=%s',
@@ -1011,12 +994,13 @@ def kinit(self, user, realm, password, ccache_name):
         except gssapi.exceptions.GSSError as e:
             raise CCacheError(message=unicode(e))
 
-        # 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)
 
             self.debug('Cleanup the armor ccache')
             ipautil.run(
-- 
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