mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Implement password based session login
* Adjust URL's - rename /ipa/login -> /ipa/session/login_kerberos - add /ipa/session/login_password * Adjust Kerberos protection on URL's in ipa.conf * Bump VERSION in httpd ipa.conf to pick up session changes. * Adjust login URL in ipa.js * Add InvalidSessionPassword to errors.py * Rename krblogin class to login_kerberos for consistency with new login_password class * Implement login_password.kinit() method which invokes /usr/bin/kinit as a subprocess * Add login_password class for WSGI dispatch, accepts POST application/x-www-form-urlencoded user & password parameters. We form the Kerberos principal from the server's realm. * Add function krb5_unparse_ccache() * Refactor code to share common code * Clean up use of ccache names, be consistent * Replace read_krbccache_file(), store_krbccache_file(), delete_krbccache_file() with load_ccache_data(), bind_ipa_ccache(), release_ipa_ccache(). bind_ipa_ccache() now sets environment KRB5CCNAME variable. release_ipa_ccache() now clears environment KRB5CCNAME variable. * ccache names should now support any ccache storage scheme, not just FILE based ccaches * Add utilies to return HTTP status from wsgi handlers, use constants for HTTP status code for consistency. Use utilies for returning from wsgi handlers rather than duplicated code. * Add KerberosSession.finalize_kerberos_acquisition() method so different login handlers can share common code. * add Requires: krb5-workstation to server (server now calls kinit) * Fix test_rpcserver.py to use new dispatch inside route() method https://fedorahosted.org/freeipa/ticket/2095
This commit is contained in:
committed by
Rob Crittenden
parent
059a90702e
commit
ee780df13c
@@ -612,6 +612,13 @@ class SessionError(AuthenticationError):
|
||||
format= _('Session error')
|
||||
|
||||
|
||||
class InvalidSessionPassword(SessionError):
|
||||
"""
|
||||
**1201** Raised when we cannot obtain a TGT for a principal.
|
||||
"""
|
||||
errno = 1201
|
||||
format= _('Principal %(principal)s cannot be authenticated: %(message)s')
|
||||
|
||||
##############################################################################
|
||||
# 2000 - 2999: Authorization errors
|
||||
class AuthorizationError(PublicError):
|
||||
|
||||
@@ -42,7 +42,7 @@ ccache_name_re = re.compile(r'^((\w+):)?(.+)')
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
def krb5_parse_ccache(name):
|
||||
def krb5_parse_ccache(ccache_name):
|
||||
'''
|
||||
Given a Kerberos ccache name parse it into it's scheme and
|
||||
location components. Currently valid values for the scheme
|
||||
@@ -55,12 +55,12 @@ def krb5_parse_ccache(name):
|
||||
does not exist it defaults to FILE.
|
||||
|
||||
:parameters:
|
||||
name
|
||||
ccache_name
|
||||
The name of the Kerberos ccache.
|
||||
:returns:
|
||||
A two-tuple of (scheme, ccache)
|
||||
'''
|
||||
match = ccache_name_re.search(name)
|
||||
match = ccache_name_re.search(ccache_name)
|
||||
if match:
|
||||
scheme = match.group(2)
|
||||
location = match.group(3)
|
||||
@@ -71,7 +71,10 @@ def krb5_parse_ccache(name):
|
||||
|
||||
return scheme, location
|
||||
else:
|
||||
raise ValueError('Invalid ccache name = "%s"' % name)
|
||||
raise ValueError('Invalid ccache name = "%s"' % ccache_name)
|
||||
|
||||
def krb5_unparse_ccache(scheme, name):
|
||||
return '%s:%s' % (scheme.upper(), name)
|
||||
|
||||
def krb5_format_principal_name(user, realm):
|
||||
'''
|
||||
@@ -388,5 +391,5 @@ class KRB5_CCache(object):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
self.debug('"%s" ccache endtime=%s (%s)', self.ccache_str(), result, krb5_format_time(result))
|
||||
self.debug('KRB5_CCache %s endtime=%s (%s)', self.ccache_str(), result, krb5_format_time(result))
|
||||
return result
|
||||
|
||||
@@ -1197,34 +1197,71 @@ class MemcacheSessionManager(SessionManager):
|
||||
krbccache_dir ='/var/run/ipa_memcached'
|
||||
krbccache_prefix = 'krbcc_'
|
||||
|
||||
def get_krbccache_pathname():
|
||||
def _get_krbccache_pathname():
|
||||
return os.path.join(krbccache_dir, '%s%s' % (krbccache_prefix, os.getpid()))
|
||||
|
||||
def read_krbccache_file(krbccache_pathname):
|
||||
root_logger.debug('reading krbccache data from "%s"', krbccache_pathname)
|
||||
src = open(krbccache_pathname)
|
||||
ccache_data = src.read()
|
||||
src.close()
|
||||
return ccache_data
|
||||
def get_ipa_ccache_name(scheme='FILE'):
|
||||
if scheme == 'FILE':
|
||||
name = os.path.join(krbccache_dir, '%s%s' % (krbccache_prefix, os.getpid()))
|
||||
else:
|
||||
raise ValueError('ccache scheme "%s" unsupported', scheme)
|
||||
|
||||
def store_krbccache_file(ccache_data):
|
||||
krbccache_pathname = get_krbccache_pathname()
|
||||
root_logger.debug('storing krbccache data into "%s"', krbccache_pathname)
|
||||
dst = open(krbccache_pathname, 'w')
|
||||
dst.write(ccache_data)
|
||||
dst.close()
|
||||
ccache_name = krb5_unparse_ccache(scheme, name)
|
||||
return ccache_name
|
||||
|
||||
return krbccache_pathname
|
||||
|
||||
def delete_krbccache_file(krbccache_pathname=None):
|
||||
if krbccache_pathname is None:
|
||||
krbccache_pathname = get_krbccache_pathname()
|
||||
def load_ccache_data(ccache_name):
|
||||
scheme, name = krb5_parse_ccache(ccache_name)
|
||||
if scheme == 'FILE':
|
||||
root_logger.debug('reading ccache data from file "%s"', name)
|
||||
src = open(name)
|
||||
ccache_data = src.read()
|
||||
src.close()
|
||||
return ccache_data
|
||||
else:
|
||||
raise ValueError('ccache scheme "%s" unsupported (%s)', scheme, ccache_name)
|
||||
|
||||
try:
|
||||
os.unlink(krbccache_pathname)
|
||||
except Exception, e:
|
||||
root_logger.error('unable to delete session krbccache file "%s", %s',
|
||||
krbccache_pathname, e)
|
||||
def bind_ipa_ccache(ccache_data, scheme='FILE'):
|
||||
if scheme == 'FILE':
|
||||
name = _get_krbccache_pathname()
|
||||
root_logger.debug('storing ccache data into file "%s"', name)
|
||||
dst = open(name, 'w')
|
||||
dst.write(ccache_data)
|
||||
dst.close()
|
||||
else:
|
||||
raise ValueError('ccache scheme "%s" unsupported', scheme)
|
||||
|
||||
ccache_name = krb5_unparse_ccache(scheme, name)
|
||||
os.environ['KRB5CCNAME'] = ccache_name
|
||||
return ccache_name
|
||||
|
||||
def release_ipa_ccache(ccache_name):
|
||||
'''
|
||||
Stop using the current request's ccache.
|
||||
* Remove KRB5CCNAME from the enviroment
|
||||
* Remove the ccache file from the file system
|
||||
|
||||
Note, we do not demand any of these elements exist, but if they
|
||||
do we'll remove them.
|
||||
'''
|
||||
|
||||
if os.environ.has_key('KRB5CCNAME'):
|
||||
if ccache_name != os.environ['KRB5CCNAME']:
|
||||
root_logger.error('release_ipa_ccache: ccache_name (%s) != KRB5CCNAME environment variable (%s)',
|
||||
ccache_name, os.environ['KRB5CCNAME'])
|
||||
del os.environ['KRB5CCNAME']
|
||||
else:
|
||||
root_logger.debug('release_ipa_ccache: KRB5CCNAME environment variable not set')
|
||||
|
||||
scheme, name = krb5_parse_ccache(ccache_name)
|
||||
if scheme == 'FILE':
|
||||
if os.path.exists(name):
|
||||
try:
|
||||
os.unlink(name)
|
||||
except Exception, e:
|
||||
root_logger.error('unable to delete session ccache file "%s", %s', name, e)
|
||||
else:
|
||||
raise ValueError('ccache scheme "%s" unsupported (%s)', scheme, ccache_name)
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user