Compatibility with different session backend + admin layout

This commit is contained in:
Valentin Samir 2015-06-11 23:04:26 +02:00
parent 245086f6ef
commit 77fc5b5988
7 changed files with 83 additions and 23 deletions

View file

@ -14,25 +14,35 @@ from .models import ServiceTicket, ProxyTicket, ProxyGrantingTicket, User, Servi
from .models import Username, ReplaceAttributName, ReplaceAttributValue, FilterAttributValue
from .forms import TicketForm
tickets_readonly_fields=('validate', 'service', 'service_pattern', 'creation', 'renew', 'single_log_out', 'value')
tickets_fields = ('validate', 'service', 'service_pattern', 'creation', 'renew', 'single_log_out')
class ServiceTicketInline(admin.TabularInline):
"""`ServiceTicket` in admin interface"""
model = ServiceTicket
extra = 0
form = TicketForm
readonly_fields = tickets_readonly_fields
fields = tickets_fields
class ProxyTicketInline(admin.TabularInline):
"""`ProxyTicket` in admin interface"""
model = ProxyTicket
extra = 0
form = TicketForm
readonly_fields = tickets_readonly_fields
fields = tickets_fields
class ProxyGrantingInline(admin.TabularInline):
"""`ProxyGrantingTicket` in admin interface"""
model = ProxyGrantingTicket
extra = 0
form = TicketForm
readonly_fields = tickets_readonly_fields
fields = tickets_fields[1:]
class UserAdmin(admin.ModelAdmin):
"""`User` in admin interface"""
inlines = (ServiceTicketInline, ProxyTicketInline, ProxyGrantingInline)
readonly_fields=('username', 'date', "session_key")
fields = ('username', 'date', "session_key")
class UsernamesInline(admin.TabularInline):
"""`Username` in admin interface"""

View file

@ -20,7 +20,7 @@ import models
class UserCredential(forms.Form):
"""Form used on the login page to retrive user credentials"""
username = forms.CharField(label=_('login'))
service = forms.CharField(widget=forms.HiddenInput(), required=False)
service = forms.CharField(label=_('service'), widget=forms.HiddenInput(), required=False)
password = forms.CharField(label=_('password'), widget=forms.PasswordInput)
lt = forms.CharField(widget=forms.HiddenInput(), required=False)
method = forms.CharField(widget=forms.HiddenInput(), required=False)
@ -34,12 +34,17 @@ class UserCredential(forms.Form):
cleaned_data = super(UserCredential, self).clean()
auth = utils.import_attr(settings.CAS_AUTH_CLASS)(cleaned_data.get("username"))
if auth.test_password(cleaned_data.get("password")):
session = utils.get_session(self.request)
try:
user = models.User.objects.get(username=auth.username, session=session)
user = models.User.objects.get(
username=auth.username,
session_key=self.request.session_key
)
user.save()
except models.User.DoesNotExist:
user = models.User.objects.create(username=auth.username, session=session)
user = models.User.objects.create(
username=auth.username,
session_key=self.request.session_key
)
user.save()
else:
raise forms.ValidationError(_(u"Bad user"))
@ -50,4 +55,4 @@ class TicketForm(forms.ModelForm):
class Meta:
model = models.Ticket
exclude = []
service = forms.CharField(widget=forms.TextInput)
service = forms.CharField(label=_('service'), widget=forms.TextInput)

View file

@ -0,0 +1,11 @@
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 deleted sessions")
def handle(self, *args, **options):
models.User.clean_deleted_sessions()

View file

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('cas_server', '0020_auto_20150609_1917'),
]
operations = [
migrations.AddField(
model_name='user',
name='session_key',
field=models.CharField(max_length=40, null=True, blank=True),
preserve_default=True,
),
migrations.AlterUniqueTogether(
name='user',
unique_together=set([('username', 'session_key')]),
),
migrations.RemoveField(
model_name='user',
name='session',
),
]

View file

