summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--freeipa.spec.in1
-rw-r--r--install/conf/ipa.conf23
-rw-r--r--install/share/wsgi.py3
-rw-r--r--install/ui/ipa.js3
-rw-r--r--ipalib/backend.py5
-rw-r--r--ipalib/krb_utils.py71
-rw-r--r--ipalib/session.py126
-rw-r--r--ipaserver/plugins/xmlserver.py7
-rw-r--r--ipaserver/rpcserver.py253
-rwxr-xr-xlite-server.py2
-rwxr-xr-xmake-lint2
-rw-r--r--tests/test_ipaserver/test_rpcserver.py6
12 files changed, 376 insertions, 126 deletions
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 3e9db73b1..3609bddf0 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -74,6 +74,7 @@ BuildRequires: python-rhsm
BuildRequires: pyOpenSSL
BuildRequires: pylint
BuildRequires: libipa_hbac-python
+BuildRequires: python-memcached
%description
IPA is an integrated solution to provide centrally managed Identity (machine,
diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf
index 676086a90..cd806be7d 100644
--- a/install/conf/ipa.conf
+++ b/install/conf/ipa.conf
@@ -44,8 +44,8 @@ WSGIScriptReloading Off
KrbConstrainedDelegationLock ipa
-# Protect UI login url with Kerberos
-<Location "/ipa/login">
+# Protect /ipa and everything below it in webspace with Apache Kerberos auth
+<Location "/ipa">
AuthType Kerberos
AuthName "Kerberos Login"
KrbMethodNegotiate on
@@ -59,22 +59,13 @@ KrbConstrainedDelegationLock ipa
ErrorDocument 401 /ipa/errors/unauthorized.html
</Location>
-# Protect xmlrpc url with Kerberos
-<Location "/ipa/xml">
- AuthType Kerberos
- AuthName "Kerberos Login"
- KrbMethodNegotiate on
- KrbMethodK5Passwd off
- KrbServiceName HTTP
- KrbAuthRealms $REALM
- Krb5KeyTab /etc/httpd/conf/ipa.keytab
- KrbSaveCredentials on
- KrbConstrainedDelegation on
- Require valid-user
- ErrorDocument 401 /ipa/errors/unauthorized.html
+# Turn off Apache authentication for sessions
+<Location "/ipa/session">
+ Satisfy Any
+ Order Deny,Allow
+ Allow from all
</Location>
-
# This is where we redirect on failed auth
Alias /ipa/errors "/usr/share/ipa/html"
diff --git a/install/share/wsgi.py b/install/share/wsgi.py
index b61b919da..9f7d3f487 100644
--- a/install/share/wsgi.py
+++ b/install/share/wsgi.py
@@ -1,6 +1,7 @@
# Authors:
# Rob Crittenden <rcritten@redhat.com>
# Jason Gerard DeRose <jderose@redhat.com>
+# John Dennis <jdennis@redhat.com>
#
# Copyright (C) 2010 Red Hat
# see file 'COPYING' for use and warranty information
@@ -45,6 +46,6 @@ else:
# This is the WSGI callable:
def application(environ, start_response):
if not environ['wsgi.multithread']:
- return api.Backend.session(environ, start_response)
+ return api.Backend.wsgi_dispatch(environ, start_response)
else:
api.log.error("IPA does not work with the threaded MPM, use the pre-fork MPM")
diff --git a/install/ui/ipa.js b/install/ui/ipa.js
index 82e892043..a599f6a8c 100644
--- a/install/ui/ipa.js
+++ b/install/ui/ipa.js
@@ -3,6 +3,7 @@
* Pavel Zuna <pzuna@redhat.com>
* Adam Young <ayoung@redhat.com>
* Endi Dewata <edewata@redhat.com>
+ * John Dennis <jdennis@redhat.com>
*
* Copyright (C) 2010 Red Hat
* see file 'COPYING' for use and warranty information
@@ -58,7 +59,7 @@ var IPA = function() {
// if current path matches live server path, use live data
if (that.url && window.location.pathname.substring(0, that.url.length) === that.url) {
- that.json_url = params.url || '/ipa/json';
+ that.json_url = params.url || '/ipa/session/json';
that.login_url = params.url || '/ipa/login';
} else { // otherwise use fixtures
diff --git a/ipalib/backend.py b/ipalib/backend.py
index 7ed378e88..0232fa536 100644
--- a/ipalib/backend.py
+++ b/ipalib/backend.py
@@ -23,6 +23,7 @@ Base classes for all backed-end plugins.
import threading
import plugable
+import os
from errors import PublicError, InternalError, CommandError
from request import context, Connection, destroy_context
@@ -106,6 +107,10 @@ class Executioner(Backend):
"""
client_ip: The IP address of the remote client.
"""
+
+ if ccache is not None:
+ os.environ["KRB5CCNAME"] = ccache
+
if self.env.in_server:
self.Backend.ldap2.connect(ccache=ccache)
else:
diff --git a/ipalib/krb_utils.py b/ipalib/krb_utils.py
index e04c70ae7..21bca68a6 100644
--- a/ipalib/krb_utils.py
+++ b/ipalib/krb_utils.py
@@ -158,7 +158,6 @@ class KRB5_CCache(object):
self.ccache = None
self.principal = None
- self.debug('opening ccache file "%s"', ccache)
try:
self.context = krbV.default_context()
self.scheme, self.name = krb5_parse_ccache(ccache)
@@ -228,8 +227,6 @@ class KRB5_CCache(object):
except krbV.Krb5Error, e:
error_code = e.args[0]
if error_code == KRB5_CC_NOTFOUND:
- self.debug('"%s" credential not found in "%s" ccache',
- krbV_principal.name, self.ccache_str()) #pylint: disable=E1103
raise KeyError('"%s" credential not found in "%s" ccache' % \
(krbV_principal.name, self.ccache_str())) #pylint: disable=E1103
raise e
@@ -281,7 +278,7 @@ class KRB5_CCache(object):
cred = self.get_credentials(krbV_principal)
authtime, starttime, endtime, renew_till = cred[3]
- self.debug('principal=%s, authtime=%s, starttime=%s, endtime=%s, renew_till=%s',
+ self.debug('get_credential_times: principal=%s, authtime=%s, starttime=%s, endtime=%s, renew_till=%s',
krbV_principal.name, #pylint: disable=E1103
krb5_format_time(authtime), krb5_format_time(starttime),
krb5_format_time(endtime), krb5_format_time(renew_till))
@@ -327,3 +324,69 @@ class KRB5_CCache(object):
if endtime < now:
return False
return True
+
+ def valid(self, host, realm):
+ '''
+ Test to see if ldap service ticket or the TGT is valid.
+
+ :parameters:
+ host
+ ldap server
+ realm
+ kerberos realm
+ :returns:
+ True if either the ldap service ticket or the TGT is valid,
+ False otherwise.
+ '''
+
+ try:
+ principal = krb5_format_service_principal_name('ldap', host, realm)
+ valid = self.credential_is_valid(principal)
+ if valid:
+ return True
+ except KeyError:
+ pass
+
+ try:
+ principal = krb5_format_tgt_principal_name(realm)
+ valid = self.credential_is_valid(principal)
+ return valid
+ except KeyError:
+ return False
+
+ def endtime(self, host, realm):
+ '''
+ Returns the minimum endtime for tickets of interest (ldap service or TGT).
+
+ :parameters:
+ host
+ ldap server
+ realm
+ kerberos realm
+ :returns:
+ UNIX timestamp value.
+ '''
+
+ result = 0
+ try:
+ principal = krb5_format_service_principal_name('ldap', host, realm)
+ authtime, starttime, endtime, renew_till = self.get_credential_times(principal)
+ if result:
+ result = min(result, endtime)
+ else:
+ result = endtime
+ except KeyError:
+ pass
+
+ try:
+ principal = krb5_format_tgt_principal_name(realm)
+ authtime, starttime, endtime, renew_till = self.get_credential_times(principal)
+ if result:
+ result = min(result, endtime)
+ else:
+ result = endtime
+ except KeyError:
+ pass
+
+ self.debug('"%s" ccache endtime=%s', self.ccache_str(), krb5_format_time(result))
+ return result
diff --git a/ipalib/session.py b/ipalib/session.py
index a58643983..1f5ee379d 100644
--- a/ipalib/session.py
+++ b/ipalib/session.py
@@ -25,6 +25,8 @@ import re
import time
from text import _
from ipapython.ipa_log_manager import *
+from ipalib import api, errors
+from ipalib import Command
from ipalib.krb_utils import *
__doc__ = '''
@@ -632,6 +634,82 @@ def fmt_time(timestamp):
#-------------------------------------------------------------------------------
+class AuthManager(object):
+ '''
+ This class is an abstract base class and is meant to be subclassed
+ to provide actual functionality. The purpose is to encapsulate all
+ the callbacks one might need to manage authenticaion. Different
+ authentication mechanisms will instantiate a subclass of this and
+ register it with the SessionAuthManger. When an authentication
+ event occurs the matching method will be called for each
+ registered class. This allows the SessionAuthManager to notify
+ interested parties.
+ '''
+
+ def __init__(self, name):
+ log_mgr.get_logger(self, True)
+ self.name = name
+
+
+ def logout(self, session_data):
+ '''
+ Called when a user requests to be logged out of their session.
+
+ :parameters:
+ session_data
+ The current session data
+ :returns:
+ None
+ '''
+ self.debug('AuthManager.logout.%s:', self.name)
+
+class SessionAuthManager(object):
+ '''
+ '''
+
+ def __init__(self):
+ '''
+ '''
+ log_mgr.get_logger(self, True)
+ self.auth_managers = {}
+
+ def register(self, name, auth_mgr):
+ self.debug('SessionAuthManager.register: name=%s', name)
+
+ existing_mgr = self.auth_managers.get(name)
+ if existing_mgr is not None:
+ raise KeyError('cannot register auth manager named "%s" one already exists, name="%s" object=%s',
+ name, existing_mgr.name, repr(existing_mgr))
+
+ if not isinstance(auth_mgr, AuthManager):
+ raise TypeError('auth_mgr must be an instance of AuthManager, not %s',
+ auth_mgr.__class__.__name__)
+
+ self.auth_managers[name] = auth_mgr
+
+
+ def unregister(self, name):
+ self.debug('SessionAuthManager.unregister: name=%s', name)
+
+ if not self.auth_managers.has_key(name):
+ raise KeyError('cannot unregister auth manager named "%s", does not exist',
+ name)
+ del self.auth_managers[name]
+
+
+ def logout(self, session_data):
+ '''
+ '''
+ self.debug('SessionAuthManager.logout:')
+
+ for auth_mgr in self.auth_managers.values():
+ try:
+ auth_mgr.logout(session_data)
+ except Exception, e:
+ self.error('%s auth_mgr logout failed: %s', auth_mgr.name, e)
+
+#-------------------------------------------------------------------------------
+
class SessionManager(object):
'''
@@ -649,8 +727,9 @@ class SessionManager(object):
log_mgr.get_logger(self, True)
self.generated_session_ids = set()
+ self.auth_mgr = SessionAuthManager()
- def generate_session_id(self, n_bits=48):
+ def generate_session_id(self, n_bits=128):
'''
Return a random string to be used as a session id.
@@ -790,8 +869,7 @@ class MemcacheSessionManager(SessionManager):
n_retries = 0
while n_retries < max_retries:
session_id = super(MemcacheSessionManager, self).new_session_id(max_retries)
- session_key = self.session_key(session_id)
- session_data = self.mc.get(session_key)
+ session_data = self.get_session_data(session_id)
if session_data is None:
break
n_retries += 1
@@ -843,6 +921,21 @@ class MemcacheSessionManager(SessionManager):
'''
return 'ipa.session.%s' % (session_id)
+ def get_session_data(self, session_id):
+ '''
+ Given a session id retrieve the session data associated with it.
+ If no session data exists for the session id return None.
+
+ :parameters:
+ session_id
+ The session id whose session data is desired.
+ :returns:
+ Session data if found, None otherwise.
+ '''
+ session_key = self.session_key(session_id)
+ session_data = self.mc.get(session_key)
+ return session_data
+
def get_session_id_from_http_cookie(self, cookie_header):
'''
Parse an HTTP cookie header and search for our session
@@ -904,8 +997,7 @@ class MemcacheSessionManager(SessionManager):
self.store_session_data(session_data)
return session_data
else:
- session_key = self.session_key(session_id)
- session_data = self.mc.get(session_key)
+ session_data = self.get_session_data(session_id)
if session_data is None:
self.debug('no session data in cache with id=%s, generating empty session data', session_id)
session_data = self.new_session_data(session_id)
@@ -1094,5 +1186,29 @@ def delete_krbccache_file(krbccache_pathname=None):
#-------------------------------------------------------------------------------
+from ipalib.request import context
+
+class session_logout(Command):
+ '''
+ RPC command used to log the current user out of their session.
+ '''
+
+ def execute(self, *args, **options):
+ session_data = getattr(context, 'session_data', None)
+ if session_data is None:
+ self.debug('session logout command: no session_data found')
+ else:
+ session_id = session_data.get('session_id')
+ self.debug('session logout command: session_id=%s', session_id)
+
+ # Notifiy registered listeners
+ session_mgr.auth_mgr.logout(session_data)
+
+ return dict(result=None)
+
+api.register(session_logout)
+
+#-------------------------------------------------------------------------------
+
session_mgr = MemcacheSessionManager()
diff --git a/ipaserver/plugins/xmlserver.py b/ipaserver/plugins/xmlserver.py
index 03bca9a80..d2a28eca8 100644
--- a/ipaserver/plugins/xmlserver.py
+++ b/ipaserver/plugins/xmlserver.py
@@ -25,8 +25,9 @@ Loads WSGI server plugins.
from ipalib import api
if 'in_server' in api.env and api.env.in_server is True:
- from ipaserver.rpcserver import session, xmlserver, jsonserver, krblogin
- api.register(session)
+ from ipaserver.rpcserver import wsgi_dispatch, xmlserver, jsonserver_kerb, jsonserver_session, krblogin
+ api.register(wsgi_dispatch)
api.register(xmlserver)
- api.register(jsonserver)
+ api.register(jsonserver_kerb)
+ api.register(jsonserver_session)
api.register(krblogin)
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index 205dc7655..d0bb605f5 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -32,9 +32,9 @@ from ipalib.request import context, Connection, destroy_context
from ipalib.rpc import xml_dumps, xml_loads
from ipalib.util import make_repr, parse_time_duration
from ipapython.compat import json
-from ipalib.session import session_mgr, read_krbccache_file, store_krbccache_file, delete_krbccache_file, fmt_time, default_max_session_lifetime
+from ipalib.session import session_mgr, AuthManager, read_krbccache_file, store_krbccache_file, delete_krbccache_file, fmt_time, default_max_session_lifetime
from ipalib.backend import Backend
-from ipalib.krb_utils import krb5_parse_ccache, KRB5_CCache, krb5_format_tgt_principal_name, krb5_format_service_principal_name, krb_ticket_expiration_threshold
+from ipalib.krb_utils import krb5_parse_ccache, KRB5_CCache, krb_ticket_expiration_threshold
from wsgiref.util import shift_path_info
from ipapython.version import VERSION
import base64
@@ -118,18 +118,17 @@ def extract_query(environ):
return query
-class session(Executioner):
+class wsgi_dispatch(Executioner):
"""
WSGI routing middleware and entry point into IPA server.
- The `session` plugin is the entry point into the IPA server. It will create
- an LDAP connection (from a session cookie or the KRB5CCNAME header) and then
- dispatch the request to the appropriate application. In WSGI parlance,
- `session` is *middleware*.
+ The `wsgi_dispatch` plugin is the entry point into the IPA server.
+ It dispatchs the request to the appropriate wsgi application
+ handler which is specific to the authentication and RPC mechanism.
"""
def __init__(self):
- super(session, self).__init__()
+ super(wsgi_dispatch, self).__init__()
self.__apps = {}
def __iter__(self):
@@ -143,7 +142,7 @@ class session(Executioner):
return key in self.__apps
def __call__(self, environ, start_response):
- self.debug('WSGI session.__call__:')
+ self.debug('WSGI wsgi_dispatch.__call__:')
try:
return self.route(environ, start_response)
finally:
@@ -151,10 +150,10 @@ class session(Executioner):
def _on_finalize(self):
self.url = self.env['mount_ipa']
- super(session, self)._on_finalize()
+ super(wsgi_dispatch, self)._on_finalize()
def route(self, environ, start_response):
- key = shift_path_info(environ)
+ key = environ.get('PATH_INFO')
if key in self.__apps:
app = self.__apps[key]
return app(environ, start_response)
@@ -189,8 +188,8 @@ class WSGIExecutioner(Executioner):
def set_api(self, api):
super(WSGIExecutioner, self).set_api(api)
- if 'session' in self.api.Backend:
- self.api.Backend.session.mount(self, self.key)
+ if 'wsgi_dispatch' in self.api.Backend:
+ self.api.Backend.wsgi_dispatch.mount(self, self.key)
def _on_finalize(self):
self.url = self.env.mount_ipa + self.key
@@ -302,7 +301,7 @@ class xmlserver(WSGIExecutioner):
"""
content_type = 'text/xml'
- key = 'xml'
+ key = '/xml'
def _on_finalize(self):
self.__system = {
@@ -317,6 +316,10 @@ class xmlserver(WSGIExecutioner):
'''
self.debug('WSGI xmlserver.__call__:')
+ ccache=environ.get('KRB5CCNAME')
+ if ccache is None:
+ return self.marshal(None, CCacheError())
+ self.create_context(ccache=ccache)
try:
self.create_context(ccache=environ.get('KRB5CCNAME'))
response = super(xmlserver, self).__call__(environ, start_response)
@@ -339,23 +342,6 @@ class xmlserver(WSGIExecutioner):
def methodHelp(self, *params):
return u'methodHelp not implemented'
- def marshaled_dispatch(self, data, ccache, client_ip):
- """
- Execute the XML-RPC request contained in ``data``.
- """
- try:
- self.create_context(ccache=ccache, client_ip=client_ip)
- (params, name) = xml_loads(data)
- if name in self.__system:
- response = (self.__system[name](*params),)
- else:
- (args, options) = params_2_args_options(params)
- response = (self.execute(name, *args, **options),)
- except PublicError, e:
- self.debug('response: %s: %s', e.__class__.__name__, str(e))
- response = Fault(e.errno, e.strerror)
- return xml_dumps(response, methodresponse=True)
-
def unmarshal(self, data):
(params, name) = xml_loads(data)
(args, options) = params_2_args_options(params)
@@ -489,17 +475,6 @@ class jsonserver(WSGIExecutioner):
"""
content_type = 'application/json'
- key = 'json'
-
- def need_login(self, start_response):
- status = '401 Unauthorized'
- headers = []
- response = ''
-
- self.debug('jsonserver: %s', status)
-
- start_response(status, headers)
- return [response]
def __call__(self, environ, start_response):
'''
@@ -507,51 +482,7 @@ class jsonserver(WSGIExecutioner):
self.debug('WSGI jsonserver.__call__:')
- # Load the session data
- session_data = session_mgr.load_session_data(environ.get('HTTP_COOKIE'))
- session_id = session_data['session_id']
-
- self.debug('jsonserver.__call__: session_id=%s start_timestamp=%s write_timestamp=%s expiration_timestamp=%s',
- session_id,
- fmt_time(session_data['session_start_timestamp']),
- fmt_time(session_data['session_write_timestamp']),
- fmt_time(session_data['session_expiration_timestamp']))
-
- ccache_data = session_data.get('ccache_data')
-
- # Redirect to login if no Kerberos credentials
- if ccache_data is None:
- self.debug('no ccache, need login')
- return self.need_login(start_response)
-
- krbccache_pathname = store_krbccache_file(ccache_data)
-
- # Redirect to login if Kerberos credentials are expired
- cc = KRB5_CCache(krbccache_pathname)
- ldap_principal = krb5_format_service_principal_name('ldap', self.api.env.host, self.api.env.realm)
- tgt_principal = krb5_format_tgt_principal_name(self.api.env.realm)
- if not (cc.credential_is_valid(ldap_principal) or cc.credential_is_valid(tgt_principal)):
- self.debug('ccache expired, deleting session, need login')
- session_mgr.delete_session_data(session_id)
- delete_krbccache_file(krbccache_pathname)
- return self.need_login(start_response)
-
- # Store the session data in the per-thread context
- setattr(context, 'session_data', session_data)
-
- self.create_context(ccache=krbccache_pathname)
-
- try:
- response = super(jsonserver, self).__call__(environ, start_response)
- finally:
- # Kerberos may have updated the ccache data, refresh our copy of it
- session_data['ccache_data'] = read_krbccache_file(krbccache_pathname)
- # Delete the temporary ccache file we used
- delete_krbccache_file(krbccache_pathname)
- # Store the session data.
- session_mgr.store_session_data(session_data)
- destroy_context()
-
+ response = super(jsonserver, self).__call__(environ, start_response)
return response
def marshal(self, result, error, _id=None):
@@ -606,15 +537,154 @@ class jsonserver(WSGIExecutioner):
options = dict((str(k), v) for (k, v) in options.iteritems())
return (method, args, options, _id)
+class AuthManagerKerb(AuthManager):
+ '''
+ Instances of the AuthManger class are used to handle
+ authentication events delivered by the SessionManager. This class
+ specifcally handles the management of Kerbeos credentials which
+ may be stored in the session.
+ '''
+
+ def __init__(self, name):
+ super(AuthManagerKerb, self).__init__(name)
+
+ def logout(self, session_data):
+ '''
+ The current user has requested to be logged out. To accomplish
+ this we remove the user's kerberos credentials from their
+ session. This does not destroy the session, it just prevents
+ it from being used for fast authentication. Because the
+ credentials are no longer in the session cache any future
+ attempt will require the acquisition of credentials using one
+ of the login mechanisms.
+ '''
+
+ if session_data.has_key('ccache_data'):
+ self.debug('AuthManager.logout.%s: deleting ccache_data', self.name)
+ del session_data['ccache_data']
+ else:
+ self.error('AuthManager.logout.%s: session_data does not contain ccache_data', self.name)
+
+
+class jsonserver_session(jsonserver):
+ """
+ JSON RPC server protected with session auth.
+ """
+
+ key = '/session/json'
+
+ def __init__(self):
+ super(jsonserver_session, self).__init__()
+ auth_mgr = AuthManagerKerb(self.__class__.__name__)
+ session_mgr.auth_mgr.register(auth_mgr.name, auth_mgr)
+
+ def need_login(self, start_response):
+ status = '401 Unauthorized'
+ headers = []
+ response = ''
+
+ self.debug('jsonserver_session: %s', status)
+
+ start_response(status, headers)
+ return [response]
+
+ def __call__(self, environ, start_response):
+ '''
+ '''
+
+ self.debug('WSGI jsonserver_session.__call__:')
+
+ # Load the session data
+ session_data = session_mgr.load_session_data(environ.get('HTTP_COOKIE'))
+ session_id = session_data['session_id']
+
+ self.debug('jsonserver_session.__call__: session_id=%s start_timestamp=%s write_timestamp=%s expiration_timestamp=%s',
+ session_id,
+ fmt_time(session_data['session_start_timestamp']),
+ fmt_time(session_data['session_write_timestamp']),
+ fmt_time(session_data['session_expiration_timestamp']))
+
+ ccache_data = session_data.get('ccache_data')
+
+ # Redirect to login if no Kerberos credentials
+ if ccache_data is None:
+ self.debug('no ccache, need login')
+ return self.need_login(start_response)
+
+ krbccache_pathname = store_krbccache_file(ccache_data)
+
+ # Redirect to login if Kerberos credentials are expired
+ cc = KRB5_CCache(krbccache_pathname)
+ if not cc.valid(self.api.env.host, self.api.env.realm):
+ self.debug('ccache expired, deleting session, need login')
+ delete_krbccache_file(krbccache_pathname)
+ return self.need_login(start_response)
+
+ # Store the session data in the per-thread context
+ setattr(context, 'session_data', session_data)
+
+ self.create_context(ccache=krbccache_pathname)
+
+ try:
+ response = super(jsonserver_session, self).__call__(environ, start_response)
+ finally:
+ # Kerberos may have updated the ccache data during the
+ # execution of the command therefore we need refresh our
+ # copy of it in the session data so the next command sees
+ # the same state of the ccache.
+ #
+ # However we must be careful not to restore the ccache
+ # data in the session data if it was explicitly deleted
+ # during the execution of the command. For example the
+ # logout command removes the ccache data from the session
+ # data to invalidate the session credentials.
+
+ if session_data.has_key('ccache_data'):
+ session_data['ccache_data'] = read_krbccache_file(krbccache_pathname)
+
+ # Delete the temporary ccache file we used
+ delete_krbccache_file(krbccache_pathname)
+ # Store the session data.
+ session_mgr.store_session_data(session_data)
+ destroy_context()
+
+ return response
+
+class jsonserver_kerb(jsonserver):
+ """
+ JSON RPC server protected with kerberos auth.
+ """
+
+ key = '/json'
+
+ def __call__(self, environ, start_response):
+ '''
+ '''
+
+ self.debug('WSGI jsonserver_kerb.__call__:')
+
+ ccache=environ.get('KRB5CCNAME')
+ if ccache is None:
+ return self.marshal(None, CCacheError())
+ self.create_context(ccache=ccache)
+
+ try:
+ response = super(jsonserver_kerb, self).__call__(environ, start_response)
+ finally:
+ destroy_context()
+
+ return response
+
+
class krblogin(Backend):
- key = 'login'
+ key = '/login'
def __init__(self):
super(krblogin, self).__init__()
def _on_finalize(self):
super(krblogin, self)._on_finalize()
- self.api.Backend.session.mount(self, self.key)
+ self.api.Backend.wsgi_dispatch.mount(self, self.key)
# Set the session expiration time
try:
@@ -652,8 +722,7 @@ class krblogin(Backend):
# Compute when the session will expire
cc = KRB5_CCache(ccache)
- tgt_principal = krb5_format_tgt_principal_name(self.api.env.realm)
- authtime, starttime, endtime, renew_till = cc.get_credential_times(tgt_principal)
+ endtime = cc.endtime(self.api.env.host, self.api.env.realm)
# Account for clock skew and/or give us some time leeway
krb_expiration = endtime - krb_ticket_expiration_threshold
@@ -673,7 +742,7 @@ class krblogin(Backend):
status = '200 Success'
response = ''
- session_cookie = session_mgr.generate_cookie('/ipa', session_data['session_id'])
+ session_cookie = session_mgr.generate_cookie('/ipa', session_id)
headers.append(('Set-Cookie', session_cookie))
start_response(status, headers)
diff --git a/lite-server.py b/lite-server.py
index b7067a56c..e06535784 100755
--- a/lite-server.py
+++ b/lite-server.py
@@ -124,7 +124,7 @@ if __name__ == '__main__':
urlmap = URLMap()
apps = [
- ('IPA', KRBCheater(api.Backend.session)),
+ ('IPA', KRBCheater(api.Backend.wsgi_dispatch)),
('webUI', KRBCheater(WebUIApp())),
]
for (name, app) in apps:
diff --git a/make-lint b/make-lint
index 20f628128..94fb1caa5 100755
--- a/make-lint
+++ b/make-lint
@@ -68,6 +68,8 @@ class IPATypeChecker(TypeChecker):
'ipalib.parameters.File': ['stdin_if_missing'],
'urlparse.SplitResult': ['netloc'],
'ipalib.krb_utils.KRB5_CCache' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
+ 'ipalib.session.AuthManager' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
+ 'ipalib.session.SessionAuthManager' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
'ipalib.session.SessionManager' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
'ipalib.session.SessionCCache' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
'ipalib.session.MemcacheSessionManager' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
diff --git a/tests/test_ipaserver/test_rpcserver.py b/tests/test_ipaserver/test_rpcserver.py
index 9aa16d0ce..e712078d7 100644
--- a/tests/test_ipaserver/test_rpcserver.py
+++ b/tests/test_ipaserver/test_rpcserver.py
@@ -84,7 +84,7 @@ def test_params_2_args_options():
class test_session(object):
- klass = rpcserver.session
+ klass = rpcserver.wsgi_dispatch
def test_route(self):
def app1(environ, start_response):
@@ -125,7 +125,7 @@ class test_session(object):
# Test that StandardError is raise if trying override a mount:
e = raises(StandardError, inst.mount, app2, 'foo')
assert str(e) == '%s.mount(): cannot replace %r with %r at %r' % (
- 'session', app1, app2, 'foo'
+ 'wsgi_dispatch', app1, app2, 'foo'
)
# Test mounting a second app:
@@ -141,7 +141,7 @@ class test_xmlserver(PluginTester):
_plugin = rpcserver.xmlserver
- def test_marshaled_dispatch(self):
+ def test_marshaled_dispatch(self): # FIXME
(o, api, home) = self.instance('Backend', in_server=True)