[open-ils-commits] r969 - in servres/trunk: . conifer conifer/integration conifer/plumbing conifer/syrup conifer/syrup/views conifer/templates (gfawcett)

svn at svn.open-ils.org svn at svn.open-ils.org
Tue Aug 17 22:46:19 EDT 2010


Author: gfawcett
Date: 2010-08-17 22:46:17 -0400 (Tue, 17 Aug 2010)
New Revision: 969

Added:
   servres/trunk/conifer/integration/cas.py
Modified:
   servres/trunk/.gitignore
   servres/trunk/conifer/integration/uwindsor.py
   servres/trunk/conifer/plumbing/hooksystem.py
   servres/trunk/conifer/settings.py
   servres/trunk/conifer/syrup/integration.py
   servres/trunk/conifer/syrup/views/_common.py
   servres/trunk/conifer/syrup/views/genshi_namespace.py
   servres/trunk/conifer/templates/browse_index.xhtml
   servres/trunk/conifer/templates/master.xhtml
   servres/trunk/conifer/templates/search_results.xhtml
   servres/trunk/conifer/urls.py
Log:
CAS authentication.

See: http://code.google.com/p/django-cas/

To use CAS authentication, you must "easy_install django-cas", then add these
to your local_settings.py:

CAS_AUTHENTICATION = True
CAS_SERVER_URL     = 'https://my.cas.server.example.net/cas/'

You will probably also want to define two customization hooks:
external_person_lookup and user_needs_decoration. See:
conifer/syrup/integration.py.

Modified: servres/trunk/.gitignore
===================================================================
--- servres/trunk/.gitignore	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/.gitignore	2010-08-18 02:46:17 UTC (rev 969)
@@ -13,3 +13,4 @@
 /conifer/remodel.sqlite3
 *~
 /conifer/test.db
+/conifer/syrup/test.db

Added: servres/trunk/conifer/integration/cas.py
===================================================================
--- servres/trunk/conifer/integration/cas.py	                        (rev 0)
+++ servres/trunk/conifer/integration/cas.py	2010-08-18 02:46:17 UTC (rev 969)
@@ -0,0 +1,53 @@
+# CAS authentication. See http://code.google.com/p/django-cas/
+#
+# To use CAS authentication, you must "easy_install django-cas", then add these
+# to your local_settings.py:
+#
+# CAS_AUTHENTICATION = True
+# CAS_SERVER_URL     = 'https://my.cas.server.example.net/cas/'
+#
+# You will probably also want to define two customization hooks:
+# external_person_lookup and user_needs_decoration. See:
+# conifer/syrup/integration.py.
+
+from conifer.plumbing.hooksystem import gethook, callhook
+import django_cas.backends
+
+
+class CASBackend(django_cas.backends.CASBackend):
+
+    def authenticate(self, ticket, service):
+        """Authenticates CAS ticket and retrieves user data"""
+
+        user = super(CASBackend, self).authenticate(ticket, service)
+        if user and gethook('external_person_lookup'):
+            decorate_user(user)
+        return user
+
+
+# TODO is this really CAS specific? Wouldn't linktool (for example)
+# also need such a decorator?
+
+def decorate_user(user):
+    dectest = gethook('user_needs_decoration', default=_user_needs_decoration)
+    if not dectest(user):
+        return
+
+    dir_entry = callhook('external_person_lookup', user.username)
+    if dir_entry is None:
+        return
+
+    user.first_name = dir_entry['given_name']
+    user.last_name  = dir_entry['surname']
+    user.email      = dir_entry.get('email', user.email)
+    user.save()
+
+    if 'patron_id' in dir_entry:
+        # note, we overrode user.get_profile() to automatically create
+        # missing profiles. See models.py.
+        user.get_profile().ils_userid = dir_entry['patron_id']
+        profile.save()
+
+
+def _user_needs_decoration(user):
+    return user.last_name is not None

Modified: servres/trunk/conifer/integration/uwindsor.py
===================================================================
--- servres/trunk/conifer/integration/uwindsor.py	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/integration/uwindsor.py	2010-08-18 02:46:17 UTC (rev 969)
@@ -135,7 +135,8 @@
     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.
