Login/Logout view are now class views

This commit is contained in:
Valentin Samir 2015-05-29 16:11:10 +02:00
parent 02872d218f
commit a0b1a095e4
3 changed files with 204 additions and 144 deletions

View file

@ -18,8 +18,8 @@ from . import views
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'^$', RedirectView.as_view(pattern_name="login")), url(r'^$', RedirectView.as_view(pattern_name="login")),
url('^login$', views.login, name='login'), url('^login$', views.LoginView.as_view(), name='login'),
url('^logout$', views.logout, name='logout'), url('^logout$', views.LogoutView.as_view(), name='logout'),
url('^validate$', views.validate, name='validate'), url('^validate$', views.validate, name='validate'),
url('^serviceValidate$', views.service_validate, name='serviceValidate'), url('^serviceValidate$', views.service_validate, name='serviceValidate'),
url('^proxyValidate$', views.proxy_validate, name='proxyValidate'), url('^proxyValidate$', views.proxy_validate, name='proxyValidate'),

View file

@ -12,12 +12,20 @@
from . import default_settings from . import default_settings
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
import urlparse import urlparse
import urllib import urllib
import random import random
import string import string
def redirect_params(url_name, params=None):
"""Redirect to `url_name` with `params` as querystring"""
url = reverse(url_name)
params = urllib.urlencode(params if params else {})
return HttpResponseRedirect(url + "?%s" % params)
def update_url(url, params): def update_url(url, params):
"""update params in the `url` query string""" """update params in the `url` query string"""
url_parts = list(urlparse.urlparse(url)) url_parts = list(urlparse.urlparse(url))

View file

