Use only classe view, put ticket prefix as config option

This commit is contained in:
Valentin Samir 2015-05-29 19:27:54 +02:00
parent e1549dd6ff
commit ff74a07965
5 changed files with 315 additions and 224 deletions

View file

@ -27,6 +27,11 @@ setting_default('CAS_TICKET_VALIDITY', 300)
setting_default('CAS_TICKET_TIMEOUT', 24*3600) setting_default('CAS_TICKET_TIMEOUT', 24*3600)
setting_default('CAS_PROXY_CA_CERTIFICATE_PATH', True) setting_default('CAS_PROXY_CA_CERTIFICATE_PATH', True)
setting_default('CAS_SERVICE_TICKET_PREFIX', 'ST')
setting_default('CAS_PROXY_TICKET_PREFIX', 'PT')
setting_default('CAS_PROXY_GRANTING_TICKET_PREFIX', 'PGT')
setting_default('CAS_PROXY_GRANTING_TICKET_IOU_PREFIX', 'PGTIOU')
setting_default('CAS_SQL_HOST', 'localhost') setting_default('CAS_SQL_HOST', 'localhost')
setting_default('CAS_SQL_USERNAME', '') setting_default('CAS_SQL_USERNAME', '')
setting_default('CAS_SQL_PASSWORD', '') setting_default('CAS_SQL_PASSWORD', '')
@ -36,3 +41,6 @@ setting_default('CAS_SQL_USER_QUERY', 'SELECT user AS usersame, pass AS ' \
'password, users.* FROM users WHERE user = %s') 'password, users.* FROM users WHERE user = %s')
setting_default('CAS_SQL_PASSWORD_CHECK', 'crypt') # crypt or plain setting_default('CAS_SQL_PASSWORD_CHECK', 'crypt') # crypt or plain
def noop():
"""do nothing"""
pass

View file

@ -357,16 +357,19 @@ class Ticket(models.Model):
class ServiceTicket(Ticket): class ServiceTicket(Ticket):
"""A Service Ticket""" """A Service Ticket"""
PREFIX = settings.CAS_SERVICE_TICKET_PREFIX
value = models.CharField(max_length=255, default=utils.gen_st, unique=True) value = models.CharField(max_length=255, default=utils.gen_st, unique=True)
def __unicode__(self): def __unicode__(self):
return u"ServiceTicket(%s, %s, %s)" % (self.user, self.value, self.service) return u"ServiceTicket(%s, %s, %s)" % (self.user, self.value, self.service)
class ProxyTicket(Ticket): class ProxyTicket(Ticket):
"""A Proxy Ticket""" """A Proxy Ticket"""
PREFIX = settings.CAS_PROXY_TICKET_PREFIX
value = models.CharField(max_length=255, default=utils.gen_pt, unique=True) value = models.CharField(max_length=255, default=utils.gen_pt, unique=True)
def __unicode__(self): def __unicode__(self):
return u"ProxyTicket(%s, %s, %s)" % (self.user, self.value, self.service) return u"ProxyTicket(%s, %s, %s)" % (self.user, self.value, self.service)
class ProxyGrantingTicket(Ticket): class ProxyGrantingTicket(Ticket):
"""A Proxy Granting Ticket""" """A Proxy Granting Ticket"""
PREFIX = settings.CAS_PROXY_GRANTING_TICKET_PREFIX
value = models.CharField(max_length=255, default=utils.gen_pgt, unique=True) value = models.CharField(max_length=255, default=utils.gen_pgt, unique=True)
def __unicode__(self): def __unicode__(self):
return u"ProxyGrantingTicket(%s, %s, %s)" % (self.user, self.value, self.service) return u"ProxyGrantingTicket(%s, %s, %s)" % (self.user, self.value, self.service)

View file

