mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
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 Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Simo Sorce <ssorce@redhat.com> Reviewed-By: David Kupka <dkupka@redhat.com>
This commit is contained in:
parent
1e912f5b83
commit
f8d7e37a09
@ -79,20 +79,6 @@ def krb5_parse_ccache(ccache_name):
|
|||||||
def krb5_unparse_ccache(scheme, name):
|
def krb5_unparse_ccache(scheme, name):
|
||||||
return '%s:%s' % (scheme.upper(), 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):
|
def krb5_format_service_principal_name(service, host, realm):
|
||||||
'''
|
'''
|
||||||
|
@ -50,13 +50,12 @@ from ipalib.errors import (PublicError, InternalError, JSONError,
|
|||||||
from ipalib.request import context, destroy_context
|
from ipalib.request import context, destroy_context
|
||||||
from ipalib.rpc import (xml_dumps, xml_loads,
|
from ipalib.rpc import (xml_dumps, xml_loads,
|
||||||
json_encode_binary, json_decode_binary)
|
json_encode_binary, json_decode_binary)
|
||||||
from ipalib.util import normalize_name
|
|
||||||
from ipapython.dn import DN
|
from ipapython.dn import DN
|
||||||
from ipaserver.plugins.ldap2 import ldap2
|
from ipaserver.plugins.ldap2 import ldap2
|
||||||
from ipalib.backend import Backend
|
from ipalib.backend import Backend
|
||||||
from ipalib.krb_utils import (
|
from ipalib.krb_utils import (
|
||||||
krb5_format_principal_name,
|
|
||||||
get_credentials_if_valid)
|
get_credentials_if_valid)
|
||||||
|
from ipapython import kerberos
|
||||||
from ipapython import ipautil
|
from ipapython import ipautil
|
||||||
from ipaplatform.paths import paths
|
from ipaplatform.paths import paths
|
||||||
from ipapython.version import VERSION
|
from ipapython.version import VERSION
|
||||||
@ -872,34 +871,15 @@ class login_password(Backend, KerberosSession):
|
|||||||
return self.bad_request(environ, start_response, "no user specified")
|
return self.bad_request(environ, start_response, "no user specified")
|
||||||
|
|
||||||
# allows login in the form user@SERVER_REALM or user@server_realm
|
# allows login in the form user@SERVER_REALM or user@server_realm
|
||||||
# FIXME: uppercasing may be removed when better handling of UPN
|
# we kinit as enterprise principal so we can assume that unknown realms
|
||||||
# is introduced
|
# are UPN
|
||||||
|
try:
|
||||||
parts = normalize_name(user)
|
user_principal = kerberos.Principal(user)
|
||||||
|
except Exception:
|
||||||
if "domain" in parts:
|
# the principal is malformed in some way (e.g. user@REALM1@REALM2)
|
||||||
# username is of the form user@SERVER_REALM or user@server_realm
|
# netbios names (NetBIOS1\user) are also not accepted (yet)
|
||||||
|
|
||||||
# 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')
|
return self.unauthorized(environ, start_response, '', 'denied')
|
||||||
|
|
||||||
else:
|
|
||||||
# username is of the form user or of some wild form, e.g.
|
|
||||||
# user@REALM1@REALM2 or NetBIOS1\NetBIOS2\user (see normalize_name)
|
|
||||||
|
|
||||||
# wild form username will fail at kinit, so nothing needs to be done
|
|
||||||
pass
|
|
||||||
|
|
||||||
password = query_dict.get('password', None)
|
password = query_dict.get('password', None)
|
||||||
if password is not None:
|
if password is not None:
|
||||||
if len(password) == 1:
|
if len(password) == 1:
|
||||||
@ -918,7 +898,7 @@ class login_password(Backend, KerberosSession):
|
|||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
self.kinit(user, self.api.env.realm, password, ipa_ccache_name)
|
self.kinit(user_principal, password, ipa_ccache_name)
|
||||||
except PasswordExpired as e:
|
except PasswordExpired as e:
|
||||||
return self.unauthorized(environ, start_response, str(e), 'password-expired')
|
return self.unauthorized(environ, start_response, str(e), 'password-expired')
|
||||||
except InvalidSessionPassword as e:
|
except InvalidSessionPassword as e:
|
||||||
@ -944,7 +924,7 @@ class login_password(Backend, KerberosSession):
|
|||||||
pass
|
pass
|
||||||
return result
|
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
|
# get anonymous ccache as an armor for FAST to enable OTP auth
|
||||||
armor_path = os.path.join(paths.IPA_CCACHES,
|
armor_path = os.path.join(paths.IPA_CCACHES,
|
||||||
"armor_{}".format(os.getpid()))
|
"armor_{}".format(os.getpid()))
|
||||||
@ -958,12 +938,13 @@ class login_password(Backend, KerberosSession):
|
|||||||
# We try to continue w/o armor, 2FA will be impacted
|
# We try to continue w/o armor, 2FA will be impacted
|
||||||
armor_path = None
|
armor_path = None
|
||||||
|
|
||||||
# Format the user as a kerberos principal
|
|
||||||
principal = krb5_format_principal_name(user, realm)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
kinit_password(principal, password, ccache_name,
|
kinit_password(
|
||||||
armor_ccache_name=armor_path)
|
unicode(principal),
|
||||||
|
password,
|
||||||
|
ccache_name,
|
||||||
|
armor_ccache_name=armor_path,
|
||||||
|
enterprise=True)
|
||||||
|
|
||||||
if armor_path:
|
if armor_path:
|
||||||
self.debug('Cleanup the armor ccache')
|
self.debug('Cleanup the armor ccache')
|
||||||
|
Loading…
Reference in New Issue
Block a user