Skip to content

Commit ebb92c7

Browse files
committed
chore: allow machine auth to generate CSRF token
1 parent d20b60e commit ebb92c7

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

superset/tasks/cache.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,19 @@ def cache_warmup(
291291
return message
292292

293293
user = security_manager.get_user_by_username(app.config["THUMBNAIL_SELENIUM_USER"])
294-
cookies = MachineAuthProvider.get_auth_cookies(user)
295-
headers = {
296-
"Cookie": f"session={cookies.get('session', '')}",
297-
"Content-Type": "application/json",
298-
}
294+
if app.config["WTF_CSRF_ENABLED"]:
295+
cookies, csrf_token = MachineAuthProvider.get_auth_cookie_and_csrf_token(user)
296+
headers = {
297+
"Cookie": f"session={cookies.get('session', '')}",
298+
"Content-Type": "application/json",
299+
"X-CSRFToken": csrf_token,
300+
}
301+
else:
302+
cookies = MachineAuthProvider.get_auth_cookies(user)
303+
headers = {
304+
"Cookie": f"session={cookies.get('session', '')}",
305+
"Content-Type": "application/json",
306+
}
299307

300308
results: dict[str, list[str]] = {"scheduled": [], "errors": []}
301309
for payload in strategy.get_payloads():

superset/utils/machine_auth.py

+26
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from flask import current_app, Flask, request, Response, session
2525
from flask_login import login_user
26+
from flask_wtf.csrf import generate_csrf
2627
from selenium.webdriver.remote.webdriver import WebDriver
2728
from werkzeug.http import parse_cookie
2829

@@ -143,6 +144,31 @@ def get_auth_cookies(user: User) -> dict[str, str]:
143144

144145
return cookies
145146

147+
@staticmethod
148+
def get_auth_cookie_and_csrf_token(user: User) -> tuple[dict[str, str], str]:
149+
# Login with the user specified to get the reports
150+
with current_app.test_request_context("/login"):
151+
login_user(user)
152+
csrf_token = generate_csrf()
153+
# A mock response object to get the cookie information from
154+
response = Response()
155+
current_app.session_interface.save_session(current_app, session, response)
156+
157+
cookies = {}
158+
159+
# Grab any "set-cookie" headers from the login response
160+
for name, value in response.headers:
161+
if name.lower() == "set-cookie":
162+
# This yields a MultiDict, which is ordered -- something like
163+
# MultiDict([('session', 'value-we-want), ('HttpOnly', ''), etc...
164+
# Therefore, we just need to grab the first tuple and add it to our
165+
# final dict
166+
cookie = parse_cookie(value)
167+
cookie_tuple = list(cookie.items())[0]
168+
cookies[cookie_tuple[0]] = cookie_tuple[1]
169+
170+
return cookie, csrf_token
171+
146172

147173
class MachineAuthProviderFactory:
148174
def __init__(self) -> None:

tests/integration_tests/utils/machine_auth_tests.py

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ def test_get_auth_cookies(self):
2727
auth_cookies = machine_auth_provider_factory.instance.get_auth_cookies(user)
2828
self.assertIsNotNone(auth_cookies["session"])
2929

30+
def test_get_auth_cookie_and_csrf_token(self):
31+
user = self.get_user("admin")
32+
(
33+
auth_cookies,
34+
csrf_token,
35+
) = machine_auth_provider_factory.instance.get_auth_cookie_and_csrf_token(user)
36+
self.assertIsNotNone(auth_cookies["session"])
37+
self.assertIsNotNone(csrf_token)
38+
3039
@patch("superset.utils.machine_auth.MachineAuthProvider.get_auth_cookies")
3140
def test_auth_driver_user(self, get_auth_cookies):
3241
user = self.get_user("admin")

0 commit comments

Comments
 (0)