Skip to content

Commit ee112fc

Browse files
authored
feat(auth-v2): Use HTTP Header to protect endpoints on production (#94588)
Depends on #94390.
1 parent 5e29259 commit ee112fc

File tree

4 files changed

+73
-4
lines changed

4 files changed

+73
-4
lines changed

src/sentry/auth_v2/endpoints/base.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from django.conf import settings
2+
from rest_framework.permissions import BasePermission
3+
from rest_framework.request import Request
4+
5+
from sentry.api.base import Endpoint
6+
7+
8+
class AuthV2Permission(BasePermission):
9+
def has_permission(self, request: Request, view: object) -> bool:
10+
if settings.IS_DEV:
11+
return True
12+
13+
# WARN: If the secret is not set on production, we must fail the request.
14+
if not settings.AUTH_V2_SECRET:
15+
return False
16+
17+
return request.META.get("HTTP_X_SENTRY_AUTH_V2") == settings.AUTH_V2_SECRET
18+
19+
20+
class AuthV2Endpoint(Endpoint):
21+
permission_classes = (AuthV2Permission,)
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
from rest_framework.permissions import AllowAny
21
from rest_framework.request import Request
32
from rest_framework.response import Response
43

54
from sentry.api.api_owners import ApiOwner
65
from sentry.api.api_publish_status import ApiPublishStatus
7-
from sentry.api.base import Endpoint, control_silo_endpoint
6+
from sentry.api.base import control_silo_endpoint
7+
8+
from .base import AuthV2Endpoint
89

910

1011
@control_silo_endpoint
11-
class UserLoginView(Endpoint):
12+
class UserLoginView(AuthV2Endpoint):
1213
owner = ApiOwner.ENTERPRISE
1314
publish_status = {
1415
"GET": ApiPublishStatus.PRIVATE,
1516
}
16-
permission_classes = (AllowAny,)
1717

1818
def get(self, request: Request) -> Response:
1919
return Response({"message": "Hello world"})

src/sentry/conf/server.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,9 @@ def env(
649649

650650
INITIAL_CUSTOM_USER_MIGRATION = "0108_fix_user"
651651

652+
# Protect login/registration endpoints during development phase
653+
AUTH_V2_SECRET = ""
654+
652655
# Auth engines and the settings required for them to be listed
653656
AUTH_PROVIDERS = {
654657
"github": ("GITHUB_APP_ID", "GITHUB_API_SECRET"),
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from django.test import override_settings
2+
from rest_framework.views import APIView
3+
4+
from sentry.auth_v2.endpoints.base import AuthV2Permission
5+
from sentry.testutils.cases import DRFPermissionTestCase
6+
from sentry.testutils.requests import drf_request_from_request
7+
8+
9+
class AuthV2PermissionsTest(DRFPermissionTestCase):
10+
"""
11+
See tests/sentry/api/test_permissions.py
12+
"""
13+
14+
def setUp(self):
15+
super().setUp()
16+
self.auth_v2_permission = AuthV2Permission()
17+
self.user = self.create_user(is_superuser=False, is_staff=False)
18+
19+
def _make_request(self):
20+
request = self.make_request(user=self.user)
21+
drf_request = drf_request_from_request(request)
22+
return drf_request
23+
24+
def test_is_dev_enabled(self):
25+
with override_settings(IS_DEV=True):
26+
request = self._make_request()
27+
assert self.auth_v2_permission.has_permission(request, APIView())
28+
29+
def test_is_dev_disabled(self):
30+
with override_settings(IS_DEV=False):
31+
request = self._make_request()
32+
request.META["HTTP_X_SENTRY_AUTH_V2"] = "" # Fail if the secret is not set
33+
assert not self.auth_v2_permission.has_permission(request, APIView())
34+
35+
def test_secret_matches(self):
36+
with override_settings(AUTH_V2_SECRET="secret"):
37+
request = self._make_request()
38+
request.META["HTTP_X_SENTRY_AUTH_V2"] = "secret"
39+
assert self.auth_v2_permission.has_permission(request, APIView())
40+
41+
def test_secret_does_not_match(self):
42+
with override_settings(AUTH_V2_SECRET="secret"):
43+
request = self._make_request()
44+
request.META["HTTP_X_SENTRY_AUTH_V2"] = "wrong-secret"
45+
assert not self.auth_v2_permission.has_permission(request, APIView())

0 commit comments

Comments
 (0)