@ -20,6 +20,7 @@ from django.views.decorators.csrf import csrf_exempt
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils import timezone from django.utils import timezone
from django.views.generic import View
import requests import requests
import urllib import urllib
@ -30,181 +31,232 @@ from . import utils
from . import forms from . import forms
from . import models from . import models
def _logout(request): class LogoutView(View):
"""Clean sessions variables""" """destroy CAS session (logout) view"""
try: request = None
del request.session["authenticated"] service = None
except KeyError: def clean_session_variables(self):
pass """Clean sessions variables"""
try: try:
del request.session["username"] del self.request.session["authenticated"]
except KeyError: except KeyError:
pass pass
try: try:
del request.session["warn"] del self.request.session["username"]
except KeyError: except KeyError:
pass pass
try:
del self.request.session["warn"]
except KeyError:
pass
def logout(self):
"""effectively destroy CAS session"""
try:
user = models.User.objects.get(username=self.request.session.get("username"))
user.logout(self.request)
user.delete()
except models.User.DoesNotExist:
pass
finally:
self.clean_session_variables()
def redirect_params(url_name, params=None): def get(self, request, *args, **kwargs):
"""Redirect to `url_name` with `params` as querystring""" """methode called on GET request on this view"""
url = reverse(url_name) self.request = request
params = urllib.urlencode(params if params else {}) self.service = request.GET.get('service')
return HttpResponseRedirect(url + "?%s" % params) self.logout()
# if service is set, redirect to service after logout
if self.service:
list(messages.get_messages(request)) # clean messages before leaving the django app
return HttpResponseRedirect(self.service)
# else redirect to login page
else:
messages.add_message(request, messages.SUCCESS, _(u'Successfully logout'))
return redirect("cas_server:login")
class LoginView(View, LogoutView):
def login(request):
"""credential requestor / acceptor""" """credential requestor / acceptor"""
# pylint: disable=too-many-instance-attributes
# Nine is reasonable in this case.
user = None user = None
form = None form = None
service_pattern = None
request = None
service = None
renew = None
gateway = None
method = None
renewed = False renewed = False
warned = False warned = False
if request.method == 'POST':
service = request.POST.get('service')
renew = True if request.POST.get('renew') else False
gateway = request.POST.get('gateway')
method = request.POST.get('method')
if not request.session.get("authenticated") or renew: def post(self, request, *args, **kwargs):
form = forms.UserCredential( """methode called on POST request on this view"""
self.request = request
self.service = request.POST.get('service')
self.renew = True if request.POST.get('renew') else False
self.gateway = request.POST.get('gateway')
self.method = request.POST.get('method')
if not request.session.get("authenticated") or self.renew:
self.form = forms.UserCredential(
request.POST, request.POST,
initial={'service':service, 'method':method, 'warn':request.session.get("warn")} initial={
'service':self.service,
'method':self.method,
'warn':request.session.get("warn")
}
) )
if form.is_valid(): if self.form.is_valid():
user = models.User.objects.get(username=form.cleaned_data['username']) self.user = models.User.objects.get(username=self.form.cleaned_data['username'])
request.session.set_expiry(0) request.session.set_expiry(0)
request.session["username"] = form.cleaned_data['username'] request.session["username"] = self.form.cleaned_data['username']
request.session["warn"] = True if form.cleaned_data.get("warn") else False request.session["warn"] = True if self.form.cleaned_data.get("warn") else False
request.session["authenticated"] = True request.session["authenticated"] = True
renewed = True self.renewed = True
warned = True self.warned = True
else: else:
_logout(request) self.logout()
else: return self.common()
service = request.GET.get('service')
renew = True if request.GET.get('renew') else False
gateway = request.GET.get('gateway')
method = request.GET.get('method')
if not request.session.get("authenticated") or renew: def get(self, request, *args, **kwargs):
form = forms.UserCredential( self.request = request
initial={'service':service, 'method':method, 'warn':request.session.get("warn")} self.service = request.GET.get('service')
self.renew = True if request.GET.get('renew') else False
self.gateway = request.GET.get('gateway')
self.method = request.GET.get('method')
if not request.session.get("authenticated") or self.renew:
self.form = forms.UserCredential(
initial={
'service':self.service,
'method':self.method,
'warn':request.session.get("warn")
}
) )
# if authenticated and successfully renewed authentication if needed return self.common()
if request.session.get("authenticated") and \
request.session.get("username") and (not renew or renewed): def service_login(self):
"""Perform login agains a service"""
try: try:
user = models.User.objects.get(username=request.session["username"]) # is the service allowed
service_pattern = models.ServicePattern.validate(self.service)
# is the current user allowed on this service
service_pattern.check_user(self.user)
# if the user has asked to be warned before any login to a service
if self.request.session.get("warn", True) and not self.warned:
messages.add_message(
self.request,
messages.WARNING,
_(u"Authentication has been required by service %(name)s (%(url)s)") % \
{'name':service_pattern.name, 'url':self.service}
)
return render(
self.request,
settings.CAS_WARN_TEMPLATE,
{'service_ticket_url':self.user.get_service_url(
self.service,
service_pattern,
renew=self.renew
)}
)
else:
# redirect, using method ?
return HttpResponseRedirect(
self.user.get_service_url(self.service, service_pattern, renew=self.renew)
)
except models.ServicePattern.DoesNotExist:
messages.add_message(
self.request,
messages.ERROR,
_(u'Service %(url)s non allowed.') % {'url' : self.service}
)
except models.BadUsername:
messages.add_message(
self.request,
messages.ERROR,
_(u"Username non allowed")
)
except models.BadFilter:
messages.add_message(
self.request,
messages.ERROR,
_(u"User charateristics non allowed")
)
except models.UserFieldNotDefined:
messages.add_message(
self.request,
messages.ERROR,
_(u"The attribut %(field)s is needed to use" \
" that service") % {'field':service_pattern.user_field}
)
# if gateway is set and auth failed redirect to the service without authentication
if self.gateway:
list(messages.get_messages(self.request)) # clean messages before leaving django
return HttpResponseRedirect(self.service)
return render(self.request, settings.CAS_LOGGED_TEMPLATE, {'session':self.request.session})
def authenticated(self):
"""Processing authenticated users"""
try:
self.user = models.User.objects.get(username=self.request.session.get("username"))
except models.User.DoesNotExist: except models.User.DoesNotExist:
_logout(request) self.logout()
return redirect_params("login", params=dict(request.GET)) return utils.redirect_params("cas_server:login", params=dict(self.request.GET))
# if login agains a service is requestest # if login agains a service is self.requestest
if service: if self.service:
return self.service_login()
else:
return render(
self.request,
settings.CAS_LOGGED_TEMPLATE,
{'session':self.request.session}
)
def not_authenticated(self):
"""Processing non authenticated users"""
if self.service:
try: try:
# is the service allowed service_pattern = models.ServicePattern.validate(self.service)
service_pattern = models.ServicePattern.validate(service) if self.gateway:
# is the current user allowed on this service list(messages.get_messages(self.request))# clean messages before leaving django
service_pattern.check_user(user) return HttpResponseRedirect(self.service)
# if the user has asked to be warned before any login to a service if self.request.session.get("authenticated") and self.renew:
if request.session.get("warn", True) and not warned:
messages.add_message( messages.add_message(
request, self.request,
messages.WARNING, messages.WARNING,
_(u"Authentication has been required by service %(name)s (%(url)s)") % \ _(u"Authentication renewal required by service %(name)s (%(url)s).") %
{'name':service_pattern.name, 'url':service} {'name':service_pattern.name, 'url':self.service}
)
return render(
request,
settings.CAS_WARN_TEMPLATE,
{'service_ticket_url':user.get_service_url(
service,
service_pattern,
renew=renew
)}
)
else:
# redirect, using method ?
return redirect(user.get_service_url(service, service_pattern, renew=renew))
except models.ServicePattern.DoesNotExist:
messages.add_message(
request,
messages.ERROR,
_(u'Service %(url)s non allowed.') % {'url' : service}
)
except models.BadUsername:
messages.add_message(
request,
messages.ERROR,
_(u"Username non allowed")
)
except models.BadFilter:
messages.add_message(
request,
messages.ERROR,
_(u"User charateristics non allowed")
)
except models.UserFieldNotDefined:
messages.add_message(
request,
messages.ERROR,
_(u"The attribut %(field)s is needed to use" \
" that service") % {'field':service_pattern.user_field}
)
# if gateway is set and auth failed redirect to the service without authentication
if gateway:
list(messages.get_messages(request)) # clean messages before leaving the django app
return redirect(service)
return render(request, settings.CAS_LOGGED_TEMPLATE, {'session':request.session})
else:
if service:
try:
service_pattern = models.ServicePattern.validate(service)
if gateway:
list(messages.get_messages(request)) # clean messages before leaving django
return redirect(service)
if request.session.get("authenticated") and renew:
messages.add_message(
request,
messages.WARNING,
_(u"Authentication renewal required by service" \
" %(name)s (%(url)s).") % {'name':service_pattern.name, 'url':service}
) )
else: else:
messages.add_message( messages.add_message(
request, self.request,
messages.WARNING, messages.WARNING,
_(u"Authentication required by service" \ _(u"Authentication required by service %(name)s (%(url)s).") %
" %(name)s (%(url)s).") % {'name':service_pattern.name, 'url':service} {'name':service_pattern.name, 'url':self.service}
) )
except models.ServicePattern.DoesNotExist: except models.ServicePattern.DoesNotExist:
messages.add_message( messages.add_message(
request, self.request,
messages.ERROR, messages.ERROR,
_(u'Service %s non allowed') % service _(u'Service %s non allowed') % self.service
) )
return render(request, settings.CAS_LOGIN_TEMPLATE, {'form':form}) return render(self.request, settings.CAS_LOGIN_TEMPLATE, {'form':self.form})
def logout(request): def common(self):
"""destroy CAS session (logout)""" """Part execute uppon GET and POST request"""
service = request.GET.get('service') # if authenticated and successfully renewed authentication if needed
if request.session.get("authenticated"): if self.request.session.get("authenticated") and (not self.renew or self.renewed):
user = models.User.objects.get(username=request.session["username"]) return self.authenticated()
user.logout(request) else:
user.delete() return self.not_authenticated()
_logout(request)
# if service is set, redirect to service after logout
if service:
list(messages.get_messages(request)) # clean messages before leaving the django app
return redirect(service)
# else redirect to login page
else:
messages.add_message(request, messages.SUCCESS, _(u'Successfully logout'))
return redirect("login")
def validate(request): def validate(request):
"""service ticket validation""" """service ticket validation"""