Implement basic tests for auth mechanism

This commit is contained in:
Alexandre Aubin 2019-08-23 02:37:57 +02:00
parent 82ba7e5b04
commit 2addea1e08
7 changed files with 184 additions and 1 deletions

View file

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
import logging
from moulinette.core import MoulinetteError
from moulinette.authenticators import BaseAuthenticator
logger = logging.getLogger('moulinette.authenticator.dummy')
# Dummy authenticator implementation
class Authenticator(BaseAuthenticator):
"""Dummy authenticator used for tests
"""
vendor = 'dummy'
def __init__(self, name, vendor, parameters, extra):
logger.debug("initialize authenticator '%s")
super(Authenticator, self).__init__(name)
def authenticate(self, password):
if not password == "Yoloswag":
raise MoulinetteError("Invalid password!")
return self

View file

@ -0,0 +1,42 @@
#############################
# Global parameters #
#############################
_global:
configuration:
authenticate:
- all
authenticator:
default:
vendor: dummy
help: Dummy Password
yoloswag:
vendor: dummy
help: Dummy Yoloswag Password
#############################
# Test Actions #
#############################
testauth:
actions:
none:
api: GET /test-auth/none
configuration:
authenticate: false
default:
api: GET /test-auth/default
configuration:
authenticate: all
authenticator: default
# only-api:
# api: GET /test-auth/only-api
# configuration:
# authenticate: api
#
other-profile:
api: GET /test-auth/other-profile
configuration:
authenticator: yoloswag

View file

@ -92,7 +92,6 @@ def patch_logging(moulinette):
} }
@pytest.fixture(scope='session', autouse=True) @pytest.fixture(scope='session', autouse=True)
def moulinette(tmp_path_factory): def moulinette(tmp_path_factory):
import moulinette import moulinette
@ -100,8 +99,10 @@ def moulinette(tmp_path_factory):
# Can't call the namespace just 'test' because # Can't call the namespace just 'test' because
# that would lead to some "import test" not importing the right stuff # that would lead to some "import test" not importing the right stuff
namespace = "moulitest" namespace = "moulitest"
tmp_cache = str(tmp_path_factory.mktemp("cache"))
tmp_data = str(tmp_path_factory.mktemp("data")) tmp_data = str(tmp_path_factory.mktemp("data"))
tmp_lib = str(tmp_path_factory.mktemp("lib")) tmp_lib = str(tmp_path_factory.mktemp("lib"))
os.environ['MOULINETTE_CACHE_DIR'] = tmp_cache
os.environ['MOULINETTE_DATA_DIR'] = tmp_data os.environ['MOULINETTE_DATA_DIR'] = tmp_data
os.environ['MOULINETTE_LIB_DIR'] = tmp_lib os.environ['MOULINETTE_LIB_DIR'] = tmp_lib
shutil.copytree("./test/actionsmap", "%s/actionsmap" % tmp_data) shutil.copytree("./test/actionsmap", "%s/actionsmap" % tmp_data)

3
test/locales/en.json Normal file
View file

@ -0,0 +1,3 @@
{
"foo": "bar"
}

0
test/src/__init__.py Normal file
View file

10
test/src/testauth.py Normal file
View file

@ -0,0 +1,10 @@
def testauth_none():
return "some_data_from_none"
def testauth_default():
return "some_data_from_default"
def testauth_other_profile():
return "some_data_from_other_profile"

99
test/test_auth.py Normal file
View file

@ -0,0 +1,99 @@
import os
import requests
def login(webapi, cookies=None, csrf=False, profile=None):
data = {"password": "Yoloswag"}
if profile:
data["profile"] = profile
return requests.post(webapi + "/login",
cookies=cookies,
data=data,
headers=None if csrf else {"X-Requested-With": ""})
def test_request_no_auth_needed(monkeypatch, tmp_path, moulinette_webapi):
r = requests.get(moulinette_webapi + "/test-auth/none")
assert r.status_code == 200
assert r.text == '"some_data_from_none"'
def test_request_with_auth_but_not_logged(monkeypatch, tmp_path, moulinette_webapi):
r = requests.get(moulinette_webapi + "/test-auth/default")
assert r.status_code == 401
assert r.text == "Authentication required"
def test_login(monkeypatch, moulinette_webapi):
r = login(moulinette_webapi)
assert r.status_code == 200
assert r.text == "Logged in"
assert "session.id" in r.cookies
assert "session.tokens" in r.cookies
cache_session_default = os.environ['MOULINETTE_CACHE_DIR'] + "/session/default/"
assert r.cookies["session.id"] + ".asc" in os.listdir(cache_session_default)
def test_login_csrf_attempt(moulinette_webapi):
# C.f.
# https://security.stackexchange.com/a/58308
# https://stackoverflow.com/a/22533680
r = login(moulinette_webapi, csrf=True)
assert r.status_code == 403
assert "session.id" not in r.cookies
assert "session.tokens" not in r.cookies
assert "CSRF protection" in r.text
def test_login_then_legit_request_without_cookies(moulinette_webapi):
login(moulinette_webapi)
r = requests.get(moulinette_webapi + "/test-auth/default")
assert r.status_code == 401
assert r.text == "Authentication required"
def test_login_then_legit_request(moulinette_webapi):
r_login = login(moulinette_webapi)
r = requests.get(moulinette_webapi + "/test-auth/default",
cookies={"session.id": r_login.cookies["session.id"],
"session.tokens": r_login.cookies["session.tokens"], })
assert r.status_code == 200
assert r.text == '"some_data_from_default"'
def test_login_then_logout(moulinette_webapi):
r_login = login(moulinette_webapi)
r = requests.get(moulinette_webapi + "/logout",
cookies={"session.id": r_login.cookies["session.id"],
"session.tokens": r_login.cookies["session.tokens"], })
assert r.status_code == 200
cache_session_default = os.environ['MOULINETTE_CACHE_DIR'] + "/session/default/"
assert not r_login.cookies["session.id"] + ".asc" in os.listdir(cache_session_default)
r = requests.get(moulinette_webapi + "/test-auth/default",
cookies={"session.id": r_login.cookies["session.id"],
"session.tokens": r_login.cookies["session.tokens"], })
assert r.status_code == 401
assert r.text == "Authentication required"