From: gfawcett
Date: Fri, 16 Jul 2010 19:37:09 +0000 (+0000)
Subject: Preliminary Sakai Linktool support
X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=66f6be0f7d6c0e94f6a6fb70d315899eea7fb229;p=Syrup.git
Preliminary Sakai Linktool support
Merged git branch 'linktool-auth' (6aae15a) into 'master'. I used
'--squash', which loses the merge history, but allows the merge to be
committed to SVN ('linktool-auth' was not an SVN branch).
git-svn-id: svn://svn.open-ils.org/ILS-Contrib/servres/trunk@928 6d9bc8c9-1ec2-4278-b937-99fde70a366f
---
diff --git a/conifer/integration/auth_linktool.py b/conifer/integration/auth_linktool.py
new file mode 100644
index 0000000..6983285
--- /dev/null
+++ b/conifer/integration/auth_linktool.py
@@ -0,0 +1,61 @@
+from django.contrib.auth.models import User
+from django.conf import settings
+from urllib import quote
+from urllib2 import urlopen
+
+def testsign(query_string):
+ url = '%s?data=%s' % (settings.LINKTOOL_AUTH_URL, quote(query_string))
+ result = urlopen(url).read()
+ return (result == 'true')
+
+class LinktoolAuthBackend(object):
+
+ def __init__(self):
+ assert settings.LINKTOOL_AUTH_URL, \
+ 'LinktoolAuthBackend requires settings.LINKTOOL_AUTH_URL'
+
+ def authenticate(self, request=None):
+ valid = testsign(request.META['QUERY_STRING'])
+ if valid:
+ username = request.GET['user']
+ return self.maybe_initialize_user(username)
+ return None
+
+ def get_user(self, user_id):
+ try:
+ return User.objects.get(pk=user_id)
+ except User.DoesNotExist:
+ return None
+
+ def maybe_initialize_user(self, username, look_local=True):
+ """Look up user in Django db; if not found, fetch user detail
+ from backend and set up a local user object. Return None if no
+ such user exists in either Django or the backend.
+
+ Setting look_local=False skips the Django search and heads
+ straight to the backend; this shaves a database call when
+ walking a set of backends to initialize a user. Skipping
+ look_local on a username that already exists in Django will
+ certainly lead to an integrity error.
+
+ This method is NOT part of the Django backend interface.
+ """
+ user = None
+ if look_local:
+ try:
+ user = User.objects.get(username=username)
+ except User.DoesNotExist:
+ pass
+ if user is None:
+ u = self.lookup(username)
+ if u: # user found in LDAP or whatever.
+ 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
+
+ def lookup(self, username):
+ return None # fixme
diff --git a/conifer/integration/clew-sections-for-site b/conifer/integration/clew-sections-for-site
new file mode 100755
index 0000000..a4912bc
--- /dev/null
+++ b/conifer/integration/clew-sections-for-site
@@ -0,0 +1,41 @@
+#!/Users/graham/bin/python-oracle-cgi-wrapper
+# -*- mode: python -*-
+
+import os
+import cx_Oracle
+import re
+import sys
+import warnings
+import simplejson as json
+import time
+import cgitb
+
+#cgitb.enable(display=True)
+
+conn = cx_Oracle.connect('sakai/PASSWORD@clew')
+
+try:
+ siteid = os.environ['PATH_INFO'][1:]
+ assert len(siteid) == 36, 'malformed site id'
+
+ cursor = conn.cursor()
+ query = """
+ select provider_id from sakai_realm
+ where realm_id like '/site/' || :1
+ """
+ cursor.execute(query, (siteid,))
+ try:
+ provider_id = cursor.fetchone()[0] or ''
+ except:
+ raise Exception('site ID not found.')
+
+ providers = provider_id.split('+')
+ output = json.dumps({'status':'ok', 'siteid': siteid, 'providers': providers})
+except Exception, e:
+ output = {'status':'error', 'error': str(e)}
+
+print 'Status: 200 OK'
+print 'Content-Type: application/json'
+print
+print output
+conn.close()
diff --git a/conifer/integration/linktool/__init__.py b/conifer/integration/linktool/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/conifer/integration/linktool/app.py b/conifer/integration/linktool/app.py
new file mode 100644
index 0000000..3cf9601
--- /dev/null
+++ b/conifer/integration/linktool/app.py
@@ -0,0 +1,14 @@
+from django.contrib.auth import authenticate, login
+from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
+
+
+def linktool_welcome(request):
+ user = authenticate(request=request)
+ if user is None:
+ return HttpResponseForbidden('You are not allowed here.')
+ else:
+ login(request, user)
+ request.session['clew-site'] = request.GET['site']
+ return HttpResponse("""
"""
+ """Redirecting to the library system...""" % (
+ request.META['SCRIPT_NAME']))
diff --git a/conifer/integration/linktool/backend.py b/conifer/integration/linktool/backend.py
new file mode 100644
index 0000000..64020aa
--- /dev/null
+++ b/conifer/integration/linktool/backend.py
@@ -0,0 +1,65 @@
+from conifer.plumbing.hooksystem import *
+from django.conf import settings
+from django.contrib.auth.models import User
+from urllib import quote
+from urllib2 import urlopen
+
+
+def testsign(query_string):
+ url = '%s?data=%s' % (settings.LINKTOOL_AUTH_URL, quote(query_string))
+ result = urlopen(url).read()
+ return (result == 'true')
+
+
+class LinktoolAuthBackend(object):
+
+ def __init__(self):
+ assert settings.LINKTOOL_AUTH_URL, \
+ 'LinktoolAuthBackend requires settings.LINKTOOL_AUTH_URL'
+
+ def authenticate(self, request=None):
+ valid = testsign(request.META['QUERY_STRING'])
+ if valid:
+ username = request.GET['user']
+ return self.maybe_initialize_user(username)
+ return None
+
+ def get_user(self, user_id):
+ try:
+ return User.objects.get(pk=user_id)
+ except User.DoesNotExist:
+ return None
+
+ def maybe_initialize_user(self, username, look_local=True):
+ """Look up user in Django db; if not found, fetch user detail
+ from backend and set up a local user object. Return None if no
+ such user exists in either Django or the backend.
+
+ Setting look_local=False skips the Django search and heads
+ straight to the backend; this shaves a database call when
+ walking a set of backends to initialize a user. Skipping
+ look_local on a username that already exists in Django will
+ certainly lead to an integrity error.
+
+ This method is NOT part of the Django backend interface.
+ """
+ user = None
+ if look_local:
+ try:
+ user = User.objects.get(username=username)
+ except User.DoesNotExist:
+ pass
+ if user is None:
+ u = self.lookup(username)
+ if u: # user found in LDAP or whatever.
+ user = User(username=username,
+ first_name = u['given_name'],
+ last_name = u['surname'],
+ email = u.get('email', None))
+ user.set_unusable_password()
+ user.save()
+ return user
+
+ def lookup(self, username):
+ return callhook('external_person_lookup', username)
+
diff --git a/conifer/integration/uwindsor.py b/conifer/integration/uwindsor.py
index bcc137c..664a3ad 100644
--- a/conifer/integration/uwindsor.py
+++ b/conifer/integration/uwindsor.py
@@ -6,7 +6,7 @@ from conifer.libsystems.evergreen import item_status as I
from conifer.libsystems.z3950 import pyz3950_search as PZ
from xml.etree import ElementTree as ET
import re
-
+import uwindsor_campus_info
def department_course_catalogue():
"""
@@ -111,3 +111,13 @@ def marcxml_to_url(marc_string):
return None
+def external_person_lookup(userid):
+ """
+ Given a userid, return either None (if the user cannot be found),
+ or a dictionary representing the user. The dictionary must contain
+ the keys ('given_name', 'surname') and should contain 'email' if
+ an email address is known.
+ """
+ return uwindsor_campus_info.call('person_lookup', userid)
+
+
diff --git a/conifer/local_settings.py.example b/conifer/local_settings.py.example
index adbe698..84ce294 100644
--- a/conifer/local_settings.py.example
+++ b/conifer/local_settings.py.example
@@ -31,9 +31,11 @@ TIME_ZONE = 'America/Detroit'
SECRET_KEY = 'replace-with-your-own-super-random-key-@vv(tuvt2+yu2r-$dxs$s7=iqjz_s!&'
#----------------------------------------------------------------------
+# Authentication systems
EVERGREEN_AUTHENTICATION = False # Evergreen ILS authentication
LINKTOOL_AUTHENTICATION = False # Sakai LMS Linktool authentication
+LINKTOOL_AUTH_URL = 'https://...' # fixme, add documentation
#----------------------------------------------------------------------
# Stuff that probably belongs in a config table in the database, with
diff --git a/conifer/settings.py b/conifer/settings.py
index 2494d06..02e7f6a 100644
--- a/conifer/settings.py
+++ b/conifer/settings.py
@@ -77,7 +77,7 @@ ROOT_URLCONF = 'conifer.urls'
TEMPLATE_DIRS = []
-INSTALLED_APPS = (
+INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
@@ -85,7 +85,7 @@ INSTALLED_APPS = (
'django.contrib.admin',
'south',
'conifer.syrup',
-)
+]
AUTH_PROFILE_MODULE = 'syrup.UserProfile'
@@ -94,6 +94,9 @@ AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend'
]
+EVERGREEN_AUTHENTICATION = False
+LINKTOOL_AUTHENTICATION = False
+
#---------------------------------------------------------------------------
# local_settings.py
@@ -120,5 +123,9 @@ if EVERGREEN_AUTHENTICATION:
AUTHENTICATION_BACKENDS.append(
'conifer.integration.auth_evergreen.django.EvergreenAuthBackend')
-#----------
+if LINKTOOL_AUTHENTICATION:
+ AUTHENTICATION_BACKENDS.append(
+ 'conifer.integration.linktool.backend.LinktoolAuthBackend')
+ INSTALLED_APPS.append(
+ 'conifer.integration.linktool.app')
diff --git a/conifer/syrup/integration.py b/conifer/syrup/integration.py
index 1b7a9d9..7ca2e3c 100644
--- a/conifer/syrup/integration.py
+++ b/conifer/syrup/integration.py
@@ -100,3 +100,12 @@ def marcxml_to_url(marc_string):
codes and $u holds the URLs.
"""
+@disable
+def external_person_lookup(userid):
+ """
+ Given a userid, return either None (if the user cannot be found),
+ or a dictionary representing the user. The dictionary must contain
+ the keys ('given_name', 'surname') and should contain 'email' if
+ an email address is known.
+ """
+
diff --git a/conifer/templates/tabbar.xhtml b/conifer/templates/tabbar.xhtml
index 303dcad..2601e17 100644
--- a/conifer/templates/tabbar.xhtml
+++ b/conifer/templates/tabbar.xhtml
@@ -7,6 +7,9 @@
use one for now
-->
+ -
+ Return to CLEW
+
- Browse
- My Reserves
diff --git a/conifer/urls.py b/conifer/urls.py
index 8d0679a..f0ec87f 100644
--- a/conifer/urls.py
+++ b/conifer/urls.py
@@ -37,3 +37,10 @@ urlpatterns = patterns('',
if not settings.DEBUG:
handler500 = 'conifer.syrup.views.custom_500_handler'
handler404b = 'conifer.syrup.views.custom_400_handler'
+
+
+if settings.LINKTOOL_AUTHENTICATION:
+ urlpatterns += patterns(
+ 'conifer.integration.linktool.app',
+ (r'^linktool-welcome/$', 'linktool_welcome'))
+