96 lines
3.3 KiB
Python
96 lines
3.3 KiB
Python
# authentic2 - versatile identity manager
|
|
# Copyright (C) 2010-2019 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from django.conf import settings
|
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
|
from django.forms import Form
|
|
from django.utils.decorators import method_decorator
|
|
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
|
|
|
|
from . import hooks, utils
|
|
from .utils.views import csrf_token_check
|
|
|
|
|
|
class ValidateCSRFMixin(object):
|
|
"""Move CSRF token validation inside the form validation.
|
|
|
|
This mixin must always be the leftest one and if your class override
|
|
form_valid() dispatch() you should move those overrides in a base
|
|
class.
|
|
"""
|
|
|
|
@method_decorator(csrf_exempt)
|
|
@method_decorator(ensure_csrf_cookie)
|
|
def dispatch(self, *args, **kwargs):
|
|
return super(ValidateCSRFMixin, self).dispatch(*args, **kwargs)
|
|
|
|
def form_valid(self, *args, **kwargs):
|
|
for form in args:
|
|
if isinstance(form, Form):
|
|
csrf_token_check(self.request, form)
|
|
if not form.is_valid():
|
|
return self.form_invalid(form)
|
|
return super(ValidateCSRFMixin, self).form_valid(*args, **kwargs)
|
|
|
|
|
|
class RedirectToNextURLViewMixin(object):
|
|
def get_success_url(self):
|
|
if REDIRECT_FIELD_NAME in self.request.GET:
|
|
return self.request.GET[REDIRECT_FIELD_NAME]
|
|
return settings.LOGIN_REDIRECT_URL
|
|
|
|
|
|
class NextURLViewMixin(RedirectToNextURLViewMixin):
|
|
"""Make a view handle a next parameter, if it's not present it is
|
|
automatically generated from the Referrer or from the value
|
|
returned by the method get_next_url_default().
|
|
"""
|
|
|
|
next_url_default = '..'
|
|
|
|
def get_next_url_default(self):
|
|
return self.next_url_default
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
if REDIRECT_FIELD_NAME in request.GET:
|
|
pass
|
|
else:
|
|
next_url = request.META.get('HTTP_REFERER') or self.next_url_default
|
|
return utils.redirect(
|
|
request,
|
|
request.path,
|
|
keep_params=True,
|
|
params={
|
|
REDIRECT_FIELD_NAME: next_url,
|
|
},
|
|
status=303,
|
|
)
|
|
return super(NextURLViewMixin, self).dispatch(request, *args, **kwargs)
|
|
|
|
|
|
class TemplateNamesMixin(object):
|
|
def get_template_names(self):
|
|
if hasattr(self, 'template_names'):
|
|
return self.template_names
|
|
return super(TemplateNamesMixin, self).get_template_names()
|
|
|
|
|
|
class HookMixin(object):
|
|
def get_form(self):
|
|
form = super(HookMixin, self).get_form()
|
|
hooks.call_hooks('front_modify_form', self, form)
|
|
return form
|