-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(scopes): Enforce scope hierarchy (#54510)
### Note - User Token UI Changes should be merged beforehand #54651 - See[ Notion doc](https://www.notion.so/sentry/WIP-Permission-Scope-Hierarchy-67620f99783345bbb8bc2828b1addc64) for detailed spec on this work ### Implementation To model the hierarchy I used a simple dict of scope -> all granted scopes. I chose this approach b/c it's very simple and easy to enforce in the code. We use a pre-save signal on the `ApiKey` and `ApiToken` models to enforce scope hierarchy. The basic scope hierarchy for each resource is: - read grants nothing - write grants read - admin grants read+write When updating one of these models, there is no way to know if the scopes are enforced without fetching it from the DB. To avoid this trip, we always iterate through the hierarchy mapping.
- Loading branch information
Showing
10 changed files
with
115 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from django.db.models.signals import pre_save | ||
from django.dispatch import receiver | ||
|
||
from sentry.conf.server import SENTRY_SCOPE_HIERARCHY_MAPPING, SENTRY_SCOPES | ||
from sentry.models import ApiKey, ApiToken | ||
|
||
|
||
@receiver(pre_save, sender=ApiKey, dispatch_uid="enforce_scope_hierarchy_api_key") | ||
@receiver(pre_save, sender=ApiToken, dispatch_uid="enforce_scope_hierarchy_api_token") | ||
def enforce_scope_hierarchy(instance, **kwargs) -> None: | ||
# It's impossible to know if the token scopes have been modified without | ||
# fetching it from the DB, so we always enforce scope hierarchy | ||
new_scopes = set(instance.get_scopes()) | ||
for scope in instance.scope_list: | ||
if scope in SENTRY_SCOPES: | ||
new_scopes = new_scopes.union(SENTRY_SCOPE_HIERARCHY_MAPPING[scope]) | ||
instance.scope_list = sorted(new_scopes) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from sentry.conf.server import SENTRY_SCOPE_HIERARCHY_MAPPING, SENTRY_SCOPES | ||
from sentry.testutils.cases import TestCase | ||
|
||
|
||
class ScopesTest(TestCase): | ||
def test_scope_hierarchy_maintained(self): | ||
for scope in SENTRY_SCOPES: | ||
assert scope in SENTRY_SCOPE_HIERARCHY_MAPPING | ||
|
||
# exclude special OAuth scopes | ||
if ":" not in scope: | ||
continue | ||
resource, access_level = scope.split(":") | ||
|
||
# check that scope is in its own mapping | ||
assert scope in SENTRY_SCOPE_HIERARCHY_MAPPING[scope] | ||
|
||
# check that write grants read | ||
if access_level == "write": | ||
assert resource + ":read" in SENTRY_SCOPE_HIERARCHY_MAPPING[scope] | ||
|
||
# # check that admin grants read+write | ||
if access_level == "admin": | ||
assert resource + ":read" in SENTRY_SCOPE_HIERARCHY_MAPPING[scope] | ||
assert resource + ":write" in SENTRY_SCOPE_HIERARCHY_MAPPING[scope] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from sentry.conf.server import SENTRY_SCOPE_HIERARCHY_MAPPING, SENTRY_SCOPES | ||
from sentry.testutils.cases import TestCase | ||
from sentry.testutils.silo import control_silo_test | ||
|
||
|
||
@control_silo_test(stable=True) | ||
class ApiTokenTest(TestCase): | ||
def test_enforces_scope_hierarchy(self): | ||
org = self.create_organization() | ||
# Ensure hierarchy is enforced for all tokens | ||
for scope in SENTRY_SCOPES: | ||
token = self.create_api_key(org, scope_list=[scope]) | ||
assert token.get_scopes() == sorted(SENTRY_SCOPE_HIERARCHY_MAPPING[scope]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters