from base64 import b64encode from wsgiref.validate import validator import pytest from paste import authenticate from ..common_wsgi import call_app @pytest.fixture def app(): @validator @authenticate @validator def app(_, start_response): start_response("200 OK", [("Content-Type", "text/plain")]) return [b"Hello, world!"] return app @pytest.mark.parametrize("method", ["GET", "HEAD"]) def test_unauthenticated_request(app, method): environ = {"REQUEST_METHOD": method} response = call_app(app, environ) assert response.data == b"Hello, world!" assert response.status == "200 OK" assert ("Content-Type", "text/plain") in response.headers @pytest.mark.parametrize("method", ["GET", "HEAD"]) def test_unauthenticated_request_with_key(app, method): environ = { "REQUEST_METHOD": method, "paste.db_conn": None, "HTTP_AUTHORIZATION": "ApiKey AAAA", } response = call_app(app, environ) assert response.data == b"Hello, world!" assert response.status == "200 OK" assert ("Content-Type", "text/plain") in response.headers @pytest.mark.parametrize("method", ["POST", "PUT", "DELETE"]) def test_authenticate_no_header(app, method): environ = {"REQUEST_METHOD": method} response = call_app(app, environ) assert response.data == b"401 Unauthorized\n" assert response.status == "401 Unauthorized" assert ("Content-Type", "text/plain") in response.headers assert ("WWW-Authenticate", "APIKey") in response.headers @pytest.mark.parametrize("method", ["POST", "PUT", "DELETE"]) @pytest.mark.parametrize("key", ["ApiKey AAAA", "APIKey AAA", "APIKey AAAA", "AAAA"]) def test_authenticate_malformed_key(app, method, key): environ = {"REQUEST_METHOD": method, "HTTP_AUTHORIZATION": key} response = call_app(app, environ) assert response.data == b"401 Unauthorized\n" assert response.status == "401 Unauthorized" assert ("Content-Type", "text/plain") in response.headers assert ("WWW-Authenticate", "APIKey") in response.headers class MockConnection: def __init__(self, check_token): self.check_token = check_token class MockAuth: def __init__(self, c): assert isinstance(c, MockConnection) self.conn = c def check_token(self, tok): return self.conn.check_token(tok) @pytest.mark.parametrize("method", ["POST", "PUT", "DELETE"]) def test_authenticate_check_token_fail(app, method, monkeypatch): check_token_called = False token = b"test" def check_token(tok): nonlocal check_token_called assert tok == token check_token_called = True return False environ = { "REQUEST_METHOD": method, "paste.db_conn": MockConnection(check_token), "HTTP_AUTHORIZATION": f"APIKey {b64encode(token).decode()}", } monkeypatch.setattr("paste.Auth", MockAuth) response = call_app(app, environ) assert check_token_called assert response.data == b"401 Unauthorized\n" assert response.status == "401 Unauthorized" assert ("Content-Type", "text/plain") in response.headers assert ("WWW-Authenticate", "APIKey") in response.headers @pytest.mark.parametrize("method", ["POST", "PUT", "DELETE"]) def test_authenticate_check_token_success(app, method, monkeypatch): check_token_called = False token = b"test" def check_token(tok): nonlocal check_token_called assert tok == token check_token_called = True return True environ = { "REQUEST_METHOD": method, "paste.db_conn": MockConnection(check_token), "HTTP_AUTHORIZATION": f"APIKey {b64encode(token).decode()}", } monkeypatch.setattr("paste.Auth", MockAuth) response = call_app(app, environ) assert check_token_called assert response.data == b"Hello, world!" assert response.status == "200 OK" assert ("Content-Type", "text/plain") in response.headers