56d3932cf7073a1b235e37c6edab3522ab43560a
[WebKit-https.git] / Tools / QueueStatusServer / config / authorization.py
1 # Copyright (C) 2018 Apple Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
6 # 1.  Redistributions of source code must retain the above copyright
7 #     notice, this list of conditions and the following disclaimer.
8 # 2.  Redistributions in binary form must reproduce the above copyright
9 #     notice, this list of conditions and the following disclaimer in the
10 #     documentation and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
13 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
16 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
20 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
21 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23 import os
24
25 _cached_authorized_api_keys = frozenset([])
26 _AUTHORIZATION_SCHEME = "apikey"
27
28
29 def _path_to_authorized_api_keys_file():
30     return os.path.abspath(os.path.join(os.path.dirname(__file__), "authorized_api_keys.txt"))
31
32
33 def _parse_authorized_api_keys(file):
34     for line in file:
35         line = line.strip()
36         if not line or line.startswith("#"):  # Skip empty lines and comments
37             continue
38         api_keys.add(line)
39     return frozenset(api_keys)
40
41
42 def authorized_api_keys():
43     global _cached_authorized_api_keys
44     if _cached_authorized_api_keys:
45         return _cached_authorized_api_keys
46
47     with open(_path_to_authorized_api_keys_file(), "r") as file:
48         _cached_authorized_api_keys = _parse_authorized_api_keys(file)
49     return _cached_authorized_api_keys
50
51
52 def _parse_authorization_header(credentials):
53     # See <https://tools.ietf.org/html/rfc7235#section-4.2>.
54     parts = credentials.split(" ", 1)
55     if len(parts) < 2:
56         return ""
57     scheme = parts[0]
58     token68_encoded_value = parts[1]
59     if scheme.lower() == _AUTHORIZATION_SCHEME:
60         return token68_encoded_value
61     return ""
62
63
64 def is_authorized(request):
65     api_key = ''
66     credentials = request.headers.get("Authorization")
67     if credentials:
68         api_key = _parse_authorization_header(credentials)
69     if not api_key:
70         api_key = request.get(_AUTHORIZATION_SCHEME)
71     return api_key in authorized_api_keys()