+    an email address is known, and 'patron_id' if a library-system ID
+    is known.
     """
     return uwindsor_campus_info.call('person_lookup', userid)
 

Modified: servres/trunk/conifer/plumbing/hooksystem.py
===================================================================
--- servres/trunk/conifer/plumbing/hooksystem.py	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/plumbing/hooksystem.py	2010-08-18 02:46:17 UTC (rev 969)
@@ -6,8 +6,6 @@
 __all__ = ['callhook', 'callhook_required', 'gethook']
 
 def gethook(name, default=None):
-    print dir(HOOKS)
-    print (name, getattr(HOOKS, name))
     return getattr(HOOKS, name) or default
 
 def callhook_required(name, *args, **kwargs):
@@ -19,3 +17,5 @@
     f = getattr(HOOKS, name)
     if f:
         return f(*args, **kwargs)
+    else:
+        return None

Modified: servres/trunk/conifer/settings.py
===================================================================
--- servres/trunk/conifer/settings.py	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/settings.py	2010-08-18 02:46:17 UTC (rev 969)
@@ -87,9 +87,11 @@
     'conifer.syrup',
 ]
 
+LOGIN_URL  = '/accounts/login/'
+LOGOUT_URL = '/accounts/logout'
+
 AUTH_PROFILE_MODULE = 'syrup.UserProfile'
 
-
 AUTHENTICATION_BACKENDS = [
     'django.contrib.auth.backends.ModelBackend'
 ]
@@ -97,6 +99,10 @@
 EVERGREEN_AUTHENTICATION = False
 LINKTOOL_AUTHENTICATION  = False
 
+# CAS authentication requires 'django-cas', 
+# http://code.google.com/p/django-cas/
+CAS_AUTHENTICATION       = False  
+
 #---------------------------------------------------------------------------
 # local_settings.py
 
@@ -126,3 +132,8 @@
 if LINKTOOL_AUTHENTICATION:
     AUTHENTICATION_BACKENDS.append(
         'conifer.integration.linktool.backend.LinktoolAuthBackend')
+
+if CAS_AUTHENTICATION:
+    AUTHENTICATION_BACKENDS.append('conifer.integration.cas.CASBackend')
+    LOGIN_URL  = '/cas/login'
+    LOGOUT_URL = '/cas/logout'

Modified: servres/trunk/conifer/syrup/integration.py
===================================================================
--- servres/trunk/conifer/syrup/integration.py	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/syrup/integration.py	2010-08-18 02:46:17 UTC (rev 969)
@@ -109,3 +109,14 @@
     an email address is known.
     """
 
+ at disable
+def user_needs_decoration(user_obj):
+    """
+    User objects are sometimes created automatically, with only a
+    username. This function determines whether it would be fruitful to
+    "decorate" the User object with, e.g., a given name, surname, and
+    email address. It doesn't perform the decoration, it simply tests
+    whether the current user object is "incomplete." Another hook
+    'external_person_lookup,' is used by Syrup to fetch the personal
+    information when needed.
+    """

Modified: servres/trunk/conifer/syrup/views/_common.py
===================================================================
--- servres/trunk/conifer/syrup/views/_common.py	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/syrup/views/_common.py	2010-08-18 02:46:17 UTC (rev 969)
@@ -4,10 +4,12 @@
 # is a module which acts as a global namespace when expanding a Genshi
 # template.
 
+from .                               import genshi_namespace
 from conifer.here                    import HERE
 from conifer.plumbing.genshi_support import TemplateSet
-from .                               import genshi_namespace
+from django.conf                     import settings
 
+
 g = TemplateSet(HERE('templates'), genshi_namespace)
 
 #----------------------------------------------------------------------
@@ -48,10 +50,11 @@
 def _access_denied(request, message):
     if request.user.is_anonymous():
         # then take them to login screen....
