Merge ~andersson123/autopkgtest-cloud:browse-cgi-api-key into autopkgtest-cloud:master

Proposed by Tim Andersson
Status: Merged
Merged at revision: ca68c2b7ca64f46ed01dc441468c748c22138e23
Proposed branch: ~andersson123/autopkgtest-cloud:browse-cgi-api-key
Merge into: autopkgtest-cloud:master
Diff against target: 146 lines (+65/-0)
5 files modified
charms/focal/autopkgtest-web/config.yaml (+5/-0)
charms/focal/autopkgtest-web/reactive/autopkgtest_web.py (+19/-0)
charms/focal/autopkgtest-web/webcontrol/request/app.py (+28/-0)
docs/administration.rst (+12/-0)
mojo/service-bundle (+1/-0)
Reviewer Review Type Date Requested Status
Skia Approve
Review via email: mp+462256@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Tim Andersson (andersson123) wrote :

(Needs testing)

Revision history for this message
Tim Andersson (andersson123) wrote :

(Needs work first actually)

Revision history for this message
Tim Andersson (andersson123) wrote :

Testing this in staging rn

Revision history for this message
Skia (hyask) wrote :

Awesome to see that! Couple of inline comments, but nothing too big.

review: Needs Fixing
Revision history for this message
Tim Andersson (andersson123) :
Revision history for this message
Tim Andersson (andersson123) wrote :

todo: add documentation on this

Revision history for this message
Tim Andersson (andersson123) wrote :

more todo:
- run api key check in constant time to avoid brute force
- decide on cookie name

Revision history for this message
Tim Andersson (andersson123) wrote :

rename the api key to X-Api-Key
use sha1 and hmac.compare_digest to compare the sha1's of the keys

Revision history for this message
Skia (hyask) wrote :

Taking a good shape! :-)

review: Needs Fixing
Revision history for this message
Tim Andersson (andersson123) wrote :

amended again, please re-review

Revision history for this message
Skia (hyask) wrote :

Last one!

review: Needs Fixing
Revision history for this message
Tim Andersson (andersson123) wrote :

Ah, good catch, ty, amended, please re-review

Revision history for this message
Skia (hyask) wrote :