@ -20,12 +20,12 @@ urlpatterns = patterns(
url(r'^$', RedirectView.as_view(pattern_name="login")), url(r'^$', RedirectView.as_view(pattern_name="login")),
url('^login$', views.LoginView.as_view(), name='login'), url('^login$', views.LoginView.as_view(), name='login'),
url('^logout$', views.LogoutView.as_view(), name='logout'), url('^logout$', views.LogoutView.as_view(), name='logout'),
url('^validate$', views.validate, name='validate'), url('^validate$', views.Validate.as_view(), name='validate'),
url('^serviceValidate$', views.service_validate, name='serviceValidate'), url('^serviceValidate$', views.ValidateService.as_view(allow_proxy_ticket=False), name='serviceValidate'),
url('^proxyValidate$', views.proxy_validate, name='proxyValidate'), url('^proxyValidate$', views.ValidateService.as_view(allow_proxy_ticket=True), name='proxyValidate'),
url('^proxy$', views.proxy, name='proxy'), url('^proxy$', views.Proxy.as_view(), name='proxy'),
url('^p3/serviceValidate$', views.p3_service_validate, name='p3_serviceValidate'), url('^p3/serviceValidate$', views.ValidateService.as_view(allow_proxy_ticket=False), name='p3_serviceValidate'),
url('^p3/proxyValidate$', views.p3_proxy_validate, name='p3_proxyValidate'), url('^p3/proxyValidate$', views.ValidateService.as_view(allow_proxy_ticket=True), name='p3_proxyValidate'),
url('^samlValidate$', views.saml_validate, name='samlValidate'), url('^samlValidate$', views.SamlValidate.as_view(), name='samlValidate'),
) )

View file

@ -62,20 +62,21 @@ def _gen_ticket(prefix):
def gen_st(): def gen_st():
"""Generate a Service Ticket""" """Generate a Service Ticket"""
return _gen_ticket('ST') return _gen_ticket(settings.CAS_SERVICE_TICKET_PREFIX)
def gen_pt(): def gen_pt():
"""Generate a Proxy Ticket""" """Generate a Proxy Ticket"""
return _gen_ticket('PT') return _gen_ticket(settings.CAS_PROXY_TICKET_PREFIX)
def gen_pgt(): def gen_pgt():
"""Generate a Proxy Granting Ticket""" """Generate a Proxy Granting Ticket"""
return _gen_ticket('PGT') return _gen_ticket(settings.CAS_PROXY_GRANTING_TICKET_PREFIX)
def gen_pgtiou(): def gen_pgtiou():
"""Generate a Proxy Granting Ticket IOU""" """Generate a Proxy Granting Ticket IOU"""
return _gen_ticket('PGTIOU') return _gen_ticket(settings.CAS_PROXY_GRANTING_TICKET_IOU_PREFIX)
def gen_saml_id(): def gen_saml_id():
"""Generate an saml id"""
return _gen_ticket('_') return _gen_ticket('_')

View file

