Commit 9a7ce56f by Ed Crewe

add the original patch file

parent 34b53889
Index: setup.py
===================================================================
--- setup.py (revision 1175)
+++ setup.py (arbetskopia)
@@ -37,5 +37,5 @@
name='django_cas',
packages=['django_cas'],
url='http://code.google.com/p/django-cas/',
- version='2.0.3',
+ version='2.0.3-KTH-2',
)
Index: django_cas/backends.py
===================================================================
--- django_cas/backends.py (revision 1175)
+++ django_cas/backends.py (arbetskopia)
@@ -4,9 +4,9 @@
from urlparse import urljoin
from django.conf import settings
+from django.core.exceptions import ObjectDoesNotExist
+from django_cas.models import User, Tgt, PgtIOU
-from django_cas.models import User
-
__all__ = ['CASBackend']
def _verify_cas1(ticket, service):
@@ -40,21 +40,71 @@
except ImportError:
from elementtree import ElementTree
+ if settings.CAS_PROXY_CALLBACK:
+ params = {'ticket': ticket, 'service': service, 'pgtUrl': settings.CAS_PROXY_CALLBACK}
+ else:
+ params = {'ticket': ticket, 'service': service}
+
+ url = (urljoin(settings.CAS_SERVER_URL, 'proxyValidate') + '?' +
+ urlencode(params))
+
+ page = urlopen(url)
+
+ try:
+ response = page.read()
+ tree = ElementTree.fromstring(response)
+ if tree[0].tag.endswith('authenticationSuccess'):
+ username = tree[0][0].text
+ if len(tree[0]) >= 2 and tree[0][1].tag.endswith('proxyGrantingTicket'):
+ pgtIou = PgtIOU.objects.get(pgtIou = tree[0][1].text)
+ try:
+ tgt = Tgt.objects.get(username = username)
+ tgt.tgt = pgtIou.tgt
+ tgt.save()
+ except ObjectDoesNotExist:
+ Tgt.objects.create(username = username, tgt = pgtIou.tgt)
+
+ pgtIou.delete()
+ return username
+ else:
+ return None
+ finally:
+ page.close()
+
+
+def verify_proxy_ticket(ticket, service):
+ """Verifies CAS 2.0+ XML-based proxy ticket.
+
+ Returns username on success and None on failure.
+ """
+
+ try:
+ from xml.etree import ElementTree
+ except ImportError:
+ from elementtree import ElementTree
+
params = {'ticket': ticket, 'service': service}
+
url = (urljoin(settings.CAS_SERVER_URL, 'proxyValidate') + '?' +
urlencode(params))
+
page = urlopen(url)
+
try:
response = page.read()
tree = ElementTree.fromstring(response)
if tree[0].tag.endswith('authenticationSuccess'):
- return tree[0][0].text
+ username = tree[0][0].text
+ proxies = []
+ for element in tree[0][1]:
+ proxies.append(element.text)
+ return {"username": username, "proxies": proxies}
else:
return None
finally:
page.close()
+
-
_PROTOCOLS = {'1': _verify_cas1, '2': _verify_cas2}
if settings.CAS_VERSION not in _PROTOCOLS:
Index: django_cas/middleware.py
===================================================================
--- django_cas/middleware.py (revision 1175)
+++ django_cas/middleware.py (arbetskopia)
@@ -1,13 +1,13 @@
"""CAS authentication middleware"""
from urllib import urlencode
-
-from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
+from django.contrib.auth import logout as do_logout
from django.contrib.auth.views import login, logout
from django.core.urlresolvers import reverse
-
+from django.http import HttpResponseRedirect, HttpResponseForbidden
+from django_cas.exceptions import CasTicketException
from django_cas.views import login as cas_login, logout as cas_logout
__all__ = ['CASMiddleware']
@@ -50,3 +50,13 @@
return HttpResponseForbidden(error)
params = urlencode({REDIRECT_FIELD_NAME: request.get_full_path()})
return HttpResponseRedirect(reverse(cas_login) + '?' + params)
+
+ def process_exception(self, request, exception):
+ """When we get a CasTicketException, that is probably caused by the ticket timing out.
+ So logout/login and get the same page again."""
+ if isinstance(exception, CasTicketException):
+ do_logout(request)
+ # This assumes that request.path requires authentication.
+ return HttpResponseRedirect(request.path)
+ else:
+ return None
Index: django_cas/views.py
===================================================================
--- django_cas/views.py (revision 1175)
+++ django_cas/views.py (arbetskopia)
@@ -3,9 +3,10 @@
from urllib import urlencode
from urlparse import urljoin
-from django.http import get_host, HttpResponseRedirect, HttpResponseForbidden
+from django.http import get_host, HttpResponseRedirect, HttpResponseForbidden, HttpResponse
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
+from django_cas.models import PgtIOU
__all__ = ['login', 'logout']
@@ -76,6 +77,7 @@
if ticket:
from django.contrib import auth
user = auth.authenticate(ticket=ticket, service=service)
+
if user is not None:
auth.login(request, user)
name = user.first_name or user.username
@@ -102,3 +104,18 @@
return HttpResponseRedirect(_logout_url(request, next_page))
else:
return HttpResponseRedirect(next_page)
+
+def proxy_callback(request):
+ """Handles CAS 2.0+ XML-based proxy callback call.
+
+ Stores the proxy granting ticket in the database for
+ future use.
+ """
+ pgtIou = request.GET.get('pgtIou')
+ tgt = request.GET.get('pgtId')
+
+ if not (pgtIou and tgt):
+ return HttpResponse()
+
+ PgtIOU.objects.create(tgt = tgt, pgtIou = pgtIou)
+ return HttpResponse()
Index: django_cas/__init__.py
===================================================================
--- django_cas/__init__.py (revision 1175)
+++ django_cas/__init__.py (arbetskopia)
@@ -11,6 +11,7 @@
'CAS_LOGOUT_COMPLETELY': True,
'CAS_REDIRECT_URL': '/',
'CAS_RETRY_LOGIN': False,
+ 'CAS_PROXY_CALLBACK': None,
'CAS_SERVER_URL': None,
'CAS_VERSION': '2',
}
Index: django_cas/exceptions.py
===================================================================
--- django_cas/exceptions.py (revision 0)
+++ django_cas/exceptions.py (revision 1216)
@@ -0,0 +1,13 @@
+class CasTicketException(Exception):
+ def __init__(self, error):
+ self.error = error
+
+ def __str__(self):
+ return repr(self.error)
+
+class CasConfigException(Exception):
+ def __init__(self, error):
+ self.error = error
+
+ def __str__(self):
+ return repr(self.error)
Index: django_cas/models.py
===================================================================
--- django_cas/models.py (revision 1175)
+++ django_cas/models.py (arbetskopia)
@@ -1,2 +1,55 @@
+from urlparse import urljoin
+from urllib import urlencode, urlopen
from django.db import models
-from django.contrib.auth.models import User
\ No newline at end of file
+from django.conf import settings
+from django.contrib.auth.models import User
+from django.core.exceptions import ObjectDoesNotExist
+from django_cas.exceptions import CasTicketException, CasConfigException
+
+class Tgt(models.Model):
+ username = models.CharField(max_length = 255, unique = True)
+ tgt = models.CharField(max_length = 255)
+
+ def get_proxy_ticket_for(self, service):
+ """Verifies CAS 2.0+ XML-based authentication ticket.
+
+ Returns username on success and None on failure.
+ """
+ if not settings.CAS_PROXY_CALLBACK:
+ raise CasConfigException("No proxy callback set in settings")
+
+ try:
+ from xml.etree import ElementTree
+ except ImportError:
+ from elementtree import ElementTree
+
+ params = {'pgt': self.tgt, 'targetService': service}
+
+ url = (urljoin(settings.CAS_SERVER_URL, 'proxy') + '?' +
+ urlencode(params))
+
+ page = urlopen(url)
+
+ try:
+ response = page.read()
+ tree = ElementTree.fromstring(response)
+ if tree[0].tag.endswith('proxySuccess'):
+ return tree[0][0].text
+ else:
+ raise CasTicketException("Failed to get proxy ticket")
+ finally:
+ page.close()
+
+class PgtIOU(models.Model):
+ pgtIou = models.CharField(max_length = 255, unique = True)
+ tgt = models.CharField(max_length = 255)
+ timestamp = models.DateTimeField(auto_now = True)
+
+def get_tgt_for(user):
+ if not settings.CAS_PROXY_CALLBACK:
+ raise CasConfigException("No proxy callback set in settings")
+
+ try:
+ return Tgt.objects.get(username = user.username)
+ except ObjectDoesNotExist:
+ raise CasTicketException("no ticket found for user " + user.username)
Index: NEWS.txt
===================================================================
--- NEWS.txt (revision 1175)
+++ NEWS.txt (arbetskopia)
@@ -1,5 +1,9 @@
= Release Notes =
+== Version X.X.X ==
+
+ * Added support for CAS proxy authentication.
+
== Version 2.0.3 ==
* Added `CAS_EXTRA_LOGIN_PARAMS` setting (patched contributed by frasern).
Index: README.txt
===================================================================
--- README.txt (revision 1175)
+++ README.txt (arbetskopia)
@@ -43,7 +43,11 @@
http://sso.some.edu/cas/).
Optional settings include:
-
+ * `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_ADMIN_PREFIX`: The URL prefix of the Django administration site.
If undefined, the CAS middleware will check the view being rendered to
see if it lives in `django.contrib.admin.views`.
@@ -125,7 +129,23 @@
For more information see http://code.djangoproject.com/ticket/4617.
+== CAS proxy tickets ==
+Using CAS proxy tickets is quite a bit less trivial than ordinary tickets.
+First of all the CAS server requires that the Django site can be accessed
+via https, and it MUST have a properly signed certificate that the CAS
+server can verify.
+
+For the test-server this can be achieved using a tunneling application
+such as stunnel. However this is not enough. The CAS proxy auhentication
+requires that both the web browser and the CAS server simoultaneously can
+make requests to the Django server, which the Django test server does not
+support.
+
+However, there is a Django app you can use to be able to start a threaded
+test server hosted here:
+http://github.com/jaylett/django_concurrent_test_server
+
== Customizing the 403 Error Page ==
Django doesn't provide a simple way to customize 403 error pages, so you'll
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