Awesome!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/charms/focal/autopkgtest-web/config.yaml b/charms/focal/autopkgtest-web/config.yaml
2index 50606ac..8fcc1e5 100644
3--- a/charms/focal/autopkgtest-web/config.yaml
4+++ b/charms/focal/autopkgtest-web/config.yaml
5@@ -16,6 +16,11 @@ options:
6 default:
7 description: "projectname → shared secret \
8 JSON mapping for github test requests"
9+ external-web-requests-api-keys:
10+ type: string
11+ default:
12+ description: "user/project → api key \
13+ JSON mapping for non-github automated test requests"
14 github-status-credentials:
15 type: string
16 default:
17diff --git a/charms/focal/autopkgtest-web/reactive/autopkgtest_web.py b/charms/focal/autopkgtest-web/reactive/autopkgtest_web.py
18index c6e0533..e8b94c9 100644
19--- a/charms/focal/autopkgtest-web/reactive/autopkgtest_web.py
20+++ b/charms/focal/autopkgtest-web/reactive/autopkgtest_web.py
21@@ -1,4 +1,5 @@
22 import glob
23+import json
24 import os
25 import pathlib
26 import shutil
27@@ -25,6 +26,7 @@ GITHUB_STATUS_CREDENTIALS_PATH = os.path.expanduser(
28 SWIFT_WEB_CREDENTIALS_PATH = os.path.expanduser(
29 "~ubuntu/swift-web-credentials.conf"
30 )
31+API_KEYS_PATH = "/home/ubuntu/external-web-requests-api-keys.json"
32
33 PUBLIC_SWIFT_CREDS_PATH = os.path.expanduser("~ubuntu/public-swift-creds")
34
35@@ -262,6 +264,23 @@ def write_github_secrets():
36 status.maintenance("Done writing github secrets")
37
38
39+@when_all(
40+ "config.changed.external-web-requests-api-keys",
41+ "config.set.external-web-requests-api-keys",
42+)
43+def write_api_keys():
44+ status.maintenance("Writing api keys")
45+ api_keys = config().get("external-web-requests-api-keys.json")
46+ try:
47+ _ = json.loads(api_keys)
48+ except json.JSONDecodeError as e:
49+ status.maintenance("api keys have invalid json format: %s" % api_keys)
50+ raise e
51+ with open(API_KEYS_PATH, "w") as f:
52+ f.write(api_keys)
53+ status.maintenance("api keys written")
54+
55+
56 @when_not("config.set.github-secrets")
57 def clear_github_secrets():
58 status.maintenance("Clearing github secrets")
59diff --git a/charms/focal/autopkgtest-web/webcontrol/request/app.py b/charms/focal/autopkgtest-web/webcontrol/request/app.py
60index 23750e6..c58cf7f 100644
61--- a/charms/focal/autopkgtest-web/webcontrol/request/app.py
62+++ b/charms/focal/autopkgtest-web/webcontrol/request/app.py
63@@ -3,6 +3,7 @@ import hmac
64 import json
65 import logging
66 import os
67+import pathlib
68 from collections import ChainMap
69 from html import escape as _escape
70
71@@ -54,6 +55,21 @@ SUCCESS = """
72 </dl>
73 """
74
75+# API keys is a json file like this:
76+# {
77+# "user1": "user1s-apikey",
78+# "user2": "user2s-apikey",
79+# }
80+try:
81+ API_KEYS = json.loads(
82+ pathlib.Path(
83+ "/home/ubuntu/external-web-requests-api-keys.json"
84+ ).read_text()
85+ )
86+except Exception as e:
87+ logging.warning("Failed to read API keys: %s", e)
88+ API_KEYS = {}
89+
90
91 def check_github_sig(request):
92 """Validate github signature of request.
93@@ -134,6 +150,18 @@ def index_root():
94 session.permanent = True
95 session["next"] = maybe_escape(request.url)
96 nick = maybe_escape(session.get("nickname"))
97+ if "X-Api-Key" in request.cookies:
98+ key_user, api_key = request.cookies.get("X-Api-Key").split(":")
99+ request_creds_sha1 = hmac.new(
100+ key_user.encode(), api_key.encode(), "sha1"
101+ ).hexdigest()
102+ for user, user_key in API_KEYS.items():
103+ iter_creds_sha1 = hmac.new(
104+ user.encode(), user_key.encode(), "sha1"
105+ ).hexdigest()
106+ if hmac.compare_digest(request_creds_sha1, iter_creds_sha1):
107+ nick = key_user
108+ session.update(nickname=key_user)
109
110 params = {
111 maybe_escape(k): maybe_escape(v) for k, v in request.args.items()
112diff --git a/docs/administration.rst b/docs/administration.rst
113index e29cf58..adb27b9 100644
114--- a/docs/administration.rst
115+++ b/docs/administration.rst
116@@ -205,6 +205,18 @@ Once those steps are done then the rows can be deleted from the database.
117 * ``sqlite3 -header -column autopkgtest.db "DELETE FROM test WHERE test.release='impish';"``
118 * ``sqlite3 -header -column autopkgtest.db "vacuum;"``
119
120+API Key Integration
121+-------------------
122+
123+Requests can be requested by using an API key instead of authenticating using SSO.
124+To do so, attach a cookie to whatever script is making the test request, with the name
125+"X-Api-Key". The value should look like this:
126+
127+.. code-block::
128+ user:api-key
129+
130+Where the user and api-key fields are provided by the Ubuntu Release Management team.
131+
132
133 Integration with GitHub and GitLab pull/merge requests
134 ------------------------------------------------------
135diff --git a/mojo/service-bundle b/mojo/service-bundle
136index e6b6a1f..7946db1 100644
137--- a/mojo/service-bundle
138+++ b/mojo/service-bundle
139@@ -199,6 +199,7 @@ applications:
140 github-status-credentials: include-file://{{local_dir}}/github-status-credentials.txt
141 swift-web-credentials: include-file://{{local_dir}}/swift-web-credentials.conf
142 public-swift-creds: include-file://{{local_dir}}/public-swift-creds
143+ external-web-requests-api-keys: include-file://{local_dir}}/external-web-requests-api-keys.json
144 https-proxy: {{ https_proxy }}
145 no-proxy: {{ no_proxy }}
146 cookies: S0 S1

Subscribers

People subscribed via source and target branches