@ -17,33 +17,44 @@ from django.db.models import Q
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.contrib.sessions.models import Session
from picklefield.fields import PickledObjectField
import re
import os
import sys
from importlib import import_module
from datetime import timedelta
from concurrent.futures import ThreadPoolExecutor
from requests_futures.sessions import FuturesSession
import utils
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
class User(models.Model):
"""A user logged into the CAS"""
class Meta:
unique_together = ("username", "session")
session = models.OneToOneField(Session, related_name="cas_server_user", blank=True, null=True, on_delete=models.SET_NULL)
unique_together = ("username", "session_key")
session_key = models.CharField(max_length=40, blank=True, null=True)
username = models.CharField(max_length=30)
date = models.DateTimeField(auto_now_add=True, auto_now=True)
@classmethod
def clean_old_entries(cls):
users = cls.objects.filter(session=None)
users = cls.objects.filter(
date__lt=(timezone.now() - timedelta(seconds=settings.SESSION_COOKIE_AGE))
)
for user in users:
user.logout()
users.delete()
@classmethod
def clean_deleted_sessions(cls):
for user in cls.objects.all():
if not SessionStore(session_key=user.session_key).get('authenticated'):
user.logout()
user.delete()
@property
def attributs(self):
"""return a fresh dict for the user attributs"""
@ -108,6 +119,7 @@ class User(models.Model):
single_log_out=service_pattern.single_log_out
)
ticket.save()
self.save()
return ticket
def get_service_url(self, service, service_pattern, renew):
@ -321,7 +333,7 @@ class Ticket(models.Model):
TIMEOUT = settings.CAS_TICKET_TIMEOUT
def __unicode__(self):
return u"Ticket(%s, %s)" % (self.user, self.service)
return u"Ticket-%s" % self.pk
@classmethod
def clean_old_entries(cls):
@ -394,13 +406,13 @@ class ServiceTicket(Ticket):
PREFIX = settings.CAS_SERVICE_TICKET_PREFIX
value = models.CharField(max_length=255, default=utils.gen_st, unique=True)
def __unicode__(self):
return u"ServiceTicket(%s, %s, %s)" % (self.user, self.value, self.service)
return u"ServiceTicket-%s" % self.pk
class ProxyTicket(Ticket):
"""A Proxy Ticket"""
PREFIX = settings.CAS_PROXY_TICKET_PREFIX
value = models.CharField(max_length=255, default=utils.gen_pt, unique=True)
def __unicode__(self):
return u"ProxyTicket(%s, %s, %s)" % (self.user, self.value, self.service)
return u"ProxyTicket-%s" % self.pk
class ProxyGrantingTicket(Ticket):
"""A Proxy Granting Ticket"""
PREFIX = settings.CAS_PROXY_GRANTING_TICKET_PREFIX
@ -409,7 +421,7 @@ class ProxyGrantingTicket(Ticket):
def __unicode__(self):
return u"ProxyGrantingTicket(%s, %s, %s)" % (self.user, self.value, self.service)
return u"ProxyGrantingTicket-%s" % self.pk
class Proxy(models.Model):
"""A list of proxies on `ProxyTicket`"""

View file

@ -15,7 +15,6 @@ from .default_settings import settings
from django.utils.importlib import import_module
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.contrib.sessions.models import Session
import urlparse
import urllib
@ -102,8 +101,3 @@ def gen_pgtiou():
def gen_saml_id():
"""Generate an saml id"""
return _gen_ticket('_')
def get_session(request):
if not request.session.exists(request.session.session_key):
request.session.create()
return Session.objects.get(session_key=request.session.session_key)

View file

@ -71,7 +71,7 @@ class LogoutMixin(object):
try:
user = models.User.objects.get(
username=self.request.session.get("username"),
session=utils.get_session(self.request)
session_key=self.request.session_key
)
user.logout(self.request)
user.delete()
@ -156,7 +156,7 @@ class LoginView(View, LogoutMixin):
if self.form.is_valid():
self.user = models.User.objects.get(
username=self.form.cleaned_data['username'],
session=utils.get_session(self.request)
session_key=self.request.session_key
)
request.session.set_expiry(0)
request.session["username"] = self.form.cleaned_data['username']
@ -263,7 +263,7 @@ class LoginView(View, LogoutMixin):
try:
self.user = models.User.objects.get(
username=self.request.session.get("username"),
session=utils.get_session(self.request)
session_key=self.request.session_key
)
except models.User.DoesNotExist:
self.logout()
@ -351,7 +351,7 @@ class Auth(View):
try:
user = models.User.objects.get(
username=form.cleaned_data['username'],
session=utils.get_session(request)
session_key=self.request.session_key
)
# is the service allowed
service_pattern = ServicePattern.validate(service)