@ -12,18 +12,20 @@
"""views for the app""" """views for the app"""
from . import default_settings from . import default_settings
default_settings.noop()
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.http import HttpResponse, HttpResponseRedirect from django.http import HttpResponse, HttpResponseRedirect
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
from django.utils import timezone from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View from django.views.generic import View
import requests import requests
import urllib
from lxml import etree from lxml import etree
from datetime import timedelta from datetime import timedelta
@ -31,8 +33,24 @@ from . import utils
from . import forms from . import forms
from . import models from . import models
class AttributesMixin(object):
"""mixin for the attributs methode"""
# pylint: disable=too-few-public-methods
def attributes(self):
"""regerate attributes list for template rendering"""
attributes = []
for key, value in self.ticket.attributs.items():
if isinstance(value, list):
for elt in value:
attributes.append((key, elt))
else:
attributes.append((key, value))
return attributes
class LogoutMixin(object): class LogoutMixin(object):
"""destroy CAS session utims""" """destroy CAS session utils"""
def clean_session_variables(self): def clean_session_variables(self):
"""Clean sessions variables""" """Clean sessions variables"""
try: try:
@ -263,204 +281,260 @@ class LoginView(View, LogoutMixin):
else: else:
return self.not_authenticated() return self.not_authenticated()
def validate(request): class Validate(View):
"""service ticket validation""" """service ticket validation"""
service = request.GET.get('service') @staticmethod
ticket = request.GET.get('ticket') def get(request):
renew = True if request.GET.get('renew') else False """methode called on GET request on this view"""
if service and ticket: service = request.GET.get('service')
try: ticket = request.GET.get('ticket')
ticket = models.ServiceTicket.objects.get( renew = True if request.GET.get('renew') else False
value=ticket, if service and ticket:
service=service, try:
validate=False,
renew=renew,
creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
)
ticket.validate = True
ticket.save()
return HttpResponse("yes\n", content_type="text/plain")
except models.ServiceTicket.DoesNotExist:
return HttpResponse("no\n", content_type="text/plain")
else:
return HttpResponse("no\n", content_type="text/plain")
def _validate_error(request, code, msg=""):
"""render the serviceValidateError.xml template using `code` and `msg`"""
return render(
request,
"cas_server/serviceValidateError.xml",
{'code':code, 'msg':msg},
content_type="text/xml; charset=utf-8"
)
def ps_validate(request, ticket_type=None):
"""factorization for serviceValidate and proxyValidate"""
if ticket_type is None:
ticket_type = ['ST']
service = request.GET.get('service')
ticket = request.GET.get('ticket')
pgt_url = request.GET.get('pgtUrl')
renew = True if request.GET.get('renew') else False
if service and ticket:
for elt in ticket_type:
if ticket.startswith(elt):
break
else:
return _validate_error(
request,
'INVALID_TICKET',
'tickets should begin with %s' % ' or '.join(ticket_type)
)
try:
proxies = []
if ticket.startswith("ST"):
ticket = models.ServiceTicket.objects.get( ticket = models.ServiceTicket.objects.get(
value=ticket, value=ticket,
service=service,
validate=False, validate=False,
renew=renew, renew=renew,
creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY)) creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
) )
elif ticket.startswith("PT"): ticket.validate = True
ticket = models.ProxyTicket.objects.get( ticket.save()
value=ticket, return HttpResponse("yes\n", content_type="text/plain")
except models.ServiceTicket.DoesNotExist:
return HttpResponse("no\n", content_type="text/plain")
else:
return HttpResponse("no\n", content_type="text/plain")
class ValidateError(Exception):
"""handle service validation error"""
def __init__(self, code, msg=""):
self.code = code
self.msg = msg
super(ValidateError).__init__(code)
def __unicode__(self):
return u"%s" % self.msg
def render(self, request):
"""render the error template for the exception"""
return render(
request,
"cas_server/serviceValidateError.xml",
{'code':self.code, 'msg':self.msg},
content_type="text/xml; charset=utf-8"
)
class ValidateService(View, AttributesMixin):
"""service ticket validation [CAS 2.0] and [CAS 3.0]"""
request = None
service = None
ticket = None
pgt_url = None
renew = None
allow_proxy_ticket = None
def get(self, request, allow_proxy_ticket=False):
"""methode called on GET request on this view"""
self.request = request
self.allow_proxy_ticket = allow_proxy_ticket
self.service = request.GET.get('service')
self.ticket = request.GET.get('ticket')
self.pgt_url = request.GET.get('pgtUrl')
self.renew = True if request.GET.get('renew') else False
if not self.service or not self.ticket:
return ValidateError(
'INVALID_REQUEST',
"you must specify a service and a ticket"
).render(request)
else:
try:
self.ticket, proxies = self.process_ticket()
params = {
'username':self.ticket.user.username,
'attributes':self.attributes(),
'proxies':proxies
}
if self.ticket.service_pattern.user_field and \
self.ticket.user.attributs.get(self.ticket.service_pattern.user_field):
params['username'] = self.ticket.user.attributs.get(
self.ticket.service_pattern.user_field
)
if self.pgt_url and self.pgt_url.startswith("https://"):
return self.process_pgturl(params)
else:
return render(
request,
"cas_server/serviceValidate.xml",
params,
content_type="text/xml; charset=utf-8"
)
except ValidateError as error:
return error.render(request)
def process_ticket(self):
"""fetch the ticket angains the database and check its validity"""
try:
proxies = []
if self.ticket.startswith(models.ServiceTicket.PREFIX):
ticket = models.ServiceTicket.objects.get(
value=self.ticket,
validate=False, validate=False,
renew=renew, renew=self.renew,
creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
)
elif self.allow_proxy_ticket and self.ticket.startswith(models.ProxyTicket.PREFIX):
ticket = models.ProxyTicket.objects.get(
value=self.ticket,
validate=False,
renew=self.renew,
creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY)) creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
) )
for prox in ticket.proxies.all(): for prox in ticket.proxies.all():
proxies.append(prox.url) proxies.append(prox.url)
else:
raise ValidateError('INVALID_TICKET')
ticket.validate = True ticket.validate = True
ticket.save() ticket.save()
if ticket.service != service: if ticket.service != self.service:
return _validate_error(request, 'INVALID_SERVICE') raise ValidateError('INVALID_SERVICE')
attributes = [] return ticket, proxies
for key, value in ticket.attributs.items():
if isinstance(value, list):
for elt in value:
attributes.append((key, elt))
else:
attributes.append((key, value))
params = {'username':ticket.user.username, 'attributes':attributes, 'proxies':proxies}
if ticket.service_pattern.user_field and \
ticket.user.attributs.get(ticket.service_pattern.user_field):
params['username'] = ticket.user.attributs.get(ticket.service_pattern.user_field)
if pgt_url and pgt_url.startswith("https://"):
pattern = models.ServicePattern.validate(pgt_url)
if pattern.proxy_callback:
proxyid = utils.gen_pgtiou()
pticket = models.ProxyGrantingTicket.objects.create(
user=ticket.user,
service=pgt_url,
service_pattern=pattern,
single_log_out=pattern.single_log_out
)
url = utils.update_url(pgt_url, {'pgtIou':proxyid, 'pgtId':pticket.value})
try:
ret = requests.get(url, verify=settings.CAS_PROXY_CA_CERTIFICATE_PATH)
if ret.status_code == 200:
params['proxyGrantingTicket'] = proxyid
else:
pticket.delete()
return render(
request,
"cas_server/serviceValidate.xml",
params,
content_type="text/xml; charset=utf-8"
)
except requests.exceptions.SSLError as error:
error = utils.unpack_nested_exception(error)
return _validate_error(request, 'INVALID_PROXY_CALLBACK', str(error))
else:
return _validate_error(
request,
'INVALID_PROXY_CALLBACK',
"callback url not allowed by configuration"
)
else:
return render(
request,
"cas_server/serviceValidate.xml",
params,
content_type="text/xml; charset=utf-8"
)
except (models.ServiceTicket.DoesNotExist, models.ProxyTicket.DoesNotExist): except (models.ServiceTicket.DoesNotExist, models.ProxyTicket.DoesNotExist):
return _validate_error(request, 'INVALID_TICKET', 'ticket not found') raise ValidateError('INVALID_TICKET', 'ticket not found')
def process_pgturl(self, params):
"""Handle PGT request"""
try:
pattern = models.ServicePattern.validate(self.pgt_url)
if pattern.proxy_callback:
proxyid = utils.gen_pgtiou()
pticket = models.ProxyGrantingTicket.objects.create(
user=self.ticket.user,
service=self.pgt_url,
service_pattern=pattern,
single_log_out=pattern.single_log_out
)
url = utils.update_url(self.pgt_url, {'pgtIou':proxyid, 'pgtId':pticket.value})
try:
ret = requests.get(url, verify=settings.CAS_PROXY_CA_CERTIFICATE_PATH)
if ret.status_code == 200:
params['proxyGrantingTicket'] = proxyid
else:
pticket.delete()
return render(
self.request,
"cas_server/serviceValidate.xml",
params,
content_type="text/xml; charset=utf-8"
)
except requests.exceptions.SSLError as error:
error = utils.unpack_nested_exception(error)
raise ValidateError('INVALID_PROXY_CALLBACK', str(error))
else:
raise ValidateError(
'INVALID_PROXY_CALLBACK',
"callback url not allowed by configuration"
)
except models.ServicePattern.DoesNotExist: except models.ServicePattern.DoesNotExist:
return _validate_error( raise ValidateError(
request,
'INVALID_PROXY_CALLBACK', 'INVALID_PROXY_CALLBACK',
'callback url not allowed by configuration' 'callback url not allowed by configuration'
) )
else:
return _validate_error(
request,
'INVALID_REQUEST',
"you must specify a service and a ticket"
)
def service_validate(request): class Proxy(View):
"""service ticket validation CAS 2.0 (also work for CAS 3.0)"""
return ps_validate(request)
def proxy_validate(request):
"""service/proxy ticket validation CAS 2.0 (also work for CAS 3.0)"""
return ps_validate(request, ["ST", "PT"])
def proxy(request):
"""proxy ticket service""" """proxy ticket service"""
pgt = request.GET.get('pgt')
target_service = request.GET.get('targetService') request = None
if pgt and target_service: pgt = None
target_service = None
def get(self, request):
"""methode called on GET request on this view"""
self.request = request
self.pgt = request.GET.get('pgt')
self.target_service = request.GET.get('targetService')
try:
if self.pgt and self.target_service:
return self.process_proxy()
else:
raise ValidateError(
'INVALID_REQUEST',
"you must specify and pgt and targetService"
)
except ValidateError as error:
return error.render(request)
def process_proxy(self):
"""handle PT request"""
try: try:
# is the target service allowed # is the target service allowed
pattern = models.ServicePattern.validate(target_service) pattern = models.ServicePattern.validate(self.target_service)
if not pattern.proxy: if not pattern.proxy:
return _validate_error( raise ValidateError(
request,
'UNAUTHORIZED_SERVICE', 'UNAUTHORIZED_SERVICE',
'the service do not allow proxy ticket' 'the service do not allow proxy ticket'
) )
# is the proxy granting ticket valid # is the proxy granting ticket valid
ticket = models.ProxyGrantingTicket.objects.get( ticket = models.ProxyGrantingTicket.objects.get(
value=pgt, value=self.pgt,
creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY)) creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
) )
# is the pgt user allowed on the target service # is the pgt user allowed on the target service
pattern.check_user(ticket.user) pattern.check_user(ticket.user)
pticket = ticket.user.get_ticket(models.ProxyTicket, target_service, pattern, False) pticket = ticket.user.get_ticket(
models.ProxyTicket,
self.target_service,
pattern,
renew=False)
pticket.proxies.create(url=ticket.service) pticket.proxies.create(url=ticket.service)
return render( return render(
request, self.request,
"cas_server/proxy.xml", "cas_server/proxy.xml",
{'ticket':pticket.value}, {'ticket':pticket.value},
content_type="text/xml; charset=utf-8" content_type="text/xml; charset=utf-8"
) )
except models.ProxyGrantingTicket.DoesNotExist: except models.ProxyGrantingTicket.DoesNotExist:
return _validate_error(request, 'INVALID_TICKET', 'PGT not found') raise ValidateError('INVALID_TICKET', 'PGT not found')
except models.ServicePattern.DoesNotExist: except models.ServicePattern.DoesNotExist:
return _validate_error(request, 'UNAUTHORIZED_SERVICE') raise ValidateError('UNAUTHORIZED_SERVICE')
except (models.BadUsername, models.BadFilter, models.UserFieldNotDefined): except (models.BadUsername, models.BadFilter, models.UserFieldNotDefined):
return _validate_error( raise ValidateError(
request,
'UNAUTHORIZED_USER', 'UNAUTHORIZED_USER',
'%s not allowed on %s' % (ticket.user, target_service) '%s not allowed on %s' % (ticket.user, self.target_service)
) )
else:
return _validate_error(
class SamlValidateError(Exception):
"""handle saml validation error"""
def __init__(self, code, msg=""):
self.code = code
self.msg = msg
super(SamlValidateError).__init__(code)
def __unicode__(self):
return u"%s" % self.msg
def render(self, request):
"""render the error template for the exception"""
return render(
request, request,
'INVALID_REQUEST', "cas_server/samlValidateError.xml",
"you must specify and pgt and targetService" {
'code':self.code,
'msg':self.msg,
'IssueInstant':timezone.now().isoformat(),
'ResponseID':utils.gen_saml_id()
},
content_type="text/xml; charset=utf-8"
) )
def p3_service_validate(request):
"""service ticket validation CAS 3.0"""
return service_validate(request)
def p3_proxy_validate(request):
"""service/proxy ticket validation CAS 3.0"""
return proxy_validate(request)
def _saml_validate_error(request, code, msg=""): def _saml_validate_error(request, code, msg=""):
"""render the samlValidateError.xml templace using `code` and `msg`""" """render the samlValidateError.xml templace using `code` and `msg`"""
return render( return render(
@ -475,76 +549,81 @@ def _saml_validate_error(request, code, msg=""):
content_type="text/xml; charset=utf-8" content_type="text/xml; charset=utf-8"
) )
@csrf_exempt class SamlValidate(View, AttributesMixin):
def saml_validate(request): """SAML ticket validation"""
"""checks the validity of a Service Ticket by a SAML 1.1 request""" request = None
if request.method == 'POST': target = None
target = request.GET.get('TARGET') ticket = None
root = etree.fromstring(request.body) root = None
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
"""dispatch requests based on method GET, POST, ..."""
return super(SamlValidation, self).dispatch(request, *args, **kwargs)
def post(self, request):
"""methode called on POST request on this view"""
self.request = request
self.target = request.GET.get('TARGET')
self.root = etree.fromstring(request.body)
try: try:
auth_req = root.getchildren()[1].getchildren()[0] self.ticket = self.process_ticket()
issue_instant = auth_req.attrib['IssueInstant'] expire_instant = (self.ticket.creation + \
request_id = auth_req.attrib['RequestID']
ticket = auth_req.getchildren()[0].text
if ticket.startswith("ST"):
ticket = models.ServiceTicket.objects.get(
value=ticket,
validate=False,
creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
)
elif ticket.startswith("PT"):
ticket = models.ProxyTicket.objects.get(
value=ticket,
validate=False,
creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
)
else:
return _saml_validate_error(
request,
'AuthnFailed',
'ticket should begin with PT- or ST-'
)
ticket.validate = True
ticket.save()
if ticket.service != target:
return _saml_validate_error(
request,
'AuthnFailed',
'TARGET do not match ticket service'
)
expire_instant = (ticket.creation + \
timedelta(seconds=settings.CAS_TICKET_VALIDITY)).isoformat() timedelta(seconds=settings.CAS_TICKET_VALIDITY)).isoformat()
attributes = [] attributes = self.attributes()
for key, value in ticket.attributs.items():
if isinstance(value, list):
for elt in value:
attributes.append((key, elt))
else:
attributes.append((key, value))
params = { params = {
'IssueInstant':issue_instant, 'IssueInstant':timezone.now().isoformat(),
'expireInstant':expire_instant, 'expireInstant':expire_instant,
'Recipient':target, 'Recipient':self.target,
'ResponseID':utils.gen_saml_id(), 'ResponseID':utils.gen_saml_id(),
'username':ticket.user.username, 'username':self.ticket.user.username,
'attributes':attributes 'attributes':attributes
} }
if ticket.service_pattern.user_field and \ if self.ticket.service_pattern.user_field and \
ticket.user.attributs.get(ticket.service_pattern.user_field): self.ticket.user.attributs.get(self.ticket.service_pattern.user_field):
params['username'] = ticket.user.attributs.get(ticket.service_pattern.user_field) params['username'] = self.ticket.user.attributs.get(
self.ticket.service_pattern.user_field
)
return render( return render(
request, request,
"cas_server/samlValidate.xml", "cas_server/samlValidate.xml",
params, params,
content_type="text/xml; charset=utf-8" content_type="text/xml; charset=utf-8"
) )
except SamlValidateError as error:
return error.render(request)
def process_ticket(self):
"""validate ticket from SAML XML body"""
try:
auth_req = self.root.getchildren()[1].getchildren()[0]
ticket = auth_req.getchildren()[0].text
if ticket.startswith(models.ServiceTicket.PREFIX):
ticket = models.ServiceTicket.objects.get(
value=ticket,
validate=False,
creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
)
elif ticket.startswith(models.ProxyTicket.PREFIX):
ticket = models.ProxyTicket.objects.get(
value=ticket,
validate=False,
creation__gt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
)
else:
raise SamlValidateError(
'AuthnFailed',
'ticket should begin with PT- or ST-'
)
ticket.validate = True
ticket.save()
if ticket.service != self.target:
raise SamlValidateError(
'AuthnFailed',
'TARGET do not match ticket service'
)
return ticket
except (IndexError, KeyError): except (IndexError, KeyError):
return _saml_validate_error(request, 'VersionMismatch') raise SamlValidateError('VersionMismatch')
except (models.ServiceTicket.DoesNotExist, models.ProxyTicket.DoesNotExist): except (models.ServiceTicket.DoesNotExist, models.ProxyTicket.DoesNotExist):
return _saml_validate_error(request, 'AuthnFailed', 'ticket not found') raise SamlValidateError('AuthnFailed', 'ticket not found')
else:
return _saml_validate_error(
request,
'VersionMismatch',
'request should be send using POST'
)