예제 #1
0
    def setUp(self):
        self.install = self.create_sentry_app_installation()
        self.code = self.install.api_grant.code
        self.client_id = self.install.sentry_app.application.client_id
        self.user = self.install.sentry_app.proxy_user

        self.grant_exchanger = GrantExchanger(
            install=self.install, client_id=self.client_id, code=self.code, user=self.user
        )
예제 #2
0
    def test_records_analytics(self, record):
        GrantExchanger.run(
            install=self.install, client_id=self.client_id, code=self.code, user=self.user
        )

        record.assert_called_with(
            "sentry_app.token_exchanged",
            sentry_app_installation_id=self.install.id,
            exchange_type="authorization",
        )
예제 #3
0
    def test_records_analytics(self, record):
        GrantExchanger.run(
            install=self.install,
            client_id=self.client_id,
            code=self.code,
            user=self.user,
        )

        record.assert_called_with(
            'sentry_app.token_exchanged',
            sentry_app_installation_id=self.install.id,
            exchange_type='authorization',
        )
예제 #4
0
    def post(self, request, installation):
        try:
            if request.json_body.get("grant_type") == GrantTypes.AUTHORIZATION:
                token = GrantExchanger.run(
                    install=installation,
                    code=request.json_body.get("code"),
                    client_id=request.json_body.get("client_id"),
                    user=request.user,
                )
            elif request.json_body.get("grant_type") == GrantTypes.REFRESH:
                token = Refresher.run(
                    install=installation,
                    refresh_token=request.json_body.get("refresh_token"),
                    client_id=request.json_body.get("client_id"),
                    user=request.user,
                )
            else:
                return Response({"error": "Invalid grant_type"}, status=403)
        except APIUnauthorized as e:
            return Response({"error": e.msg or "Unauthorized"}, status=403)

        attrs = {"state": request.json_body.get("state"), "application": None}

        body = ApiTokenSerializer().serialize(token, attrs, request.user)

        return Response(body, status=201)
예제 #5
0
    def post(self, request, installation):
        with sentry_sdk.configure_scope() as scope:
            scope.set_tag("organization", installation.organization_id)
            scope.set_tag("sentry_app_id", installation.sentry_app_id)
            scope.set_tag("sentry_app_slug", installation.sentry_app.slug)

            try:
                if request.json_body.get("grant_type") == GrantTypes.AUTHORIZATION:
                    token = GrantExchanger.run(
                        install=installation,
                        code=request.json_body.get("code"),
                        client_id=request.json_body.get("client_id"),
                        user=request.user,
                    )
                elif request.json_body.get("grant_type") == GrantTypes.REFRESH:
                    token = Refresher.run(
                        install=installation,
                        refresh_token=request.json_body.get("refresh_token"),
                        client_id=request.json_body.get("client_id"),
                        user=request.user,
                    )
                else:
                    return Response({"error": "Invalid grant_type"}, status=403)
            except APIUnauthorized as e:
                logger.error(e, exc_info=True)
                return Response({"error": e.msg or "Unauthorized"}, status=403)

            attrs = {"state": request.json_body.get("state"), "application": None}

            body = ApiTokenSerializer().serialize(token, attrs, request.user)

            return Response(body, status=201)
예제 #6
0
    def test_non_internal_app(self):
        sentry_app = self.create_sentry_app(name="My External App",
                                            organization=self.org)

        install = self.create_sentry_app_installation(slug=sentry_app.slug,
                                                      organization=self.org,
                                                      user=self.user)

        client_id = install.sentry_app.application.client_id
        user = install.sentry_app.proxy_user

        api_token = GrantExchanger.run(install=install,
                                       code=install.api_grant.code,
                                       client_id=client_id,
                                       user=user)

        url = reverse(
            "sentry-api-0-sentry-internal-app-token-details",
            args=[install.sentry_app.slug, api_token.token],
        )

        self.login_as(user=self.user)
        response = self.client.delete(url, format="json")

        assert response.status_code == 403
        assert response.data == "This route is limited to internal integrations only"