-        dest = (request.META['SCRIPT_NAME'] + \
-                    '/accounts/login/?next=%s%s' % (
-                request.META['SCRIPT_NAME'],
-                request.META['PATH_INFO']))
+        dest = (request.META['SCRIPT_NAME'] + 
+                settings.LOGIN_URL +
+                '?next=' +
+                request.META['SCRIPT_NAME'] +
+                request.META['PATH_INFO'])
         return HttpResponseRedirect(dest)
     else:
         return simple_message(_('Access denied.'), message,

Modified: servres/trunk/conifer/syrup/views/genshi_namespace.py
===================================================================
--- servres/trunk/conifer/syrup/views/genshi_namespace.py	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/syrup/views/genshi_namespace.py	2010-08-18 02:46:17 UTC (rev 969)
@@ -13,4 +13,5 @@
 
 from conifer.plumbing.hooksystem import gethook, callhook
 from conifer.syrup               import models
+from django.conf                 import settings
 from django.utils.translation    import ugettext as _

Modified: servres/trunk/conifer/templates/browse_index.xhtml
===================================================================
--- servres/trunk/conifer/templates/browse_index.xhtml	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/templates/browse_index.xhtml	2010-08-18 02:46:17 UTC (rev 969)
@@ -15,7 +15,7 @@
   <h1>${title}</h1> 
   <div py:if="user.is_anonymous()">
     (Note: some reserve materials may require you
-    to <a href="${ROOT}/accounts/login/?next=${ROOT}/">log in</a>)
+    to <a href="${ROOT}${settings.LOGIN_URL}?next=${ROOT}/">log in</a>)
   </div>
 
     

Modified: servres/trunk/conifer/templates/master.xhtml
===================================================================
--- servres/trunk/conifer/templates/master.xhtml	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/templates/master.xhtml	2010-08-18 02:46:17 UTC (rev 969)
@@ -51,12 +51,12 @@
         </div>
       <div id="welcome" py:if="user.is_authenticated()">
 	<strong style="padding-right: 18px;">Welcome, ${user.first_name or user.username}!</strong>
-	<a href="${ROOT}/accounts/logout">Log Out</a>
+	<a href="${ROOT}${settings.LOGOUT_URL}">Log Out</a>
 	&bull; <a href="${ROOT}/prefs/">Preferences</a>
       </div>
       <div id="welcome" py:if="not user.is_authenticated()">
 	<strong style="padding-right: 18px;">Welcome!</strong>
-	<a class="loginbutton" href="${ROOT}/accounts/login/">Log In</a>
+	<a class="loginbutton" href="${ROOT}${settings.LOGIN_URL}">Log In</a>
 	&bull; <a href="${ROOT}/prefs/">Preferences</a>
       </div>
     </div>

Modified: servres/trunk/conifer/templates/search_results.xhtml
===================================================================
--- servres/trunk/conifer/templates/search_results.xhtml	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/templates/search_results.xhtml	2010-08-18 02:46:17 UTC (rev 969)
@@ -53,7 +53,7 @@
 
     <div py:if="user.is_anonymous()">
       Your searches may return more results if you <a
-      href="${ROOT}/accounts/login/?next=${ROOT}/">log in</a> before
+      href="${ROOT}${settings.LOGIN_URL}?next=${ROOT}/">log in</a> before
       searching.
     </div>
 

Modified: servres/trunk/conifer/urls.py
===================================================================
--- servres/trunk/conifer/urls.py	2010-08-18 02:45:46 UTC (rev 968)
+++ servres/trunk/conifer/urls.py	2010-08-18 02:46:17 UTC (rev 969)
@@ -47,3 +47,9 @@
         (r'^linktool-welcome/copy_old$', 'linktool_copy_old'),
         (r'^linktool-welcome/associate$', 'linktool_associate'),
         )
+
+if settings.CAS_AUTHENTICATION:
+    urlpatterns += patterns(
+        'django_cas.views',
+    (r'^%s$' % settings.LOGIN_URL[1:],  'login'),
+    (r'^%s$' % settings.LOGOUT_URL[1:], 'logout'))



More information about the open-ils-commits mailing list