diff --git a/backend/test_auth_server/__main__.py b/backend/test_auth_server/__main__.py index bf5fd576..1dc6302f 100644 --- a/backend/test_auth_server/__main__.py +++ b/backend/test_auth_server/__main__.py @@ -8,6 +8,7 @@ index_bp = Blueprint("index", __name__) index_endpoint = Api(index_bp) +# Take the key the same as the id, uid can then be used in backend token_dict = { "teacher1":{ "id":"Gunnar", @@ -44,6 +45,41 @@ "admin1":{ "id":"admin_person", "jobTitle":"admin" + }, + # Lowest authorized user to test login requirement + "login": { + "id": "login", + "jobTitle": None + }, + # Student authorization access, associated with valid_... + "student": { + "id": "student", + "jobTitle": None + }, + # Student authorization access, other + "student_other": { + "id": "student_other", + "jobTitle": None + }, + # Teacher authorization access, associated with valid_... + "teacher": { + "id": "teacher", + "jobTitle": "teacher" + }, + # Teacher authorization access, other + "teacher_other": { + "id": "teacher_other", + "jobTitle": "teacher" + }, + # Admin authorization access, associated with valid_... + "admin": { + "id": "admin", + "jobTitle": "admin" + }, + # Admin authorization access, other + "admin_other": { + "id": "admin_other", + "jobTitle": "admin" } } diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index fe9d3961..a7cc092b 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -2,7 +2,7 @@ from datetime import datetime from zoneinfo import ZoneInfo -import pytest +from pytest import fixture from project.sessionmaker import engine, Session from project.db_in import db from project.models.course import Course @@ -11,7 +11,7 @@ from project.models.course_relation import CourseStudent,CourseAdmin from project.models.submission import Submission, SubmissionStatus -@pytest.fixture +@fixture def db_session(): """Create a new database session for a test. After the test, all changes are rolled back and the session is closed.""" @@ -123,7 +123,22 @@ def submissions(session): ) ] -@pytest.fixture +### AUTHENTICATION & AUTHORIZATION ### +def auth_tokens(): + """Add the authenticated users to the database""" + + return [ + User(uid="login", role=Role.STUDENT), + User(uid="student", role=Role.STUDENT), + User(uid="student_other", role=Role.STUDENT), + User(uid="teacher", role=Role.TEACHER), + User(uid="teacher_other", role=Role.TEACHER), + User(uid="admin", role=Role.ADMIN), + User(uid="admin_other", role=Role.ADMIN) + ] + +### SESSION ### +@fixture def session(): """Create a new database session for a test. After the test, all changes are rolled back and the session is closed.""" @@ -132,6 +147,8 @@ def session(): session = Session() try: + session.add_all(auth_tokens()) + # Populate the database session.add_all(users()) session.commit() diff --git a/backend/tests/endpoints/conftest.py b/backend/tests/endpoints/conftest.py index b76e8369..fd46dd8a 100644 --- a/backend/tests/endpoints/conftest.py +++ b/backend/tests/endpoints/conftest.py @@ -5,6 +5,8 @@ from datetime import datetime from zoneinfo import ZoneInfo import pytest +from pytest import fixture, FixtureRequest +from flask.testing import FlaskClient from sqlalchemy import create_engine from sqlalchemy.exc import SQLAlchemyError from project.models.user import User,Role @@ -15,7 +17,23 @@ from project.models.submission import Submission, SubmissionStatus from project.models.project import Project +### AUTHENTICATION & AUTHORIZATION ### +@fixture +def auth_test(request: FixtureRequest, client: FlaskClient, valid_course_entry): + """Add concrete test data""" + # endpoint, parameters, method, token, status + endpoint, parameters, method, *other = request.param + d = { + "course_id": valid_course_entry.course_id + } + + for index, parameter in enumerate(parameters): + endpoint = endpoint.replace(f"@{index}", str(d[parameter])) + + return endpoint, getattr(client, method), *other + +### OTHER ### @pytest.fixture def valid_submission(valid_user_entry, valid_project_entry): """ diff --git a/backend/tests/endpoints/endpoint.py b/backend/tests/endpoints/endpoint.py new file mode 100644 index 00000000..1c468164 --- /dev/null +++ b/backend/tests/endpoints/endpoint.py @@ -0,0 +1,56 @@ +"""Base class for endpoint tests""" + +from typing import List, Tuple +from pytest import param + +def authentication_tests(tests: List[Tuple[str, List[str], List[str]]]) -> List[any]: + """Transform the format to single authentication tests""" + + single_tests = [] + for test in tests: + endpoint, parameters, methods = test + for method in methods: + single_tests.append(param( + (endpoint, parameters, method), + id = f"{endpoint} {method}" + )) + return single_tests + +def authorization_tests(tests: List[Tuple[str, List[str], str, List[str], List[str]]]) -> List[any]: + """Transform the format to single authorization tests""" + + single_tests = [] + for test in tests: + endpoint, parameters, method, allowed_tokens, disallowed_tokens = test + for token in (allowed_tokens + disallowed_tokens): + allowed = token in allowed_tokens + single_tests.append(param( + (endpoint, parameters, method, token, allowed), + id = f"{endpoint} {method} {token} {'allowed' if allowed else 'disallowed'}" + )) + return single_tests + +class TestEndpoint: + """Base class for endpoint tests""" + + def authentication(self, authentication_parameter: Tuple[str, any]): + """Test if the authentication for the given enpoint works""" + + endpoint, method = authentication_parameter + + response = method(endpoint) + assert response.status_code == 401 + + response = method(endpoint, headers = {"Authorization": "0123456789"}) + assert response.status_code == 401 + + response = method(endpoint, headers = {"Authorization": "login"}) + assert response.status_code != 401 + + def authorization(self, auth_parameter: Tuple[str, any, str, bool]): + """Test if the authorization for the given endpoint works""" + + endpoint, method, token, allowed = auth_parameter + + response = method(endpoint, headers = {"Authorization": token}) + assert allowed == (response.status_code != 403) diff --git a/backend/tests/models/user_test.py b/backend/tests/models/user_test.py index 05520b8c..d607ebad 100644 --- a/backend/tests/models/user_test.py +++ b/backend/tests/models/user_test.py @@ -14,11 +14,11 @@ def test_create_user(self, session: Session): session.add(user) session.commit() assert session.get(User, "user01") is not None - assert session.query(User).count() == 5 + assert session.query(User).count() == 12 def test_query_user(self, session: Session): """Test if a user can be queried""" - assert session.query(User).count() == 4 + assert session.query(User).count() == 11 teacher = session.query(User).filter_by(uid="brinkmann").first() assert teacher is not None assert teacher.role == Role.ADMIN @@ -36,7 +36,7 @@ def test_delete_user(self, session: Session): session.delete(user) session.commit() assert session.get(User, user.uid) is None - assert session.query(User).count() == 3 + assert session.query(User).count() == 10 @mark.parametrize("property_name", ["uid"]) def test_property_not_nullable(self, session: Session, property_name: str):