authentic/tests/test_login.py

207 lines
8.1 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/>.
import pytest
from django.utils.six.moves.urllib.parse import quote
from django.contrib.auth import get_user_model
from authentic2 import models
from utils import login
def test_login_inactive_user(db, app):
User = get_user_model()
user1 = User.objects.create(username='john.doe')
user1.set_password('john.doe')
user1.save()
user2 = User.objects.create(username='john.doe')
user2.set_password('john.doe')
user2.save()
login(app, user1)
assert int(app.session['_auth_user_id']) in [user1.id, user2.id]
app.get('/logout/').form.submit()
assert '_auth_user_id' not in app.session
user1.is_active = False
user1.save()
login(app, user1)
assert int(app.session['_auth_user_id']) == user2.id
app.get('/logout/').form.submit()
assert '_auth_user_id' not in app.session
user2.is_active = False
user2.save()
with pytest.raises(AssertionError):
login(app, user1)
assert '_auth_user_id' not in app.session
def test_registration_url_on_login_page(db, app):
response = app.get('/login/?next=/whatever')
assert 'register/?next=/whatever"' in response
def test_redirect_login_to_homepage(db, app, settings, simple_user, superuser):
settings.A2_LOGIN_REDIRECT_AUTHENTICATED_USERS_TO_HOMEPAGE = True
login(app, simple_user)
response = app.get('/login/')
assert response.status_code == 302
def test_exponential_backoff(db, app, settings):
response = app.get('/login/')
response.form.set('username', '')
response.form.set('password', 'zozo')
response = response.form.submit('login-password-submit')
assert response.status_code == 200
for i in range(10):
response.form.set('username', 'zozo')
response.form.set('password', 'zozo')
response = response.form.submit('login-password-submit')
assert 'too many login' not in response.text
settings.A2_LOGIN_EXPONENTIAL_RETRY_TIMEOUT_DURATION = 1.0
settings.A2_LOGIN_EXPONENTIAL_RETRY_TIMEOUT_MIN_DURATION = 10.0
for i in range(10):
response.form.set('username', 'zozo')
response.form.set('password', 'zozo')
response = response.form.submit('login-password-submit')
if 1.8 ** i > 10:
break
assert 'too many login' not in response.text, '%s' % i
assert 'too many login' in response.text, '%s' % i
def test_encoded_utf8_in_next_url(app, db):
url = '/manage/roles/?search-ou=all&search-text=r%C3%A9dacteur&search-internals=on'
response = app.get(url)
response = response.follow()
needle = 'next=%s' % quote(url)
assert needle in response.text
def test_session_expire(app, simple_user, freezer):
freezer.move_to('2018-01-01')
# Verify session work as usual
login(app, simple_user)
response = app.get('/')
assert simple_user.first_name in response
freezer.move_to('2018-01-15')
response = app.get('/')
assert simple_user.first_name not in response
def test_session_remember_me_ok(app, settings, simple_user, freezer):
settings.A2_USER_REMEMBER_ME = 3600 * 24 * 30
freezer.move_to('2018-01-01')
# Verify session are longer
login(app, simple_user, remember_me=True)
response = app.get('/')
assert simple_user.first_name in response
# less than 30 days, session is still alive
freezer.move_to('2018-01-30')
response = app.get('/')
assert simple_user.first_name in response
def test_session_remember_me_nok(app, settings, simple_user, freezer):
settings.A2_USER_REMEMBER_ME = 3600 * 24 * 30
freezer.move_to('2018-01-01')
# Verify session are longer
login(app, simple_user, remember_me=True)
response = app.get('/')
assert simple_user.first_name in response
# more than 30 days, session is dead
freezer.move_to('2018-01-31')
response = app.get('/')
assert simple_user.first_name not in response
def test_ou_selector(app, settings, simple_user, ou1, ou2, user_ou1, role_ou1):
settings.A2_LOGIN_FORM_OU_SELECTOR = True
response = app.get('/login/')
# Check selector is here and there are no errors
assert not response.pyquery('.errorlist')
assert response.pyquery.find('select#id_ou')
assert len(response.pyquery.find('select#id_ou optgroup')) == 0
assert (set([elt.text for elt in response.pyquery.find('select#id_ou option')])
== set([u'Default organizational unit', u'OU1', u'OU2', u'---------']))
# Check selector is required
response.form.set('username', simple_user.username)
response.form.set('password', simple_user.username)
response = response.form.submit(name='login-password-submit')
assert response.pyquery('.errorlist')
# Check login to the wrong ou do not work
response.form.set('password', simple_user.username)
response.form.set('ou', str(ou1.pk))
response = response.form.submit(name='login-password-submit')
assert not response.pyquery('.errorlist:not(.nonfield)')
assert response.pyquery('.errorlist.nonfield')
assert '_auth_user_id' not in app.session
# Check login to the proper ou works
response.form.set('password', simple_user.username)
response.form.set('ou', str(simple_user.ou.pk))
response = response.form.submit(name='login-password-submit').follow()
assert '_auth_user_id' in app.session
response = response.click('Logout').maybe_follow()
assert '_auth_user_id' not in app.session
assert app.cookies['preferred-ous'] == str(simple_user.ou.pk)
# Check last ou is preselected and shown first
response = app.get('/login/')
assert response.pyquery.find('select#id_ou')
assert len(response.pyquery.find('select#id_ou optgroup')) == 2
assert (set([elt.text for elt in response.pyquery.find('select#id_ou option')])
== set([u'Default organizational unit', u'OU1', u'OU2', u'---------']))
assert response.pyquery.find('select#id_ou option[selected]')[0].text == u'Default organizational unit'
# Create a service
service = models.Service.objects.create(name='Service', slug='service', ou=ou1)
response = app.get('/login/')
assert response.pyquery.find('select#id_ou option[selected]')[0].text == u'Default organizational unit'
# service is specified but not access-control is defined, default for user is selected
response = app.get('/login/?service=service')
assert response.pyquery.find('select#id_ou option[selected]')[0].text == u'Default organizational unit'
# service is specified, access control is defined but role is empty, default for user is selected
service.authorized_roles.through.objects.create(service=service, role=role_ou1)
response = app.get('/login/?service=service')
assert response.pyquery.find('select#id_ou option[selected]')[0].text == u'Default organizational unit'
# user is added to role_ou1, default for user is still selected
user_ou1.roles.add(role_ou1)
response = app.get('/login/?service=service')
assert response.pyquery.find('select#id_ou option[selected]')[0].text == u'Default organizational unit'
# Clear cookies, OU1 is selected
app.cookiejar.clear()
response = app.get('/login/?service=service')
assert response.pyquery.find('select#id_ou option[selected]')[0].text == u'OU1'
# if we change the user's ou, then default selected OU changes
user_ou1.ou = ou2
user_ou1.save()
response = app.get('/login/?service=service')
assert response.pyquery.find('select#id_ou option[selected]')[0].text == u'OU2'