From 02872d218fb506d82d94a9b554b98a1dbfab593b Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Thu, 28 May 2015 17:30:27 +0200 Subject: [PATCH] Django command to clean old tickets --- cas_server/default_settings.py | 1 + cas_server/management/__init__.py | 0 cas_server/management/commands/__init__.py | 0 .../management/commands/cas_clean_tickets.py | 12 ++++ cas_server/models.py | 57 ++++++++++++++++--- 5 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 cas_server/management/__init__.py create mode 100644 cas_server/management/commands/__init__.py create mode 100644 cas_server/management/commands/cas_clean_tickets.py diff --git a/cas_server/default_settings.py b/cas_server/default_settings.py index ecef7bb..22caa2d 100644 --- a/cas_server/default_settings.py +++ b/cas_server/default_settings.py @@ -24,6 +24,7 @@ setting_default('CAS_LOGGED_TEMPLATE', 'cas_server/logged.html') setting_default('CAS_AUTH_CLASS', auth.DjangoAuthUser) setting_default('CAS_ST_LEN', 30) setting_default('CAS_TICKET_VALIDITY', 300) +setting_default('CAS_TICKET_TIMEOUT', 24*3600) setting_default('CAS_PROXY_CA_CERTIFICATE_PATH', True) setting_default('CAS_SQL_HOST', 'localhost') diff --git a/cas_server/management/__init__.py b/cas_server/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cas_server/management/commands/__init__.py b/cas_server/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cas_server/management/commands/cas_clean_tickets.py b/cas_server/management/commands/cas_clean_tickets.py new file mode 100644 index 0000000..71a2877 --- /dev/null +++ b/cas_server/management/commands/cas_clean_tickets.py @@ -0,0 +1,12 @@ +from django.core.management.base import BaseCommand, CommandError +from django.utils.translation import ugettext_lazy as _ + +from ... import models + +class Command(BaseCommand): + args = '' + help = _(u"Clean old trickets") + + def handle(self, *args, **options): + for ticket_class in [models.ServiceTicket, models.ProxyTicket, models.ProxyGrantingTicket]: + ticket_class.clean() diff --git a/cas_server/models.py b/cas_server/models.py index 8c1b783..3a36e86 100644 --- a/cas_server/models.py +++ b/cas_server/models.py @@ -10,7 +10,11 @@ # # (c) 2015 Valentin Samir """models for the app""" +from . import default_settings + +from django.conf import settings from django.db import models +from django.db.models import Q from django.contrib import messages from picklefield.fields import PickledObjectField from django.utils.translation import ugettext_lazy as _ @@ -18,7 +22,8 @@ from django.utils import timezone import re import os - +import sys +from datetime import timedelta from concurrent.futures import ThreadPoolExecutor from requests_futures.sessions import FuturesSession @@ -285,6 +290,39 @@ class Ticket(models.Model): def __unicode__(self): return u"Ticket(%s, %s)" % (self.user, self.service) + @classmethod + def clean(cls): + """Remove old ticket and send SLO to timed-out services""" + # removing old validated ticket and non validated expired tickets + cls.objects.filter( + ( + Q(single_log_out=False)&Q(validate=True) + )|( + Q(validate=False)&\ + Q(creation__lt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))) + ) + ).delete() + + # sending SLO to timed-out validated tickets + if settings.CAS_TICKET_TIMEOUT and \ + settings.CAS_TICKET_TIMEOUT >= settings.CAS_TICKET_VALIDITY: + async_list = [] + session = FuturesSession(executor=ThreadPoolExecutor(max_workers=10)) + queryset = cls.objects.filter( + single_log_out=True, + validate=True, + creation__lt=(timezone.now() - timedelta(seconds=settings.CAS_TICKET_TIMEOUT)) + ) + for ticket in queryset: + async_list.append(ticket.logout(None, session)) + queryset.delete() + for future in async_list: + if future: + try: + future.result() + except Exception as error: + sys.stderr.write("%r\n" % error) + def logout(self, request, session): """Send a SLO request to the ticket service""" if self.validate and self.single_log_out: @@ -306,13 +344,16 @@ class Ticket(models.Model): headers=headers ) except Exception as error: - error = utils.unpack_nested_exception(error) - messages.add_message( - request, - messages.WARNING, - _(u'Error during service logout %(service)s:\n%(error)s') % - {'service': self.service, 'error':error} - ) + if request is not None: + error = utils.unpack_nested_exception(error) + messages.add_message( + request, + messages.WARNING, + _(u'Error during service logout %(service)s:\n%(error)s') % + {'service': self.service, 'error':error} + ) + else: + sys.stderr.write("%r\n" % error) class ServiceTicket(Ticket): """A Service Ticket"""