feat(embedded): aud claim and type for guest token (#18651)

* add aud claim and type for guest token

* update test

* lint

* make jwt audience configurable

* lint

* Apply suggestions from code review

Co-authored-by: David Aaron Suddjian <1858430+suddjian@users.noreply.github.com>

* verify aud

* add tests for aud and type claim

Co-authored-by: David Aaron Suddjian <1858430+suddjian@users.noreply.github.com>
This commit is contained in:
Lily Kuang
2022-02-14 10:43:35 -08:00
committed by GitHub
parent 4001165f55
commit e6ea197e9f
4 changed files with 72 additions and 3 deletions

View File

@@ -22,6 +22,7 @@ import jwt
from tests.integration_tests.base_tests import SupersetTestCase
from flask_wtf.csrf import generate_csrf
from superset.utils.urls import get_url_host
class TestSecurityCsrfApi(SupersetTestCase):
@@ -90,6 +91,8 @@ class TestSecurityGuestTokenApi(SupersetTestCase):
self.assert200(response)
token = json.loads(response.data)["token"]
decoded_token = jwt.decode(token, self.app.config["GUEST_TOKEN_JWT_SECRET"])
decoded_token = jwt.decode(
token, self.app.config["GUEST_TOKEN_JWT_SECRET"], audience=get_url_host()
)
self.assertEqual(user, decoded_token["user"])
self.assertEqual(resource, decoded_token["resources"][0])

View File

@@ -44,6 +44,7 @@ from superset.utils.core import (
get_example_default_schema,
)
from superset.utils.database import get_example_database
from superset.utils.urls import get_url_host
from superset.views.access_requests import AccessRequestsModelView
from .base_tests import SupersetTestCase
@@ -1177,17 +1178,20 @@ class TestGuestTokens(SupersetTestCase):
resources = [{"some": "resource"}]
rls = [{"dataset": 1, "clause": "access = 1"}]
token = security_manager.create_guest_access_token(user, resources, rls)
aud = get_url_host()
# unfortunately we cannot mock time in the jwt lib
decoded_token = jwt.decode(
token,
self.app.config["GUEST_TOKEN_JWT_SECRET"],
algorithms=[self.app.config["GUEST_TOKEN_JWT_ALGO"]],
audience=aud,
)
self.assertEqual(user, decoded_token["user"])
self.assertEqual(resources, decoded_token["resources"])
self.assertEqual(now, decoded_token["iat"])
self.assertEqual(aud, decoded_token["aud"])
self.assertEqual("guest", decoded_token["type"])
self.assertEqual(
now + (self.app.config["GUEST_TOKEN_JWT_EXP_SECONDS"] * 1000),
decoded_token["exp"],
@@ -1241,3 +1245,57 @@ class TestGuestTokens(SupersetTestCase):
self.assertRaisesRegex(
ValueError, "Guest token does not contain a resources claim"
)
def test_get_guest_user_not_guest_type(self):
now = time.time()
user = {"username": "test_guest"}
resources = [{"some": "resource"}]
aud = get_url_host()
claims = {
"user": user,
"resources": resources,
"rls_rules": [],
# standard jwt claims:
"aud": aud,
"iat": now, # issued at
"type": "not_guest",
}
token = jwt.encode(
claims,
self.app.config["GUEST_TOKEN_JWT_SECRET"],
algorithm=self.app.config["GUEST_TOKEN_JWT_ALGO"],
)
fake_request = FakeRequest()
fake_request.headers[current_app.config["GUEST_TOKEN_HEADER_NAME"]] = token
guest_user = security_manager.get_guest_user_from_request(fake_request)
self.assertIsNone(guest_user)
self.assertRaisesRegex(ValueError, "This is not a guest token.")
def test_get_guest_user_bad_audience(self):
now = time.time()
user = {"username": "test_guest"}
resources = [{"some": "resource"}]
aud = get_url_host()
claims = {
"user": user,
"resources": resources,
"rls_rules": [],
# standard jwt claims:
"aud": "bad_audience",
"iat": now, # issued at
"type": "guest",
}
token = jwt.encode(
claims,
self.app.config["GUEST_TOKEN_JWT_SECRET"],
algorithm=self.app.config["GUEST_TOKEN_JWT_ALGO"],
)
fake_request = FakeRequest()
fake_request.headers[current_app.config["GUEST_TOKEN_HEADER_NAME"]] = token
guest_user = security_manager.get_guest_user_from_request(fake_request)
self.assertRaisesRegex(jwt.exceptions.InvalidAudienceError, "Invalid audience")
self.assertIsNone(guest_user)