add request as first argument to all backends (#33992)

This commit is contained in:
Benjamin Dauvergne 2019-06-13 12:34:18 +02:00
parent 8bb83c01e7
commit 27702e72c7
15 changed files with 45 additions and 30 deletions

View File

@ -17,6 +17,7 @@
import logging
import smtplib
import django
from django.db import models
from django.contrib.auth import get_user_model
from django.core.exceptions import MultipleObjectsReturned
@ -34,7 +35,7 @@ from rest_framework.viewsets import ModelViewSet
from rest_framework.routers import SimpleRouter
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import permissions, status
from rest_framework import permissions, status, authentication
from rest_framework.exceptions import PermissionDenied, AuthenticationFailed
from rest_framework.fields import CreateOnlyDefault
from rest_framework.decorators import list_route, detail_route
@ -52,6 +53,11 @@ from .models import Attribute, PasswordReset, Service
from .a2_rbac.utils import get_default_ou
# Retro-compatibility with Django 1.8
if django.VERSION < (1, 11):
authentication.authenticate = utils.authenticate
class HookMixin(object):
def get_serializer(self, *args, **kwargs):
serializer = super(HookMixin, self).get_serializer(*args, **kwargs)

View File

@ -1392,7 +1392,7 @@ class LDAPBackend(object):
class LDAPBackendPasswordLost(LDAPBackend):
def authenticate(self, user=None):
def authenticate(self, request, user=None):
if not user:
return
config = self.get_config()

View File

@ -68,10 +68,8 @@ class ModelBackend(ModelBackend):
from .. import models
return bool(models.PasswordReset.filter(user=user).count())
def authenticate(self, username=None, password=None, realm=None, ou=None, **kwargs):
def authenticate(self, request, username=None, password=None, realm=None, ou=None):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
if not username:
return
query = self.get_query(username=username, realm=realm, ou=ou)
@ -99,6 +97,6 @@ class ModelBackend(ModelBackend):
class DummyModelBackend(ModelBackend):
def authenticate(self, user=None):
def authenticate(self, request, user=None):
if user is not None:
return user

View File

@ -21,8 +21,6 @@ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import forms as auth_forms
from django.utils import html
from django.contrib.auth import authenticate
from authentic2.forms.fields import PasswordField
from ..a2_rbac.models import OrganizationalUnit as OU
@ -98,7 +96,7 @@ class AuthenticationForm(auth_forms.AuthenticationForm):
ou = self.cleaned_data.get('ou')
if username is not None and password:
self.user_cache = authenticate(username=username, password=password, ou=ou, request=self.request)
self.user_cache = utils.authenticate(self.request, username=username, password=password, ou=ou)
if self.user_cache is None:
raise forms.ValidationError(
self.error_messages['invalid_login'],

View File

@ -33,7 +33,7 @@ from django.http import HttpResponseRedirect, HttpResponse
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.http.request import QueryDict
from django.contrib.auth import (REDIRECT_FIELD_NAME, login as auth_login, SESSION_KEY,
HASH_SESSION_KEY, BACKEND_SESSION_KEY, authenticate,
HASH_SESSION_KEY, BACKEND_SESSION_KEY, authenticate as dj_authenticate,
get_user_model)
from django import forms
from django.forms.utils import ErrorList, to_current_timezone
@ -835,7 +835,7 @@ def switch_user(request, new_user):
for key in (SESSION_KEY, BACKEND_SESSION_KEY, HASH_SESSION_KEY,
constants.LAST_LOGIN_SESSION_KEY):
switched[key] = request.session[key]
user = authenticate(user=new_user)
user = authenticate(request, user=new_user)
login(request, user, 'switch')
request.session[constants.SWITCH_USER_SESSION_KEY] = switched
if constants.LAST_LOGIN_SESSION_KEY not in request.session:
@ -1152,3 +1152,8 @@ def gettid():
libc = ctypes.cdll.LoadLibrary('libc.so.6')
SYS_gettid = 186
return libc.syscall(SYS_gettid)
def authenticate(request=None, **kwargs):
# Compatibility layer with Django 1.8
return dj_authenticate(request=request, **kwargs)

View File

@ -43,7 +43,7 @@ from django.views.decorators.debug import sensitive_post_parameters
from django.contrib.auth.decorators import login_required
from django.db.models.fields import FieldDoesNotExist
from django.db.models.query import Q
from django.contrib.auth import get_user_model, authenticate
from django.contrib.auth import get_user_model
from django.http import Http404
from django.utils.http import urlsafe_base64_decode
from django.views.generic.edit import CreateView
@ -690,7 +690,7 @@ class PasswordResetConfirmView(cbv.RedirectToNextURLViewMixin, FormView):
try:
uid = urlsafe_base64_decode(uidb64)
# use authenticate to eventually get an LDAPUser
self.user = authenticate(user=UserModel._default_manager.get(pk=uid))
self.user = utils.authenticate(request, user=UserModel._default_manager.get(pk=uid))
except (TypeError, ValueError, OverflowError,
UserModel.DoesNotExist):
validlink = False

View File

@ -26,7 +26,7 @@ from requests_oauthlib import OAuth2Session
import django
from django.views.generic import View, FormView
from django.http import HttpResponseRedirect, Http404
from django.contrib.auth import authenticate, REDIRECT_FIELD_NAME, get_user_model
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
from django.contrib import messages
from django.shortcuts import resolve_url, render
from django.utils.translation import ugettext as _
@ -402,8 +402,11 @@ class LoginOrLinkView(PopupViewMixin, FcOAuthSessionViewMixin, View):
default_ou = get_default_ou()
email_is_unique = a2_app_settings.A2_EMAIL_IS_UNIQUE or default_ou.email_is_unique
user = authenticate(sub=self.sub, user_info=self.user_info,
token=self.token)
user = a2_utils.authenticate(
request,
sub=self.sub,
user_info=self.user_info,
token=self.token)
if not user and self.user_info.get('email') and email_is_unique:
email = self.user_info['email']
User = get_user_model()
@ -428,8 +431,11 @@ class LoginOrLinkView(PopupViewMixin, FcOAuthSessionViewMixin, View):
self.logger.info(u'fc link created sub %s user %s', self.sub, user)
hooks.call_hooks('event', name='fc-link', user=user, sub=self.sub,
request=request)
user = authenticate(sub=self.sub, user_info=self.user_info,
token=self.token)
user = a2_utils.authenticate(
request=request,
sub=self.sub,
user_info=self.user_info,
token=self.token)
else:
messages.warning(
request,

View File

@ -36,7 +36,7 @@ from . import models, utils
class OIDCBackend(ModelBackend):
def authenticate(self, access_token=None, id_token=None, nonce=None, **kwargs):
def authenticate(self, request, access_token=None, id_token=None, nonce=None):
logger = logging.getLogger(__name__)
if id_token is None:
return

View File

@ -23,13 +23,13 @@ import requests
from django.core.urlresolvers import reverse
from django.utils.translation import get_language, ugettext as _
from django.contrib import messages
from django.contrib.auth import REDIRECT_FIELD_NAME, authenticate
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.conf import settings
from django.views.generic.base import View
from django.http import HttpResponseBadRequest
from authentic2.decorators import setting_enabled
from authentic2.utils import redirect, login, good_next_url
from authentic2.utils import redirect, login, good_next_url, authenticate
from . import app_settings, models
from .utils import get_provider, get_provider_by_issuer
@ -198,7 +198,7 @@ class LoginCallback(View):
return self.continue_to_next_url()
logger.info(u'got token response %s', result)
access_token = result.get('access_token')
user = authenticate(access_token=access_token, nonce=nonce, id_token=result['id_token'])
user = authenticate(request, access_token=access_token, nonce=nonce, id_token=result['id_token'])
if user:
# remember last tokens for logout
tokens = request.session.setdefault('auth_oidc', {}).setdefault('tokens', [])

View File

@ -22,7 +22,7 @@ from . import app_settings
class SAMLBackend(SAMLBackend):
def authenticate(self, saml_attributes, request=None):
def authenticate(self, request, saml_attributes):
if not app_settings.enable:
return None
return super(SAMLBackend, self).authenticate(saml_attributes=saml_attributes, request=request)

View File

@ -253,7 +253,8 @@ class UserProfileTests(TestCase):
user_editable=True,
user_visible=True,
kind='string')
self.assertTrue(self.client.login(username='testbot',
self.assertTrue(self.client.login(request=None,
username='testbot',
password='secret'))
# get the edit page in order to check form's prefix
@ -298,7 +299,8 @@ class UserProfileTests(TestCase):
user_visible=False,
kind='string')
self.assertTrue(self.client.login(username='testbot',
self.assertTrue(self.client.login(request=None,
username='testbot',
password='secret'))
response = self.client.get(reverse('profile_edit'))
form = get_response_form(response)

View File

@ -75,7 +75,7 @@ def test_api_user(client):
assert response.content == b'{}'
# login
client.login(username='john.doe', password='password')
client.login(request=None, username='john.doe', password='password')
response = client.get('/api/user/', HTTP_ORIGIN='http://testserver')
data = json.loads(response.content)
assert isinstance(data, dict)

View File

@ -14,7 +14,7 @@
# 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.contrib.auth import authenticate
from authentic2.utils import authenticate
from authentic2.backends import is_user_authenticable

View File

@ -24,7 +24,7 @@ import ldap
from ldap.dn import escape_dn_chars
from ldaptools.slapd import Slapd, has_slapd
from django.contrib.auth import get_user_model, authenticate
from django.contrib.auth import get_user_model
from django.core.exceptions import ImproperlyConfigured
from django.core import management
from django.core import mail
@ -35,6 +35,7 @@ from django.utils.six.moves.urllib import parse as urlparse
from authentic2.a2_rbac.utils import get_default_ou
from django_rbac.utils import get_ou_model
from authentic2.backends import ldap_backend
from authentic2.utils import authenticate
from authentic2 import crypto, models
import utils

View File

@ -15,13 +15,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# authentic2
from django.contrib.auth import authenticate
from django.contrib.auth.middleware import AuthenticationMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
from authentic2.utils import (good_next_url, same_origin, select_next_url,
user_can_change_password, login,
get_authentication_events)
get_authentication_events, authenticate)
def test_good_next_url(db, rf, settings):