예제 #7
0
    def test_organization(self):
        self.request.session = {}
        sentry_app = self.create_sentry_app(name="Tesla App",
                                            published=True,
                                            organization=self.organization)
        install = self.create_sentry_app_installation(
            slug=sentry_app.slug,
            organization=self.organization,
            user=self.user)

        client_id = sentry_app.application.client_id
        user = sentry_app.proxy_user

        api_token = GrantExchanger.run(install=install,
                                       code=install.api_grant.code,
                                       client_id=client_id,
                                       user=user)

        self.request.user = sentry_app.proxy_user

        self.request.auth = api_token

        assert (
            get_rate_limit_key(self.view, self.request) ==
            f"org:OrganizationGroupIndexEndpoint:GET:{install.organization_id}"
        )
    def post(self, request, installation):
        try:
            if request.json_body.get('grant_type') == GrantTypes.AUTHORIZATION:
                token = GrantExchanger.run(
                    install=installation,
                    code=request.json_body.get('code'),
                    client_id=request.json_body.get('client_id'),
                    user=request.user,
                )
            elif request.json_body.get('grant_type') == GrantTypes.REFRESH:
                token = Refresher.run(
                    install=installation,
                    refresh_token=request.json_body.get('refresh_token'),
                    client_id=request.json_body.get('client_id'),
                    user=request.user,
                )
            else:
                return Response({'error': 'Invalid grant_type'}, status=403)
        except APIUnauthorized as e:
            return Response({'error': e.msg or 'Unauthorized'}, status=403)

        attrs = {
            'state': request.json_body.get('state'),
            'application': None,
        }

        body = ApiTokenSerializer().serialize(token, attrs, request.user)

        return Response(body, status=201)
예제 #9
0
 def setUp(self):
     super().setUp()
     self.token = GrantExchanger.run(
         install=self.installation,
         code=self.installation.api_grant.code,
         client_id=self.published_app.application.client_id,
         user=self.published_app.proxy_user,
     )
예제 #10
0
    def setUp(self):
        self.install = self.create_sentry_app_installation()
        self.code = self.install.api_grant.code
        self.client_id = self.install.sentry_app.application.client_id
        self.user = self.install.sentry_app.proxy_user

        self.grant_exchanger = GrantExchanger(
            install=self.install,
            client_id=self.client_id,
            code=self.code,
            user=self.user,
        )
예제 #11
0
 def test_sentry_app_installation_mark_installed_wrong_app(self):
     self.token = GrantExchanger.run(
         install=self.installation2,
         code=self.installation2.api_grant.code,
         client_id=self.unpublished_app.application.client_id,
         user=self.unpublished_app.proxy_user,
     )
     self.url = reverse("sentry-api-0-sentry-app-installation-details",
                        args=[self.installation.uuid])
     response = self.client.put(
         self.url,
         data={"status": "installed"},
         HTTP_AUTHORIZATION=f"Bearer {self.token.token}",
         format="json",
     )
     assert response.status_code == 403
예제 #12
0
    def setUp(self):
        self.install = self.create_sentry_app_installation()
        self.client_id = self.install.sentry_app.application.client_id
        self.user = self.install.sentry_app.proxy_user

        self.token = GrantExchanger.run(
            install=self.install,
            code=self.install.api_grant.code,
            client_id=self.client_id,
            user=self.user,
        )

        self.refresher = Refresher(
            install=self.install,
            client_id=self.client_id,
            refresh_token=self.token.refresh_token,
            user=self.user,
        )
예제 #13
0
    def setUp(self):
        self.install = self.create_sentry_app_installation()
        self.client_id = self.install.sentry_app.application.client_id
        self.user = self.install.sentry_app.proxy_user

        self.token = GrantExchanger.run(
            install=self.install,
            code=self.install.api_grant.code,
            client_id=self.client_id,
            user=self.user,
        )

        self.refresher = Refresher(
            install=self.install,
            client_id=self.client_id,
            refresh_token=self.token.refresh_token,
            user=self.user,
        )
 def test_sentry_app_installation_mark_installed_wrong_app(self):
     self.token = GrantExchanger.run(
         install=self.installation2,
         code=self.installation2.api_grant.code,
         client_id=self.unpublished_app.application.client_id,
         user=self.unpublished_app.proxy_user,
     )
     self.url = reverse(
         'sentry-api-0-sentry-app-installation-details',
         args=[self.installation.uuid],
     )
     response = self.client.put(
         self.url,
         data={'status': 'installed'},
         HTTP_AUTHORIZATION=u'Bearer {}'.format(self.token.token),
         format='json',
     )
     assert response.status_code == 403
