Skip to content

Commit 150d8ae

Browse files
authored
Add "impersonator" field to WorkOSAuthenticationResponse (#237)
* Add "impersonator" field to `WorkOSAuthenticationResponse` * Fix typo * Run `black` * Switch to less scary looking example key * Run `black tests`
1 parent 9d681ad commit 150d8ae

7 files changed

+63
-33
lines changed

tests/conftest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def __init__(self, content, status_code, headers=None):
2626

2727
@pytest.fixture
2828
def set_api_key(monkeypatch):
29-
monkeypatch.setattr(workos, "api_key", "sk_abdsomecharactersm284")
29+
monkeypatch.setattr(workos, "api_key", "sk_test")
3030

3131

3232
@pytest.fixture

tests/test_directory_sync.py

-15
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ def setup(self, set_api_key, set_client_id):
1313

1414
@pytest.fixture
1515
def mock_users(self):
16-
1716
user_list = [MockDirectoryUser(id=str(i)).to_dict() for i in range(100)]
1817

1918
return {
@@ -36,7 +35,6 @@ def mock_users(self):
3635

3736
@pytest.fixture
3837
def mock_default_limit_users(self):
39-
4038
user_list = [MockDirectoryUser(id=str(i)).to_dict() for i in range(10)]
4139

4240
return {
@@ -59,7 +57,6 @@ def mock_default_limit_users(self):
5957

6058
@pytest.fixture
6159
def mock_default_limit_users_v2(self):
62-
6360
user_list = [MockDirectoryUser(id=str(i)).to_dict() for i in range(10)]
6461

6562
dict_response = {
@@ -84,7 +81,6 @@ def mock_default_limit_users_v2(self):
8481

8582
@pytest.fixture
8683
def mock_users_pagination_response(self):
87-
8884
user_list = [MockDirectoryUser(id=str(i)).to_dict() for i in range(90)]
8985

9086
return {
@@ -107,7 +103,6 @@ def mock_users_pagination_response(self):
107103

108104
@pytest.fixture
109105
def mock_groups(self):
110-
111106
group_list = [MockDirectoryGroup(id=str(i)).to_dict() for i in range(5000)]
112107

113108
return {
@@ -130,7 +125,6 @@ def mock_groups(self):
130125

131126
@pytest.fixture
132127
def mock_default_limit_groups(self):
133-
134128
group_list = [MockDirectoryGroup(id=str(i)).to_dict() for i in range(10)]
135129

136130
return {
@@ -153,7 +147,6 @@ def mock_default_limit_groups(self):
153147

154148
@pytest.fixture
155149
def mock_default_limit_groups_v2(self):
156-
157150
group_list = [MockDirectoryGroup(id=str(i)).to_dict() for i in range(10)]
158151

159152
dict_response = {
@@ -178,7 +171,6 @@ def mock_default_limit_groups_v2(self):
178171

179172
@pytest.fixture
180173
def mock_groups_pagination_reponse(self):
181-
182174
group_list = [MockDirectoryGroup(id=str(i)).to_dict() for i in range(4990)]
183175

184176
return {
@@ -243,7 +235,6 @@ def mock_group(self):
243235

244236
@pytest.fixture
245237
def mock_directories(self):
246-
247238
directory_list = [MockDirectory(id=str(i)).to_dict() for i in range(5000)]
248239

249240
return {
@@ -266,7 +257,6 @@ def mock_directories(self):
266257

267258
@pytest.fixture
268259
def mock_directories_with_limit(self):
269-
270260
directory_list = [MockDirectory(id=str(i)).to_dict() for i in range(4)]
271261

272262
return {
@@ -288,7 +278,6 @@ def mock_directories_with_limit(self):
288278

289279
@pytest.fixture
290280
def mock_directories_with_limit_v2(self):
291-
292281
directory_list = [MockDirectory(id=str(i)).to_dict() for i in range(4)]
293282

294283
dict_response = {
@@ -312,7 +301,6 @@ def mock_directories_with_limit_v2(self):
312301

313302
@pytest.fixture
314303
def mock_default_limit_directories(self):
315-
316304
directory_list = [MockDirectory(id=str(i)).to_dict() for i in range(10)]
317305

318306
return {
@@ -335,7 +323,6 @@ def mock_default_limit_directories(self):
335323

336324
@pytest.fixture
337325
def mock_default_limit_directories_v2(self):
338-
339326
directory_list = [MockDirectory(id=str(i)).to_dict() for i in range(10)]
340327

341328
dict_response = {
@@ -360,7 +347,6 @@ def mock_default_limit_directories_v2(self):
360347

361348
@pytest.fixture
362349
def mock_directories_pagination_response(self):
363-
364350
directory_list = [MockDirectory(id=str(i)).to_dict() for i in range(4990)]
365351

366352
return {
@@ -502,7 +488,6 @@ def test_list_directories_auto_pagination_v2(
502488
mock_directories,
503489
mock_request_method,
504490
):
505-
506491
directories = mock_default_limit_directories_v2
507492
mock_request_method("get", mock_directories_pagination_response, 200)
508493
all_directories = directories.auto_paging_iter()

tests/test_sso.py

-8
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ def mock_connection(self):
6363

6464
@pytest.fixture
6565
def mock_connections(self):
66-
6766
connection_list = [MockConnection(id=str(i)).to_dict() for i in range(5000)]
6867

6968
return {
@@ -84,7 +83,6 @@ def mock_connections(self):
8483

8584
@pytest.fixture
8685
def mock_connections_with_limit(self):
87-
8886
connection_list = [MockConnection(id=str(i)).to_dict() for i in range(4)]
8987

9088
return {
@@ -106,7 +104,6 @@ def mock_connections_with_limit(self):
106104

107105
@pytest.fixture
108106
def mock_connections_with_limit_v2(self, set_api_key_and_client_id):
109-
110107
connection_list = [MockConnection(id=str(i)).to_dict() for i in range(4)]
111108

112109
dict_response = {
@@ -129,7 +126,6 @@ def mock_connections_with_limit_v2(self, set_api_key_and_client_id):
129126

130127
@pytest.fixture
131128
def mock_connections_with_default_limit(self):
132-
133129
connection_list = [MockConnection(id=str(i)).to_dict() for i in range(10)]
134130

135131
return {
@@ -152,7 +148,6 @@ def mock_connections_with_default_limit(self):
152148

153149
@pytest.fixture
154150
def mock_connections_with_default_limit_v2(self, setup_with_client_id):
155-
156151
connection_list = [MockConnection(id=str(i)).to_dict() for i in range(10)]
157152

158153
dict_response = {
@@ -176,7 +171,6 @@ def mock_connections_with_default_limit_v2(self, setup_with_client_id):
176171

177172
@pytest.fixture
178173
def mock_connections_pagination_response(self):
179-
180174
connection_list = [MockConnection(id=str(i)).to_dict() for i in range(4990)]
181175

182176
return {
@@ -565,7 +559,6 @@ def test_list_connections_honors_limit(
565559
mock_request_method,
566560
setup_with_client_id,
567561
):
568-
569562
connections = mock_connections_with_limit
570563
mock_request_method("get", mock_connections_pagination_response, 200)
571564
all_connections = SSO.construct_from_response(connections).auto_paging_iter()
@@ -579,7 +572,6 @@ def test_list_connections_honors_limit_v2(
579572
mock_request_method,
580573
setup_with_client_id,
581574
):
582-
583575
connections = mock_connections_with_limit_v2
584576
mock_request_method("get", mock_connections_pagination_response, 200)
585577
all_connections = connections.auto_paging_iter()

tests/test_user_management.py

+38-6
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,19 @@ def mock_auth_response(self):
140140

141141
return {"user": user, "organization_id": "org_12345"}
142142

143+
@pytest.fixture
144+
def mock_auth_response_with_impersonator(self):
145+
user = MockUser("user_01H7ZGXFP5C6BBQY6Z7277ZCT0").to_dict()
146+
147+
return {
148+
"user": user,
149+
"organization_id": "org_12345",
150+
"impersonator": {
151+
"email": "[email protected]",
152+
"reason": "Debugging an account issue.",
153+
},
154+
}
155+
143156
@pytest.fixture
144157
def mock_magic_auth_challenge_response(self):
145158
return {
@@ -546,7 +559,7 @@ def test_authenticate_with_password(
546559
assert request["json"]["user_agent"] == user_agent
547560
assert request["json"]["ip_address"] == ip_address
548561
assert request["json"]["client_id"] == "client_b27needthisforssotemxo"
549-
assert request["json"]["client_secret"] == "sk_abdsomecharactersm284"
562+
assert request["json"]["client_secret"] == "sk_test"
550563
assert request["json"]["grant_type"] == "password"
551564

552565
def test_authenticate_with_code(self, capture_and_mock_request, mock_auth_response):
@@ -569,9 +582,28 @@ def test_authenticate_with_code(self, capture_and_mock_request, mock_auth_respon
569582
assert request["json"]["user_agent"] == user_agent
570583
assert request["json"]["ip_address"] == ip_address
571584
assert request["json"]["client_id"] == "client_b27needthisforssotemxo"
572-
assert request["json"]["client_secret"] == "sk_abdsomecharactersm284"
585+
assert request["json"]["client_secret"] == "sk_test"
573586
assert request["json"]["grant_type"] == "authorization_code"
574587

588+
def test_authenticate_impersonator_with_code(
589+
self, capture_and_mock_request, mock_auth_response_with_impersonator
590+
):
591+
code = "test_code"
592+
593+
url, request = capture_and_mock_request(
594+
"post", mock_auth_response_with_impersonator, 200
595+
)
596+
597+
response = self.user_management.authenticate_with_code(
598+
code=code,
599+
)
600+
601+
print(response)
602+
assert url[0].endswith("user_management/authenticate")
603+
assert response["user"]["id"] == "user_01H7ZGXFP5C6BBQY6Z7277ZCT0"
604+
assert response["impersonator"]["email"] == "[email protected]"
605+
assert response["impersonator"]["reason"] == "Debugging an account issue."
606+
575607
def test_authenticate_with_magic_auth(
576608
self, capture_and_mock_request, mock_auth_response
577609
):
@@ -597,7 +629,7 @@ def test_authenticate_with_magic_auth(
597629
assert request["json"]["email"] == email
598630
assert request["json"]["ip_address"] == ip_address
599631
assert request["json"]["client_id"] == "client_b27needthisforssotemxo"
600-
assert request["json"]["client_secret"] == "sk_abdsomecharactersm284"
632+
assert request["json"]["client_secret"] == "sk_test"
601633
assert (
602634
request["json"]["grant_type"]
603635
== "urn:workos:oauth:grant-type:magic-auth:code"
@@ -631,7 +663,7 @@ def test_authenticate_with_email_verification(
631663
)
632664
assert request["json"]["ip_address"] == ip_address
633665
assert request["json"]["client_id"] == "client_b27needthisforssotemxo"
634-
assert request["json"]["client_secret"] == "sk_abdsomecharactersm284"
666+
assert request["json"]["client_secret"] == "sk_test"
635667
assert (
636668
request["json"]["grant_type"]
637669
== "urn:workos:oauth:grant-type:email-verification:code"
@@ -669,7 +701,7 @@ def test_authenticate_with_totp(self, capture_and_mock_request, mock_auth_respon
669701
)
670702
assert request["json"]["ip_address"] == ip_address
671703
assert request["json"]["client_id"] == "client_b27needthisforssotemxo"
672-
assert request["json"]["client_secret"] == "sk_abdsomecharactersm284"
704+
assert request["json"]["client_secret"] == "sk_test"
673705
assert request["json"]["grant_type"] == "urn:workos:oauth:grant-type:mfa-totp"
674706

675707
def test_authenticate_with_organization_selection(
@@ -700,7 +732,7 @@ def test_authenticate_with_organization_selection(
700732
)
701733
assert request["json"]["ip_address"] == ip_address
702734
assert request["json"]["client_id"] == "client_b27needthisforssotemxo"
703-
assert request["json"]["client_secret"] == "sk_abdsomecharactersm284"
735+
assert request["json"]["client_secret"] == "sk_test"
704736
assert (
705737
request["json"]["grant_type"]
706738
== "urn:workos:oauth:grant-type:organization-selection"

tests/test_webhooks.py

-2
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,13 @@ def test_timestamp_outside_threshold(
8181
assert "Timestamp outside the tolerance zone" in str(err.value)
8282

8383
def test_sig_hash_does_not_match_expected_sig_length(self, mock_sig_hash):
84-
8584
result = self.webhooks.constant_time_compare(
8685
mock_sig_hash,
8786
"df25b6efdd39d82e7b30e75ea19655b306860ad5cde3eeaeb6f1dfea029ea25",
8887
)
8988
assert result == False
9089

9190
def test_sig_hash_does_not_match_expected_sig_value(self, mock_sig_hash):
92-
9391
result = self.webhooks.constant_time_compare(
9492
mock_sig_hash,
9593
"df25b6efdd39d82e7b30e75ea19655b306860ad5cde3eeaeb6f1dfea029ea252",

workos/resources/user_management.py

+24
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ def construct_from_response(cls, response):
2121
user = WorkOSUser.construct_from_response(response["user"])
2222
authentication_response.user = user
2323

24+
if "impersonator" in response:
25+
impersonator = WorkOSImpersonator.construct_from_response(
26+
response["impersonator"]
27+
)
28+
authentication_response.impersonator = impersonator
29+
else:
30+
authentication_response.impersonator = None
31+
2432
return authentication_response
2533

2634
def to_dict(self):
@@ -31,6 +39,9 @@ def to_dict(self):
3139
user_dict = self.user.to_dict()
3240
authentication_response_dict["user"] = user_dict
3341

42+
if self.impersonator:
43+
authentication_response_dict["impersonator"] = self.impersonator.to_dict()
44+
3445
return authentication_response_dict
3546

3647

@@ -120,3 +131,16 @@ class WorkOSUser(WorkOSBaseResource):
120131
"created_at",
121132
"updated_at",
122133
]
134+
135+
136+
class WorkOSImpersonator(WorkOSBaseResource):
137+
"""Representation of a WorkOS Dashboard member impersonating a user
138+
139+
Attributes:
140+
OBJECT_FIELDS (list): List of fields a WorkOSImpersonator comprises.
141+
"""
142+
143+
OBJECT_FIELDS = [
144+
"email",
145+
"reason",
146+
]

workos/webhooks.py

-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ def request_helper(self):
2323
DEFAULT_TOLERANCE = 180
2424

2525
def verify_event(self, payload, sig_header, secret, tolerance=DEFAULT_TOLERANCE):
26-
2726
if payload is None:
2827
raise ValueError("Payload body is missing and is a required parameter")
2928
if sig_header is None:

0 commit comments

Comments
 (0)