Skip to content

Commit b73bbdd

Browse files
pakelleyjombooth
andcommitted
fix: DIA-2122: allow all LSO users to modify JWT settings (#7323)
Co-authored-by: Jo Booth <[email protected]>
1 parent c8bea38 commit b73bbdd

File tree

3 files changed

+73
-14
lines changed

3 files changed

+73
-14
lines changed

label_studio/core/utils/common.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,3 +750,19 @@ def empty(*args, **kwargs):
750750
def get_ttl_hash(seconds: int = 60) -> int:
751751
"""Return the same value within `seconds` time period"""
752752
return round(time.time() / seconds)
753+
754+
755+
def is_community():
756+
"""Determine if the current Label Studio instance is the community edition (aka LSO).
757+
758+
Returns
759+
-------
760+
bool
761+
True if running open-source Label Studio, False otherwise.
762+
"""
763+
try:
764+
import label_studio_enterprise # noqa: F401
765+
766+
return False
767+
except ImportError:
768+
return True

label_studio/jwt_auth/models.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import Any
33

44
from annoying.fields import AutoOneToOneField
5+
from core.utils.common import is_community
56
from django.db import models
67
from django.utils.translation import gettext_lazy as _
78
from organizations.models import Organization
@@ -39,9 +40,19 @@ def has_view_permission(self, user):
3940
return self.organization.has_permission(user)
4041

4142
def has_modify_permission(self, user):
42-
"""Only organization owners/admins can modify JWT settings."""
43+
"""Determine who can modify JWT settings.
44+
45+
In label studio enterprise: Only organization owners/admins can modify JWT settings.
46+
In label studio open-source: Any organization member can modify JWT settings.
47+
"""
4348
if not self.organization.has_permission(user):
4449
return False
50+
51+
# open-source
52+
if is_community():
53+
return True
54+
55+
# enterprise
4556
is_owner = user.is_owner if hasattr(user, 'is_owner') else (user.id == self.organization.created_by.id)
4657
is_administrator = hasattr(user, 'is_administrator') and user.is_administrator
4758
return is_owner or is_administrator

label_studio/tests/jwt_auth/test_models.py

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import pytest
22
from jwt_auth.models import LSAPIToken, LSTokenBackend
33
from organizations.models import OrganizationMember
4+
from organizations.tests.factories import OrganizationFactory
45
from rest_framework_simplejwt.exceptions import TokenError
56
from rest_framework_simplejwt.settings import api_settings as simple_jwt_settings
67
from rest_framework_simplejwt.token_blacklist.models import BlacklistedToken, OutstandingToken
8+
from users.models import User
79

810
from ..utils import mock_feature_flag
911
from .utils import create_user_with_token_settings
@@ -12,26 +14,56 @@
1214
@mock_feature_flag(flag_name='fflag__feature_develop__prompts__dia_1829_jwt_token_auth', value=True)
1315
@pytest.mark.django_db
1416
def test_jwt_settings_permissions():
15-
user = create_user_with_token_settings(api_tokens_enabled=True, legacy_api_tokens_enabled=False)
16-
org = user.active_organization
17-
OrganizationMember.objects.create(
18-
user=user,
19-
organization=org,
20-
)
17+
org = OrganizationFactory()
18+
user = org.created_by
2119

2220
# Any member should be able to view
2321
assert org.jwt.has_view_permission(user)
2422

25-
# Only owners and administrators can modify
26-
user.is_owner = True
27-
user.save()
23+
# Any LSO member should be able to modify
24+
# (tests for enterprise handled in enterprise test suite)
2825
assert org.jwt.has_modify_permission(user)
2926
assert org.jwt.has_permission(user)
3027

31-
user.is_owner = False
32-
user.save()
33-
assert not org.jwt.has_modify_permission(user)
34-
assert not org.jwt.has_permission(user)
28+
29+
@mock_feature_flag(flag_name='fflag__feature_develop__prompts__dia_1829_jwt_token_auth', value=True)
30+
@pytest.mark.django_db
31+
def test_non_owner_user_can_modify_jwt_settings():
32+
"""Test that a regular non-owner user who is added to an organization can modify JWT settings"""
33+
org = OrganizationFactory()
34+
non_owner = User.objects.create(email='[email protected]')
35+
36+
OrganizationMember.objects.create(
37+
user=non_owner,
38+
organization=org,
39+
)
40+
non_owner.active_organization = org
41+
non_owner.save()
42+
43+
assert org.jwt.has_view_permission(non_owner)
44+
assert org.jwt.has_modify_permission(non_owner)
45+
assert org.jwt.has_permission(non_owner)
46+
47+
48+
@mock_feature_flag(flag_name='fflag__feature_develop__prompts__dia_1829_jwt_token_auth', value=True)
49+
@pytest.mark.django_db
50+
def test_user_from_other_org_cannot_access_jwt_settings():
51+
"""Test that users from other organizations cannot view or modify JWT settings"""
52+
org1 = OrganizationFactory()
53+
org1_owner = org1.created_by
54+
55+
org2 = OrganizationFactory()
56+
org2_owner = org2.created_by
57+
58+
# Verify org1 owner cannot view or modify JWT settings of org2
59+
assert not org2.jwt.has_view_permission(org1_owner)
60+
assert not org2.jwt.has_modify_permission(org1_owner)
61+
assert not org2.jwt.has_permission(org1_owner)
62+
63+
# Verify org2 owner cannot view or modify JWT settings of org1
64+
assert not org1.jwt.has_view_permission(org2_owner)
65+
assert not org1.jwt.has_modify_permission(org2_owner)
66+
assert not org1.jwt.has_permission(org2_owner)
3567

3668

3769
@mock_feature_flag(flag_name='fflag__feature_develop__prompts__dia_1829_jwt_token_auth', value=True)

0 commit comments

Comments
 (0)