예제 #15
0
class TestGrantExchanger(TestCase):
    def setUp(self):
        self.install = self.create_sentry_app_installation()
        self.code = self.install.api_grant.code
        self.client_id = self.install.sentry_app.application.client_id
        self.user = self.install.sentry_app.proxy_user

        self.grant_exchanger = GrantExchanger(
            install=self.install,
            client_id=self.client_id,
            code=self.code,
            user=self.user,
        )

    def test_happy_path(self):
        assert self.grant_exchanger.call()

    @patch('sentry.mediators.token_exchange.Validator.run')
    def test_validate_generic_token_exchange_requirements(self, validator):
        self.grant_exchanger.call()

        validator.assert_called_once_with(
            install=self.install,
            client_id=self.client_id,
            user=self.user,
        )

    def test_grant_must_belong_to_installations(self):
        other_install = self.create_sentry_app_installation()
        self.grant_exchanger.code = other_install.api_grant.code

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_request_user_owns_api_grant(self):
        self.grant_exchanger.user = self.create_user()

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_grant_must_be_active(self):
        self.install.api_grant.update(expires_at=(datetime.utcnow() -
                                                  timedelta(hours=1)))

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_grant_must_exist(self):
        self.grant_exchanger.code = '123'

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    @patch('sentry.models.ApiGrant.application',
           side_effect=ApiApplication.DoesNotExist)
    def test_application_must_exist(self, _):
        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    @patch('sentry.models.ApiApplication.sentry_app',
           side_effect=SentryApp.DoesNotExist)
    def test_sentry_app_must_exist(self, _):
        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()
예제 #16
0
class TestGrantExchanger(TestCase):
    def setUp(self):
        self.install = self.create_sentry_app_installation()
        self.code = self.install.api_grant.code
        self.client_id = self.install.sentry_app.application.client_id
        self.user = self.install.sentry_app.proxy_user

        self.grant_exchanger = GrantExchanger(
            install=self.install,
            client_id=self.client_id,
            code=self.code,
            user=self.user,
        )

    def test_happy_path(self):
        assert self.grant_exchanger.call()

    @patch('sentry.mediators.token_exchange.Validator.run')
    def test_validate_generic_token_exchange_requirements(self, validator):
        self.grant_exchanger.call()

        validator.assert_called_once_with(
            install=self.install,
            client_id=self.client_id,
            user=self.user,
        )

    def test_grant_must_belong_to_installations(self):
        other_install = self.create_sentry_app_installation()
        self.grant_exchanger.code = other_install.api_grant.code

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_request_user_owns_api_grant(self):
        self.grant_exchanger.user = self.create_user()

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_grant_must_be_active(self):
        self.install.api_grant.update(expires_at=(datetime.utcnow() - timedelta(hours=1)))

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_grant_must_exist(self):
        self.grant_exchanger.code = '123'

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    @patch('sentry.models.ApiGrant.application', side_effect=ApiApplication.DoesNotExist)
    def test_application_must_exist(self, _):
        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    @patch('sentry.models.ApiApplication.sentry_app', side_effect=SentryApp.DoesNotExist)
    def test_sentry_app_must_exist(self, _):
        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()
