Commit aad4f470 by Sebastian Annies

added template method configurable in settings for populating the user object

parent 2c3bf9e1
......@@ -3,6 +3,7 @@
== Version 2.1.1 ==
* Bug Fix Release
* Added a template method for populating user object
== Version 2.1.0 ==
......
......@@ -42,6 +42,7 @@ Optional settings include:
* CAS_RETRY_LOGIN: If True and an unknown or invalid ticket is received, the user is redirected back to the login page.
* CAS_VERSION: The CAS protocol version to use. '1' and '2' are supported, with '2' being the default.
* CAS_PROXY_CALLBACK: The URL given to the CAS server in order to initialize a proxy ticket. The ticket granting ticket will be sent to this URL. The url must be registered in urls.py and handled by django_cas.views.proxy_callback, e.g: ``(r'^accounts/login/casProxyCallback$', 'django_cas.views.proxy_callback')``
* CAS_USER_DETAILS_RESOLVER: template method for populating the user object.
Make sure your project knows how to log users in and out by adding these to your URL mappings:
......@@ -50,33 +51,34 @@ Make sure your project knows how to log users in and out by adding these to your
Users should now be able to log into your site (and staff into the administration interface) using CAS.
Managing Access to the Admin Interface
--------------------------------------
Populating The User Object From CAS 2.0 Attributes
--------------------------------------------------
At the moment, the best way to give a user access to the admin interface is by doing one of the following:
Since there are manyfold ways transmitting user attributes in CAS and even more ways to map them
on django.auth.User the mapping is done via a template method.
Create the initial superuser account with a username that matches the desired user. django_cas will be able to make use of the existing user.
Similarly, create database fixtures for the superusers, and load them when deploying the application.
Ask the user to sign in to the application and, as an admin, log into the admin interface and change their access through the Users table.
Populating User Data
To add user data, subclass CASBackend and specify that as your application's backend.
The template method is defined via the ``CAS_USER_DETAILS_RESOLVER`` setting::
CAS_USER_DETAILS_RESOLVER = cas_integration.populate_user
and an example method would be::
CAS_URI = 'http://www.yale.edu/tp/cas'
NSMAP = {'cas': CAS_URI}
CAS = '{%s}' % CAS_URI
def populate_user(user, authentication_response):
if authentication_response.find(CAS + 'authenticationSuccess/' + CAS + 'attributes' , namespaces=NSMAP) is not None:
attr = authentication_response.find(CAS + 'authenticationSuccess/' + CAS + 'attributes' , namespaces=NSMAP)
if attr.find(CAS + 'is_superuser', NSMAP) is not None:
user.is_superuser = attr.find(CAS + 'is_superuser', NSMAP).text.upper() == 'TRUE'
if attr.find(CAS + 'is_staff', NSMAP) is not None:
user.is_staff = attr.find(CAS + 'is_staff', NSMAP).text.upper() == 'TRUE'
pass
For example::
from django_cas.backends import CASBackend
class PopulatedCASBackend(CASBackend):
"""CAS authentication backend with user data populated from AD"""
def authenticate(self, ticket, service):
"""Authenticates CAS ticket and retrieves user data"""
user = super(PopulatedCASBackend, self).authenticate(
ticket, service)
# Connect to AD, modify user object, etc.
return user
Preventing Infinite Redirects
-----------------------------
......@@ -127,11 +129,9 @@ Version 2.0 of django_cas breaks compatibility in some small ways, in order simp
CAS_LOGIN_URL and CAS_LOGOUT_URL: Version 2.0 is capable of determining these automatically.
CAS_POPULATE_USER: Subclass CASBackend instead (see above).
CAS_REDIRECT_FIELD_NAME: Django's own REDIRECT_FIELD_NAME is now used unconditionally.
CAS_USER_DETAILS_RESOLVER: template method for populating user object
Ed Crewe 2 Dec 2010
====================
Add proxy authentication
------------------------
......
......@@ -25,9 +25,9 @@ def _verify_cas1(ticket, service):
try:
verified = page.readline().strip()
if verified == 'yes':
return page.readline().strip()
return page.readline().strip(), None
else:
return None
return None, None
finally:
page.close()
......@@ -71,9 +71,9 @@ def _verify_cas2(ticket, service):
Tgt.objects.create(username = username, tgt = pgtIou.tgt)
pgtIou.delete()
return username
return username, tree
else:
return None
return None, tree
def verify_proxy_ticket(ticket, service):
......@@ -117,6 +117,9 @@ if settings.CAS_VERSION not in _PROTOCOLS:
_verify = _PROTOCOLS[settings.CAS_VERSION]
_CAS_USER_DETAILS_RESOLVER = getattr(settings, 'CAS_USER_DETAILS_RESOLVER', None)
class CASBackend(object):
"""CAS authentication backend"""
......@@ -124,15 +127,18 @@ class CASBackend(object):
"""Verifies CAS ticket and gets or creates User object
NB: Use of PT to identify proxy
"""
username = _verify(ticket, service)
username, authentication_response = _verify(ticket, service)
if not username:
return None
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
# user will have an "unusable" password
user = User.objects.create_user(username, '')
user.save()
user, created = User.objects.get_or_create(username=username)
if created:
user.set_unusable_password()
if authentication_response and _CAS_USER_DETAILS_RESOLVER:
_CAS_USER_DETAILS_RESOLVER(user, authentication_response)
user.save()
return user
def get_user(self, user_id):
......@@ -142,3 +148,4 @@ class CASBackend(object):
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment