mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
224 lines
8.1 KiB
Python
224 lines
8.1 KiB
Python
from __future__ import annotations
|
|
|
|
from time import time
|
|
from typing import Any
|
|
from unittest.mock import Mock, patch
|
|
from urllib.parse import parse_qs
|
|
|
|
import pytest
|
|
import responses
|
|
from django.forms import ChoiceField
|
|
from django.http import HttpRequest
|
|
|
|
from sentry.identity.vsts.provider import VSTSIdentityProvider, VSTSOAuth2CallbackView
|
|
from sentry.integrations.vsts.integration import AccountConfigView, AccountForm
|
|
from sentry.models.identity import Identity
|
|
from sentry.testutils.cases import TestCase
|
|
from sentry.testutils.silo import control_silo_test
|
|
|
|
|
|
@control_silo_test
|
|
class TestVSTSOAuthCallbackView(TestCase):
|
|
@responses.activate
|
|
def test_exchange_token(self):
|
|
def redirect_url():
|
|
return "https://app.vssps.visualstudio.com/oauth2/authorize"
|
|
|
|
view = VSTSOAuth2CallbackView(
|
|
access_token_url="https://app.vssps.visualstudio.com/oauth2/token",
|
|
client_id="vsts-client-id",
|
|
client_secret="vsts-client-secret",
|
|
)
|
|
request = Mock()
|
|
pipeline = Mock()
|
|
|
|
pipeline.redirect_url = redirect_url
|
|
|
|
responses.add(
|
|
responses.POST,
|
|
"https://app.vssps.visualstudio.com/oauth2/token",
|
|
json={
|
|
"access_token": "xxxxxxxxx",
|
|
"token_type": "jwt-bearer",
|
|
"expires_in": "3599",
|
|
"refresh_token": "zzzzzzzzzz",
|
|
},
|
|
)
|
|
|
|
result = view.exchange_token(request, pipeline, "oauth-code")
|
|
mock_request = responses.calls[0].request
|
|
req_params = parse_qs(mock_request.body)
|
|
|
|
assert req_params["grant_type"] == ["urn:ietf:params:oauth:grant-type:jwt-bearer"]
|
|
assert req_params["assertion"] == ["oauth-code"]
|
|
assert req_params["redirect_uri"] == ["https://app.vssps.visualstudio.com/oauth2/authorize"]
|
|
assert req_params["client_assertion_type"] == [
|
|
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
|
|
]
|
|
assert req_params["client_assertion"] == ["vsts-client-secret"]
|
|
|
|
assert result["access_token"] == "xxxxxxxxx"
|
|
assert result["token_type"] == "jwt-bearer"
|
|
assert result["expires_in"] == "3599"
|
|
assert result["refresh_token"] == "zzzzzzzzzz"
|
|
|
|
|
|
@control_silo_test
|
|
class TestAccountConfigView(TestCase):
|
|
def setUp(self):
|
|
responses.reset()
|
|
account_id = "1234567-8910"
|
|
self.base_url = "http://sentry2.visualstudio.com/"
|
|
self.accounts: list[dict[str, Any]] = [
|
|
{
|
|
"accountId": "1234567-89",
|
|
"NamespaceId": "00000000-0000-0000-0000-000000000000",
|
|
"accountName": "sentry",
|
|
"OrganizationName": None,
|
|
"AccountType": 0,
|
|
"AccountOwner": "00000000-0000-0000-0000-000000000000",
|
|
"CreatedBy": "00000000-0000-0000-0000-000000000000",
|
|
"CreatedDate": "0001-01-01T00:00:00",
|
|
"AccountStatus": 0,
|
|
"StatusReason": None,
|
|
"LastUpdatedBy": "00000000-0000-0000-0000-000000000000",
|
|
"Properties": {},
|
|
},
|
|
{
|
|
"accountId": account_id,
|
|
"NamespaceId": "00000000-0000-0000-0000-000000000000",
|
|
"accountName": "sentry2",
|
|
"OrganizationName": None,
|
|
"AccountType": 0,
|
|
"AccountOwner": "00000000-0000-0000-0000-000000000000",
|
|
"CreatedBy": "00000000-0000-0000-0000-000000000000",
|
|
"CreatedDate": "0001-01-01T00:00:00",
|
|
"AccountStatus": 0,
|
|
"StatusReason": None,
|
|
"LastUpdatedBy": "00000000-0000-0000-0000-000000000000",
|
|
"Properties": {},
|
|
},
|
|
]
|
|
responses.add(
|
|
responses.GET,
|
|
"https://app.vssps.visualstudio.com/_apis/accounts",
|
|
json={"value": self.accounts, "count": len(self.accounts)},
|
|
status=200,
|
|
)
|
|
responses.add(
|
|
responses.GET,
|
|
"https://app.vssps.visualstudio.com/_apis/resourceareas/79134C72-4A58-4B42-976C-04E7115F32BF?hostId=%s&api-preview=5.0-preview.1"
|
|
% account_id,
|
|
json={"locationUrl": self.base_url},
|
|
)
|
|
|
|
@responses.activate
|
|
def test_dispatch(self):
|
|
view = AccountConfigView()
|
|
request = HttpRequest()
|
|
request.POST.update({"account": "1234567-8910"})
|
|
|
|
pipeline = Mock()
|
|
pipeline.state = {
|
|
"accounts": self.accounts,
|
|
"identity": {"data": {"access_token": "123456789"}},
|
|
}
|
|
pipeline.fetch_state = lambda key: pipeline.state[key]
|
|
pipeline.bind_state = lambda name, value: pipeline.state.update({name: value})
|
|
|
|
view.dispatch(request, pipeline)
|
|
|
|
assert pipeline.fetch_state(key="account") == self.accounts[1]
|
|
assert pipeline.next_step.call_count == 1
|
|
|
|
@responses.activate
|
|
def test_get_accounts(self):
|
|
view = AccountConfigView()
|
|
accounts = view.get_accounts("access-token", 123)
|
|
assert accounts is not None
|
|
assert accounts["value"][0]["accountName"] == "sentry"
|
|
assert accounts["value"][1]["accountName"] == "sentry2"
|
|
|
|
@responses.activate
|
|
def test_account_form(self):
|
|
account_form = AccountForm(self.accounts)
|
|
field = account_form.fields["account"]
|
|
assert isinstance(field, ChoiceField)
|
|
assert field.choices == [
|
|
("1234567-89", "sentry"),
|
|
("1234567-8910", "sentry2"),
|
|
]
|
|
|
|
@responses.activate
|
|
@patch("sentry.integrations.vsts.integration.get_user_info")
|
|
@patch("sentry.integrations.vsts.integration.render_to_response")
|
|
def test_no_accounts_received(self, mock_render_to_response, mock_get_user_info):
|
|
responses.reset()
|
|
responses.add(
|
|
responses.GET,
|
|
"https://app.vssps.visualstudio.com/_apis/accounts",
|
|
json={"value": [], "count": 0},
|
|
status=200,
|
|
)
|
|
|
|
view = AccountConfigView()
|
|
request = Mock()
|
|
request.POST = {}
|
|
request.user = self.user
|
|
|
|
pipeline = Mock()
|
|
pipeline.fetch_state = lambda key: {"data": {"access_token": "1234567890"}}
|
|
pipeline.organization = self.organization
|
|
|
|
view.dispatch(request, pipeline)
|
|
assert mock_get_user_info.called is True
|
|
assert mock_render_to_response.called is True
|
|
assert mock_render_to_response.call_args[1]["context"] == {"no_accounts": True}
|
|
|
|
|
|
@control_silo_test
|
|
class VstsIdentityProviderTest(TestCase):
|
|
client_secret = "12345678"
|
|
|
|
def setUp(self):
|
|
self.identity_provider_model = self.create_identity_provider(type="vsts")
|
|
self.identity = Identity.objects.create(
|
|
idp=self.identity_provider_model,
|
|
user=self.user,
|
|
external_id="vsts_id",
|
|
data={
|
|
"access_token": "123456789",
|
|
"token_type": "token_type",
|
|
"expires": 12345678,
|
|
"refresh_token": "n354678",
|
|
},
|
|
)
|
|
self.provider = VSTSIdentityProvider()
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def patch_get_oauth_client_secret(self):
|
|
with patch.object(
|
|
VSTSIdentityProvider, "get_oauth_client_secret", return_value=self.client_secret
|
|
):
|
|
yield
|
|
|
|
@responses.activate
|
|
def test_refresh_identity(self):
|
|
refresh_data = {
|
|
"access_token": "access token for this user",
|
|
"token_type": "type of token",
|
|
"expires": 1234567,
|
|
"refresh_token": "new refresh token to use when the token has timed out",
|
|
}
|
|
responses.add(
|
|
responses.POST, "https://app.vssps.visualstudio.com/oauth2/token", json=refresh_data
|
|
)
|
|
self.provider.refresh_identity(self.identity, redirect_url="redirect_url")
|
|
|
|
assert len(responses.calls) == 1
|
|
|
|
new_identity = Identity.objects.get(id=self.identity.id)
|
|
assert new_identity.data["access_token"] == refresh_data["access_token"]
|
|
assert new_identity.data["token_type"] == refresh_data["token_type"]
|
|
assert new_identity.data["expires"] <= int(time())
|