diff --git a/engine/apps/mobile_app/tests/test_mobile_app_gateway.py b/engine/apps/mobile_app/tests/test_mobile_app_gateway.py index 09d11a08..c16be45a 100644 --- a/engine/apps/mobile_app/tests/test_mobile_app_gateway.py +++ b/engine/apps/mobile_app/tests/test_mobile_app_gateway.py @@ -300,7 +300,7 @@ def test_mobile_app_gateway_proxies_headers( ): mock_requests.post.return_value = MockResponse() - _, user, auth_token = make_organization_and_user_with_mobile_app_auth_token() + _, _, auth_token = make_organization_and_user_with_mobile_app_auth_token() client = APIClient() url = reverse("mobile_app:gateway", kwargs={"downstream_backend": DOWNSTREAM_BACKEND, "downstream_path": "test"}) @@ -315,7 +315,6 @@ def test_mobile_app_gateway_proxies_headers( params={}, headers={ "Authorization": f"Bearer {MOCK_AUTH_TOKEN}", - "X-Grafana-User": f"email:{user.email}", "Content-Type": content_type_header, }, ) @@ -328,30 +327,11 @@ def test_mobile_app_gateway_properly_generates_an_auth_token( make_organization, make_user_for_organization, ): - user_id = 90095905 stack_id = 895 - organization_id = 8905 - stack_slug = "mvcmnvcmnvc" - org_slug = "raintank" - - organization = make_organization( - stack_id=stack_id, org_id=organization_id, stack_slug=stack_slug, org_slug=org_slug - ) - user = make_user_for_organization(organization, user_id=user_id) + organization = make_organization(stack_id=stack_id) + user = make_user_for_organization(organization) auth_token = MobileAppGatewayView._get_auth_token(DOWNSTREAM_BACKEND, user) assert auth_token == f"{stack_id}:{MOCK_AUTH_TOKEN}" - - mock_request_signed_token.assert_called_once_with( - organization, - [CloudAuthApiClient.Scopes.INCIDENT_WRITE], - { - "user_id": user.user_id, # grafana user ID - "user_email": user.email, - "stack_id": organization.stack_id, - "organization_id": organization.org_id, # grafana org ID - "stack_slug": organization.stack_slug, - "org_slug": organization.org_slug, - }, - ) + mock_request_signed_token.assert_called_once_with(user, [CloudAuthApiClient.Scopes.INCIDENT_WRITE]) diff --git a/engine/apps/mobile_app/views.py b/engine/apps/mobile_app/views.py index af9dcf70..f113f135 100644 --- a/engine/apps/mobile_app/views.py +++ b/engine/apps/mobile_app/views.py @@ -153,20 +153,11 @@ class MobileAppGatewayView(APIView): HS256 = symmetric = shared secret (don't use this) """ org = user.organization - token_claims = { - "user_id": user.user_id, # grafana user ID - "user_email": user.email, - "stack_id": org.stack_id, - "organization_id": org.org_id, # grafana org ID - "stack_slug": org.stack_slug, - "org_slug": org.org_slug, - } - token_scopes = { cls.SupportedDownstreamBackends.INCIDENT: [CloudAuthApiClient.Scopes.INCIDENT_WRITE], }[downstream_backend] - return f"{org.stack_id}:{CloudAuthApiClient().request_signed_token(org, token_scopes, token_claims)}" + return f"{org.stack_id}:{CloudAuthApiClient().request_signed_token(user, token_scopes)}" @classmethod def _get_downstream_headers( @@ -174,7 +165,6 @@ class MobileAppGatewayView(APIView): ) -> typing.Dict[str, str]: headers = { "Authorization": f"Bearer {cls._get_auth_token(downstream_backend, user)}", - "X-Grafana-User": f"email:{user.email}", } if (v := request.META.get("CONTENT_TYPE", None)) is not None: diff --git a/engine/common/cloud_auth_api/client.py b/engine/common/cloud_auth_api/client.py index 7939b4ee..32bcbfbb 100644 --- a/engine/common/cloud_auth_api/client.py +++ b/engine/common/cloud_auth_api/client.py @@ -9,7 +9,7 @@ from django.conf import settings from rest_framework import status if typing.TYPE_CHECKING: - from apps.user_management.models import Organization + from apps.user_management.models import User logger = logging.getLogger(__name__) @@ -43,8 +43,13 @@ class CloudAuthApiClient: self.api_token = settings.GRAFANA_CLOUD_AUTH_API_SYSTEM_TOKEN def request_signed_token( - self, org: "Organization", scopes: typing.List[Scopes], claims: typing.Dict[str, typing.Any] + self, + user: "User", + scopes: typing.List[Scopes], + extra_claims: typing.Optional[typing.Dict[str, typing.Any]] = None, ) -> str: + org = user.organization + # The Cloud Auth API expects the org_id and stack_id to be strings org_id = str(org.org_id) stack_id = str(org.stack_id) @@ -73,7 +78,10 @@ class CloudAuthApiClient: url, headers=headers, json={ - "claims": claims, + "claims": { + "sub": f"email:{user.email}", + }, + "extra": extra_claims or {}, "accessPolicy": { "scopes": scopes, }, diff --git a/engine/common/cloud_auth_api/tests/test_client.py b/engine/common/cloud_auth_api/tests/test_client.py index 94785c68..6a34078f 100644 --- a/engine/common/cloud_auth_api/tests/test_client.py +++ b/engine/common/cloud_auth_api/tests/test_client.py @@ -19,7 +19,7 @@ def configure_cloud_auth_api_client(settings): @pytest.mark.django_db @pytest.mark.parametrize("response_status_code", [status.HTTP_200_OK, status.HTTP_401_UNAUTHORIZED]) @httpretty.activate(verbose=True, allow_net_connect=False) -def test_request_signed_token(make_organization, response_status_code): +def test_request_signed_token(make_organization, make_user_for_organization, response_status_code): mock_auth_token = ",mnasdlkjlakjoqwejroiqwejr" mock_response_text = "error message" @@ -27,12 +27,13 @@ def test_request_signed_token(make_organization, response_status_code): stack_id = 5 organization = make_organization(stack_id=stack_id, org_id=org_id) + user = make_user_for_organization(organization=organization) scopes = ["incident:write", "foo:bar"] - claims = {"vegetable": "carrot", "fruit": "apple"} + extra_claims = {"vegetable": "carrot", "fruit": "apple"} def _make_request(): - return CloudAuthApiClient().request_signed_token(organization, scopes, claims) + return CloudAuthApiClient().request_signed_token(user, scopes, extra_claims) url = f"{GRAFANA_CLOUD_AUTH_API_URL}/v1/sign" mock_response = httpretty.Response(json.dumps({"data": {"token": mock_auth_token}}), status=response_status_code) @@ -55,7 +56,10 @@ def test_request_signed_token(make_organization, response_status_code): # assert we're sending the right body assert json.loads(last_request.body) == { - "claims": claims, + "claims": { + "sub": f"email:{user.email}", + }, + "extra": extra_claims, "accessPolicy": { "scopes": scopes, },