Compatibility with different session backend + admin layout
This commit is contained in:
parent
245086f6ef
commit
77fc5b5988
7 changed files with 83 additions and 23 deletions
|
@ -14,25 +14,35 @@ from .models import ServiceTicket, ProxyTicket, ProxyGrantingTicket, User, Servi
|
||||||
from .models import Username, ReplaceAttributName, ReplaceAttributValue, FilterAttributValue
|
from .models import Username, ReplaceAttributName, ReplaceAttributValue, FilterAttributValue
|
||||||
from .forms import TicketForm
|
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):
|
class ServiceTicketInline(admin.TabularInline):
|
||||||
"""`ServiceTicket` in admin interface"""
|
"""`ServiceTicket` in admin interface"""
|
||||||
model = ServiceTicket
|
model = ServiceTicket
|
||||||
extra = 0
|
extra = 0
|
||||||
form = TicketForm
|
form = TicketForm
|
||||||
|
readonly_fields = tickets_readonly_fields
|
||||||
|
fields = tickets_fields
|
||||||
class ProxyTicketInline(admin.TabularInline):
|
class ProxyTicketInline(admin.TabularInline):
|
||||||
"""`ProxyTicket` in admin interface"""
|
"""`ProxyTicket` in admin interface"""
|
||||||
model = ProxyTicket
|
model = ProxyTicket
|
||||||
extra = 0
|
extra = 0
|
||||||
form = TicketForm
|
form = TicketForm
|
||||||
|
readonly_fields = tickets_readonly_fields
|
||||||
|
fields = tickets_fields
|
||||||
class ProxyGrantingInline(admin.TabularInline):
|
class ProxyGrantingInline(admin.TabularInline):
|
||||||
"""`ProxyGrantingTicket` in admin interface"""
|
"""`ProxyGrantingTicket` in admin interface"""
|
||||||
model = ProxyGrantingTicket
|
model = ProxyGrantingTicket
|
||||||
extra = 0
|
extra = 0
|
||||||
form = TicketForm
|
form = TicketForm
|
||||||
|
readonly_fields = tickets_readonly_fields
|
||||||
|
fields = tickets_fields[1:]
|
||||||
|
|
||||||
class UserAdmin(admin.ModelAdmin):
|
class UserAdmin(admin.ModelAdmin):
|
||||||
"""`User` in admin interface"""
|
"""`User` in admin interface"""
|
||||||
inlines = (ServiceTicketInline, ProxyTicketInline, ProxyGrantingInline)
|
inlines = (ServiceTicketInline, ProxyTicketInline, ProxyGrantingInline)
|
||||||
|
readonly_fields=('username', 'date', "session_key")
|
||||||
|
fields = ('username', 'date', "session_key")
|
||||||
|
|
||||||
class UsernamesInline(admin.TabularInline):
|
class UsernamesInline(admin.TabularInline):
|
||||||
"""`Username` in admin interface"""
|
"""`Username` in admin interface"""
|
||||||
|
|
|
@ -20,7 +20,7 @@ import models
|
||||||
class UserCredential(forms.Form):
|
class UserCredential(forms.Form):
|
||||||
"""Form used on the login page to retrive user credentials"""
|
"""Form used on the login page to retrive user credentials"""
|
||||||
username = forms.CharField(label=_('login'))
|
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)
|
password = forms.CharField(label=_('password'), widget=forms.PasswordInput)
|
||||||
lt = forms.CharField(widget=forms.HiddenInput(), required=False)
|
lt = forms.CharField(widget=forms.HiddenInput(), required=False)
|
||||||
method = 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()
|
cleaned_data = super(UserCredential, self).clean()
|
||||||
auth = utils.import_attr(settings.CAS_AUTH_CLASS)(cleaned_data.get("username"))
|
auth = utils.import_attr(settings.CAS_AUTH_CLASS)(cleaned_data.get("username"))
|
||||||
if auth.test_password(cleaned_data.get("password")):
|
if auth.test_password(cleaned_data.get("password")):
|
||||||
session = utils.get_session(self.request)
|
|
||||||
try:
|
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()
|
user.save()
|
||||||
except models.User.DoesNotExist:
|
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()
|
user.save()
|
||||||
else:
|
else:
|
||||||
raise forms.ValidationError(_(u"Bad user"))
|
raise forms.ValidationError(_(u"Bad user"))
|
||||||
|
@ -50,4 +55,4 @@ class TicketForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Ticket
|
model = models.Ticket
|
||||||
exclude = []
|
exclude = []
|
||||||
service = forms.CharField(widget=forms.TextInput)
|
service = forms.CharField(label=_('service'), widget=forms.TextInput)
|
||||||
|
|
11
cas_server/management/commands/cas_clean_sessions.py
Normal file
11
cas_server/management/commands/cas_clean_sessions.py
Normal 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()
|
28
cas_server/migrations/0021_auto_20150611_2102.py
Normal file
28
cas_server/migrations/0021_auto_20150611_2102.py
Normal 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',
|
||||||
|
),
|
||||||
|
]
|
|
@ -17,33 +17,44 @@ from django.db.models import Q
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.sessions.models import Session
|
|
||||||
from picklefield.fields import PickledObjectField
|
from picklefield.fields import PickledObjectField
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from importlib import import_module
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from requests_futures.sessions import FuturesSession
|
from requests_futures.sessions import FuturesSession
|
||||||
|
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
|
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
|
||||||
|
|
||||||
class User(models.Model):
|
class User(models.Model):
|
||||||
"""A user logged into the CAS"""
|
"""A user logged into the CAS"""
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("username", "session")
|
unique_together = ("username", "session_key")
|
||||||
session = models.OneToOneField(Session, related_name="cas_server_user", blank=True, null=True, on_delete=models.SET_NULL)
|
session_key = models.CharField(max_length=40, blank=True, null=True)
|
||||||
username = models.CharField(max_length=30)
|
username = models.CharField(max_length=30)
|
||||||
date = models.DateTimeField(auto_now_add=True, auto_now=True)
|
date = models.DateTimeField(auto_now_add=True, auto_now=True)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def clean_old_entries(cls):
|
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:
|
for user in users:
|
||||||
user.logout()
|
user.logout()
|
||||||
users.delete()
|
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
|
@property
|
||||||
def attributs(self):
|
def attributs(self):
|
||||||
"""return a fresh dict for the user attributs"""
|
"""return a fresh dict for the user attributs"""
|
||||||
|
@ -108,6 +119,7 @@ class User(models.Model):
|
||||||
single_log_out=service_pattern.single_log_out
|
single_log_out=service_pattern.single_log_out
|
||||||
)
|
)
|
||||||
ticket.save()
|
ticket.save()
|
||||||
|
self.save()
|
||||||
return ticket
|
return ticket
|
||||||
|
|
||||||
def get_service_url(self, service, service_pattern, renew):
|
def get_service_url(self, service, service_pattern, renew):
|
||||||
|
@ -321,7 +333,7 @@ class Ticket(models.Model):
|
||||||
TIMEOUT = settings.CAS_TICKET_TIMEOUT
|
TIMEOUT = settings.CAS_TICKET_TIMEOUT
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"Ticket(%s, %s)" % (self.user, self.service)
|
return u"Ticket-%s" % self.pk
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def clean_old_entries(cls):
|
def clean_old_entries(cls):
|
||||||
|
@ -394,13 +406,13 @@ class ServiceTicket(Ticket):
|
||||||
PREFIX = settings.CAS_SERVICE_TICKET_PREFIX
|
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" % self.pk
|
||||||
class ProxyTicket(Ticket):
|
class ProxyTicket(Ticket):
|
||||||
"""A Proxy Ticket"""
|
"""A Proxy Ticket"""
|
||||||
PREFIX = settings.CAS_PROXY_TICKET_PREFIX
|
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" % self.pk
|
||||||
class ProxyGrantingTicket(Ticket):
|
class ProxyGrantingTicket(Ticket):
|
||||||
"""A Proxy Granting Ticket"""
|
"""A Proxy Granting Ticket"""
|
||||||
PREFIX = settings.CAS_PROXY_GRANTING_TICKET_PREFIX
|
PREFIX = settings.CAS_PROXY_GRANTING_TICKET_PREFIX
|
||||||
|
@ -409,7 +421,7 @@ class ProxyGrantingTicket(Ticket):
|
||||||
|
|
||||||
|
|
||||||
def __unicode__(self):
|
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):
|
class Proxy(models.Model):
|
||||||
"""A list of proxies on `ProxyTicket`"""
|
"""A list of proxies on `ProxyTicket`"""
|
||||||
|
|
|
@ -15,7 +15,6 @@ from .default_settings import settings
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.contrib.sessions.models import Session
|
|
||||||
|
|
||||||
import urlparse
|
import urlparse
|
||||||
import urllib
|
import urllib
|
||||||
|
@ -102,8 +101,3 @@ def gen_pgtiou():
|
||||||
def gen_saml_id():
|
def gen_saml_id():
|
||||||
"""Generate an saml id"""
|
"""Generate an saml id"""
|
||||||
return _gen_ticket('_')
|
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)
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ class LogoutMixin(object):
|
||||||
try:
|
try:
|
||||||
user = models.User.objects.get(
|
user = models.User.objects.get(
|
||||||
username=self.request.session.get("username"),
|
username=self.request.session.get("username"),
|
||||||
session=utils.get_session(self.request)
|
session_key=self.request.session_key
|
||||||
)
|
)
|
||||||
user.logout(self.request)
|
user.logout(self.request)
|
||||||
user.delete()
|
user.delete()
|
||||||
|
@ -156,7 +156,7 @@ class LoginView(View, LogoutMixin):
|
||||||
if self.form.is_valid():
|
if self.form.is_valid():
|
||||||
self.user = models.User.objects.get(
|
self.user = models.User.objects.get(
|
||||||
username=self.form.cleaned_data['username'],
|
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.set_expiry(0)
|
||||||
request.session["username"] = self.form.cleaned_data['username']
|
request.session["username"] = self.form.cleaned_data['username']
|
||||||
|
@ -263,7 +263,7 @@ class LoginView(View, LogoutMixin):
|
||||||
try:
|
try:
|
||||||
self.user = models.User.objects.get(
|
self.user = models.User.objects.get(
|
||||||
username=self.request.session.get("username"),
|
username=self.request.session.get("username"),
|
||||||
session=utils.get_session(self.request)
|
session_key=self.request.session_key
|
||||||
)
|
)
|
||||||
except models.User.DoesNotExist:
|
except models.User.DoesNotExist:
|
||||||
self.logout()
|
self.logout()
|
||||||
|
@ -351,7 +351,7 @@ class Auth(View):
|
||||||
try:
|
try:
|
||||||
user = models.User.objects.get(
|
user = models.User.objects.get(
|
||||||
username=form.cleaned_data['username'],
|
username=form.cleaned_data['username'],
|
||||||
session=utils.get_session(request)
|
session_key=self.request.session_key
|
||||||
)
|
)
|
||||||
# is the service allowed
|
# is the service allowed
|
||||||
service_pattern = ServicePattern.validate(service)
|
service_pattern = ServicePattern.validate(service)
|
||||||
|
|
Loading…
Reference in a new issue