예제 #17
0
class TestGrantExchanger(TestCase):
    def setUp(self):
        self.install = self.create_sentry_app_installation()
        self.code = self.install.api_grant.code
        self.client_id = self.install.sentry_app.application.client_id
        self.user = self.install.sentry_app.proxy_user

        self.grant_exchanger = GrantExchanger(install=self.install,
                                              client_id=self.client_id,
                                              code=self.code,
                                              user=self.user)

    def test_happy_path(self):
        assert self.grant_exchanger.call()

    def test_adds_token_to_installation(self):
        token = self.grant_exchanger.call()
        assert SentryAppInstallation.objects.get(
            id=self.install.id).api_token == token

    @patch("sentry.mediators.token_exchange.Validator.run")
    def test_validate_generic_token_exchange_requirements(self, validator):
        self.grant_exchanger.call()

        validator.assert_called_once_with(install=self.install,
                                          client_id=self.client_id,
                                          user=self.user)

    def test_grant_must_belong_to_installations(self):
        other_install = self.create_sentry_app_installation()
        self.grant_exchanger.code = other_install.api_grant.code

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_request_user_owns_api_grant(self):
        self.grant_exchanger.user = self.create_user()

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_grant_must_be_active(self):
        self.install.api_grant.update(expires_at=(datetime.utcnow() -
                                                  timedelta(hours=1)))

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_grant_must_exist(self):
        self.grant_exchanger.code = "123"

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    @patch("sentry.models.ApiGrant.application",
           side_effect=ApiApplication.DoesNotExist)
    def test_application_must_exist(self, _):
        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    @patch("sentry.models.ApiApplication.sentry_app",
           side_effect=SentryApp.DoesNotExist)
    def test_sentry_app_must_exist(self, _):
        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_deletes_grant_on_successful_exchange(self):
        grant_id = self.install.api_grant_id
        self.grant_exchanger.call()
        assert not ApiGrant.objects.filter(id=grant_id)

    @patch("sentry.analytics.record")
    def test_records_analytics(self, record):
        GrantExchanger.run(install=self.install,
                           client_id=self.client_id,
                           code=self.code,
                           user=self.user)

        record.assert_called_with(
            "sentry_app.token_exchanged",
            sentry_app_installation_id=self.install.id,
            exchange_type="authorization",
        )
예제 #18
0
class TestGrantExchanger(TestCase):
    def setUp(self):
        self.install = self.create_sentry_app_installation()
        self.code = self.install.api_grant.code
        self.client_id = self.install.sentry_app.application.client_id
        self.user = self.install.sentry_app.proxy_user

        self.grant_exchanger = GrantExchanger(
            install=self.install,
            client_id=self.client_id,
            code=self.code,
            user=self.user,
        )

    def test_happy_path(self):
        assert self.grant_exchanger.call()

    def test_adds_token_to_installation(self):
        token = self.grant_exchanger.call()
        assert SentryAppInstallation.objects.get(id=self.install.id).api_token == token

    @patch('sentry.mediators.token_exchange.Validator.run')
    def test_validate_generic_token_exchange_requirements(self, validator):
        self.grant_exchanger.call()

        validator.assert_called_once_with(
            install=self.install,
            client_id=self.client_id,
            user=self.user,
        )

    def test_grant_must_belong_to_installations(self):
        other_install = self.create_sentry_app_installation()
        self.grant_exchanger.code = other_install.api_grant.code

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_request_user_owns_api_grant(self):
        self.grant_exchanger.user = self.create_user()

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_grant_must_be_active(self):
        self.install.api_grant.update(expires_at=(datetime.utcnow() - timedelta(hours=1)))

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_grant_must_exist(self):
        self.grant_exchanger.code = '123'

        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    @patch('sentry.models.ApiGrant.application', side_effect=ApiApplication.DoesNotExist)
    def test_application_must_exist(self, _):
        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    @patch('sentry.models.ApiApplication.sentry_app', side_effect=SentryApp.DoesNotExist)
    def test_sentry_app_must_exist(self, _):
        with self.assertRaises(APIUnauthorized):
            self.grant_exchanger.call()

    def test_deletes_grant_on_successful_exchange(self):
        grant_id = self.install.api_grant_id
        self.grant_exchanger.call()
        assert not ApiGrant.objects.filter(id=grant_id)

    @patch('sentry.analytics.record')
    def test_records_analytics(self, record):
        GrantExchanger.run(
            install=self.install,
            client_id=self.client_id,
            code=self.code,
            user=self.user,
        )

        record.assert_called_with(
            'sentry_app.token_exchanged',
            sentry_app_installation_id=self.install.id,
            exchange_type='authorization',
        )