aboutsummaryrefslogtreecommitdiffstats
path: root/tests/middleware/test_authenticate.py
blob: 9fccb323614eafeca7e69625bf8d0ca87582c5c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
from base64 import b64encode
from wsgiref.validate import validator

import pytest

import paste
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 MockStore:
    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.Store", MockStore)
    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.Store", MockStore)
    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