Implement session-based and OAuth 2 authentications

Relates #21. Please see acceptance docs for feature details.

Signed-off-by: Aaron Tan <jangsutsr@gmail.com>
This commit is contained in:
Aaron Tan
2017-11-02 17:18:27 -04:00
committed by adamscmRH
parent 2ebee58727
commit 1c2621cd60
37 changed files with 1712 additions and 144 deletions

View File

@@ -0,0 +1,100 @@
import pytest
from datetime import timedelta
import re
from django.utils.timezone import now as tz_now
from django.test.utils import override_settings
from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.sessions.models import Session
from django.contrib.auth import SESSION_KEY
from awx.main.models import UserSessionMembership
from awx.api.versioning import reverse
class AlwaysPassBackend(object):
user = None
def authenticate(self, **credentials):
return AlwaysPassBackend.user
@classmethod
def get_backend_path(cls):
return '{}.{}'.format(cls.__module__, cls.__name__)
@pytest.mark.django_db
def test_session_create_delete(admin, post, get):
AlwaysPassBackend.user = admin
with override_settings(
AUTHENTICATION_BACKENDS=(AlwaysPassBackend.get_backend_path(),),
SESSION_COOKIE_NAME='session_id'
):
response = post(
'/api/login/',
data={'username': admin.username, 'password': admin.password, 'next': '/api/'},
expect=302, middleware=SessionMiddleware(), format='multipart'
)
assert 'session_id' in response.cookies
session_key = re.findall(r'session_id=[a-zA-z0-9]+',
str(response.cookies['session_id']))[0][len('session_id=') :]
session = Session.objects.get(session_key=session_key)
assert int(session.get_decoded()[SESSION_KEY]) == admin.pk
response = get(
'/api/logout/', middleware=SessionMiddleware(),
cookies={'session_id': session_key}, expect=302
)
assert not Session.objects.filter(session_key=session_key).exists()
@pytest.mark.django_db
def test_session_overlimit(admin, post):
AlwaysPassBackend.user = admin
with override_settings(
AUTHENTICATION_BACKENDS=(AlwaysPassBackend.get_backend_path(),),
SESSION_COOKIE_NAME='session_id', SESSIONS_PER_USER=3
):
sessions_to_deprecate = []
for _ in range(5):
response = post(
'/api/login/',
data={'username': admin.username, 'password': admin.password, 'next': '/api/'},
expect=302, middleware=SessionMiddleware(), format='multipart'
)
session_key = re.findall(
r'session_id=[a-zA-z0-9]+',
str(response.cookies['session_id'])
)[0][len('session_id=') :]
sessions_to_deprecate.append(Session.objects.get(session_key=session_key))
sessions_to_deprecate[0].expire_date = tz_now() - timedelta(seconds=1000)
sessions_to_deprecate[0].save()
sessions_overlimit = [x.session for x in UserSessionMembership.get_memberships_over_limit(admin)]
assert sessions_to_deprecate[0] not in sessions_overlimit
assert sessions_to_deprecate[1] in sessions_overlimit
for session in sessions_to_deprecate[2 :]:
assert session not in sessions_overlimit
@pytest.mark.django_db
def test_password_update_clears_sessions(admin, alice, post, patch):
AlwaysPassBackend.user = alice
with override_settings(
AUTHENTICATION_BACKENDS=(AlwaysPassBackend.get_backend_path(),),
SESSION_COOKIE_NAME='session_id'
):
response = post(
'/api/login/',
data={'username': alice.username, 'password': alice.password, 'next': '/api/'},
expect=302, middleware=SessionMiddleware(), format='multipart'
)
session_key = re.findall(
r'session_id=[a-zA-z0-9]+',
str(response.cookies['session_id'])
)[0][len('session_id=') :]
assert Session.objects.filter(session_key=session_key).exists()
patch(
reverse('api:user_detail', kwargs={'pk': alice.pk}), admin,
data={'password': 'new_password'}, expect=200
)
assert not Session.objects.filter(session_key=session_key).exists()