147 lines
5.9 KiB
Python
147 lines
5.9 KiB
Python
import logging
|
|
|
|
from django.utils.translation import ugettext as _
|
|
from django.shortcuts import render
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
from django.views.generic.base import TemplateView
|
|
from django.template.loader import render_to_string
|
|
from django.contrib import messages
|
|
from django.contrib.auth.forms import AuthenticationForm
|
|
from django.contrib.auth import authenticate, login
|
|
|
|
|
|
from authentic2.utils import continue_to_next_url, record_authentication_event, redirect, redirect_to_login
|
|
|
|
from . import models, util, app_settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def handle_request(request):
|
|
# Check certificate validity
|
|
ssl_info = util.SSLInfo(request)
|
|
accept_self_signed = app_settings.ACCEPT_SELF_SIGNED
|
|
|
|
if not ssl_info.cert:
|
|
logger.error('SSL Client Authentication failed: '
|
|
'SSL CGI variable CERT is missing')
|
|
messages.add_message(request, messages.ERROR,
|
|
_('SSL Client Authentication failed. '
|
|
'No client certificate found.'))
|
|
return redirect_to_login(request)
|
|
elif not accept_self_signed and not ssl_info.verify:
|
|
logger.error('SSL Client Authentication failed: '
|
|
'SSL CGI variable VERIFY is not SUCCESS')
|
|
messages.add_message(request, messages.ERROR,
|
|
_('SSL Client Authentication failed. '
|
|
'Your client certificate is not valid.'))
|
|
return redirect_to_login(request)
|
|
|
|
# SSL entries for this certificate?
|
|
user = authenticate(ssl_info=ssl_info)
|
|
|
|
# If the user is logged in, no need to create an account
|
|
# If there is an SSL entries, no need for account creation,
|
|
# just need to login, treated after
|
|
if 'do_creation' in request.session and not user \
|
|
and not request.user.is_authenticated():
|
|
from backends import SSLBackend
|
|
if SSLBackend().create_user(ssl_info):
|
|
user = authenticate(ssl_info=ssl_info)
|
|
logger.info(u'account created for %s', user)
|
|
else:
|
|
logger.error('account creation failure')
|
|
messages.add_message(request, messages.ERROR,
|
|
_('SSL Client Authentication failed. Internal server error.'))
|
|
return redirect_to_login(request)
|
|
|
|
# No SSL entries and no user session, redirect account linking page
|
|
if not user and not request.user.is_authenticated():
|
|
return render(request, 'auth/account_linking_ssl.html')
|
|
|
|
# No SSL entries but active user session, perform account linking
|
|
if not user and request.user.is_authenticated():
|
|
from backend import SSLBackend
|
|
if SSLBackend().link_user(ssl_info, request.user):
|
|
logger.info('Successful linking of the SSL '
|
|
'Certificate to an account, redirection to %s' % next_url)
|
|
else:
|
|
logger.error('login() failed')
|
|
messages.add_message(request, messages.ERROR,
|
|
_('SSL Client Authentication failed. Internal server error.'))
|
|
return redirect_to_login(request)
|
|
|
|
# SSL Entries found for this certificate,
|
|
# if the user is logged out, we login
|
|
if not request.user.is_authenticated():
|
|
login(request, user)
|
|
record_authentication_event(request, how='ssl')
|
|
return continue_to_next_url(request)
|
|
|
|
# SSL Entries found for this certificate, if the user is logged in, we
|
|
# check that the SSL entry for the certificate is this user.
|
|
# else, we make this certificate point on that user.
|
|
if user.username != request.user.username:
|
|
logger.warning(u'The certificate belongs to %s, '
|
|
'but %s is logged with, we change the association!',
|
|
user, request.user)
|
|
from backends import SSLBackend
|
|
cert = SSLBackend().get_certificate(ssl_info)
|
|
cert.user = request.user
|
|
cert.save()
|
|
return continue_to_next_url(request)
|
|
|
|
###
|
|
# post_account_linking
|
|
# @request
|
|
#
|
|
# Called after an account linking.
|
|
###
|
|
@csrf_exempt
|
|
def post_account_linking(request):
|
|
logger.info('auth2_ssl Return after account linking form filled')
|
|
if request.method == "POST":
|
|
if 'do_creation' in request.POST \
|
|
and request.POST['do_creation'] == 'on':
|
|
logger.info('account creation asked')
|
|
request.session['do_creation'] = 'do_creation'
|
|
return redirect_to_login(request, login_url='user_signin_ssl')
|
|
form = AuthenticationForm(data=request.POST)
|
|
if form.is_valid():
|
|
logger.info('form valid')
|
|
user = form.get_user()
|
|
try:
|
|
login(request, user)
|
|
record_authentication_event(request, how='password')
|
|
except:
|
|
logger.error('login() failed')
|
|
messages.add_message(request, messages.ERROR,
|
|
_('SSL Client Authentication failed. Internal server error.'))
|
|
|
|
logger.debug('session opened')
|
|
return redirect_to_login(request, login_url='user_signin_ssl')
|
|
else:
|
|
logger.warning('form not valid - Try again! (Brute force?)')
|
|
return render(request, 'auth/account_linking_ssl.html')
|
|
else:
|
|
return render(request, 'auth/account_linking_ssl.html')
|
|
|
|
def profile(request, template_name='ssl/profile.html', *args, **kwargs):
|
|
context = kwargs.pop('context', {})
|
|
certificates = models.ClientCertificate.objects.filter(user=request.user)
|
|
context.update({'certificates': certificates})
|
|
return render_to_string(template_name, context, request=request)
|
|
|
|
def delete_certificate(request, certificate_pk):
|
|
qs = models.ClientCertificate.objects.filter(pk=certificate_pk)
|
|
count = qs.count()
|
|
qs.delete()
|
|
if count:
|
|
logger.info('client certificate %s deleted', certificate_pk)
|
|
messages.info(request, _('Certificate deleted.'))
|
|
return redirect(request, 'account_management',
|
|
fragment='a2-ssl-certificate-profile')
|
|
|
|
class SslErrorView(TemplateView):
|
|
template_name = 'error_ssl.html'
|
|
error_ssl = SslErrorView.as_view()
|