From 49a54d20781831b48667e504c14f676b3cb95d47 Mon Sep 17 00:00:00 2001 From: gfawcett Date: Sun, 1 Mar 2009 03:29:48 +0000 Subject: [PATCH] added Django authentication-backend It authenticates users against an Evergreen server via XMLRPC (for simplicity: XMLRPC requires no third-party modules). Just set the EVERGREEN_XMLRPC_SERVER to a valid host and away you go. git-svn-id: svn://svn.open-ils.org/ILS-Contrib/servres/trunk@129 6d9bc8c9-1ec2-4278-b937-99fde70a366f --- conifer/custom/__init__.py | 0 conifer/custom/auth_evergreen.py | 31 ++++++++++++ conifer/custom/auth_evergreen_support.py | 86 ++++++++++++++++++++++++++++++++ conifer/settings.py | 11 ++++ 4 files changed, 128 insertions(+) create mode 100644 conifer/custom/__init__.py create mode 100644 conifer/custom/auth_evergreen.py create mode 100644 conifer/custom/auth_evergreen_support.py diff --git a/conifer/custom/__init__.py b/conifer/custom/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/conifer/custom/auth_evergreen.py b/conifer/custom/auth_evergreen.py new file mode 100644 index 0000000..23d8c34 --- /dev/null +++ b/conifer/custom/auth_evergreen.py @@ -0,0 +1,31 @@ +from auth_evergreen_support import EvergreenAuthServer +from django.contrib.auth.models import User +from django.conf import settings + +class EvergreenAuthBackend(EvergreenAuthServer): + + def __init__(self): + EvergreenAuthServer.__init__( + self, settings.EVERGREEN_XMLRPC_SERVER) + + def authenticate(self, username=None, password=None): + pwd_valid = self.login(username, password) + if pwd_valid: + try: + user = User.objects.get(username=username) + except User.DoesNotExist: + u = self.lookup(username) + user = User(username=username, + first_name= u['first_name'], + last_name = u['last_name'], + email = u['email']) + user.set_unusable_password() + user.save() + return user + return None + + def get_user(self, user_id): + try: + return User.objects.get(pk=user_id) + except User.DoesNotExist: + return None diff --git a/conifer/custom/auth_evergreen_support.py b/conifer/custom/auth_evergreen_support.py new file mode 100644 index 0000000..da2819c --- /dev/null +++ b/conifer/custom/auth_evergreen_support.py @@ -0,0 +1,86 @@ +# auth_evergreen_support -- Authentication and user lookup against an +# Evergreen XML-RPC server. + +# This is the Evergreen-specific stuff, with no Django dependencies. + +import xmlrpclib +import md5 +import warnings +import time + +#---------------------------------------------------------------------- +# support + +def do_request(proxy, method, *args): + # Against my test server, I would get intermittent + # ProtcolErrors. If we get one, try again, backing off gradually. + for attempt in range(5): + try: + return getattr(proxy, method)(*args) + except xmlrpclib.ProtocolError, pe: + warnings.warn('open-ils xml-rpc protocol error: trying again: ' + method) + time.sleep(0.1 * attempt) # back off a bit and try again + +def _hsh(s): + return md5.new(s).hexdigest() + +#---------------------------------------------------------------------- +# main interface + +class EvergreenAuthServer(object): + + def __init__(self, address, verbose=False): + self.address = address + self.verbose = verbose + + def proxy(self, service): + server = xmlrpclib.Server( + 'http://%s/xml-rpc/%s' % (self.address, service), + verbose=self.verbose) + def req(method, *args): + return do_request(server, method, *args) + return req + + def login(self, username, password): + """Return True if the username/password are good, False otherwise.""" + prx = self.proxy('open-ils.auth') + seed = prx('open-ils.auth.authenticate.init', username) + resp = prx('open-ils.auth.authenticate.complete', + dict(username='admin', + password=_hsh(seed + _hsh(password)), + type='reserves')) + try: + # do we need the authkey for anything? + authkey = resp['payload']['authtoken'] + return True + except KeyError: + return False + + def lookup(self, username): + """Given a username, return a dict, or None. The dict must have + four keys (first_name, last_name, email, external_username), where + external_username value is the username parameter.""" + + prx = self.proxy('open-ils.actor') + r = prx('open-ils.actor.user.search.username', 'admin') + if not r: + return None + else: + r = r[0]['__data__'] + f = lambda k: r.get(k) + person = dict((j, f(k)) for j,k in [('first_name', 'first_given_name'), + ('last_name', 'family_name'), + ('email', 'email'), + ('external_username', 'usrname')]) + return person + +#---------------------------------------------------------------------- +# testing + +if __name__ == '__main__': + from pprint import pprint + address = '192.168.1.10' + egreen = EvergreenAuthServer(address) + username, password = 'admin', 'open-ils' + print egreen.login(username, password) + pprint(egreen.lookup('admin')) diff --git a/conifer/settings.py b/conifer/settings.py index 415cc47..c1b181d 100644 --- a/conifer/settings.py +++ b/conifer/settings.py @@ -92,3 +92,14 @@ INSTALLED_APPS = ( ) AUTH_PROFILE_MODULE = 'syrup.UserProfile' + + +AUTHENTICATION_BACKENDS = [ + 'django.contrib.auth.backends.ModelBackend', +] + +EVERGREEN_XMLRPC_SERVER = None # evergreen host, for auth, e.g. '192.168.1.10' + +if EVERGREEN_XMLRPC_SERVER: + AUTHENTICATION_BACKENDS.append( + 'conifer.custom.auth_evergreen.EvergreenAuthBackend') -- 2.11.0