Skip to content

Commit 0cd9585

Browse files
Ajay KumarAjay Kumar
authored andcommitted
Updates Base URL + Requirements Version
1 parent 979d4bb commit 0cd9585

File tree

3 files changed

+184
-6
lines changed

3 files changed

+184
-6
lines changed

python-django-sso-example/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ pytz==2021.1
77
requests==2.25.1
88
sqlparse==0.4.2
99
urllib3==1.26.5
10-
workos>=1.23.3
10+
workos>=5.37.0
1111
python-dotenv
Lines changed: 181 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,182 @@
1-
from django.test import TestCase
1+
from django.test import TestCase, Client
2+
from django.urls import reverse
3+
from unittest.mock import patch, MagicMock
4+
import os
5+
# Import views module to ensure workos is loaded before patching
6+
from sso import views
27

3-
# Create your tests here.
8+
9+
class SSOViewTests(TestCase):
10+
def setUp(self):
11+
self.client = Client()
12+
# Set environment variables for testing
13+
os.environ["WORKOS_API_KEY"] = "test_api_key"
14+
os.environ["WORKOS_CLIENT_ID"] = "test_client_id"
15+
os.environ["REDIRECT_URI"] = "http://localhost:8000/auth/callback"
16+
17+
def tearDown(self):
18+
# Clean up environment variables
19+
if "WORKOS_API_KEY" in os.environ:
20+
del os.environ["WORKOS_API_KEY"]
21+
if "WORKOS_CLIENT_ID" in os.environ:
22+
del os.environ["WORKOS_CLIENT_ID"]
23+
if "REDIRECT_URI" in os.environ:
24+
del os.environ["REDIRECT_URI"]
25+
26+
def test_login_no_session(self):
27+
"""Test login view when no session is active"""
28+
response = self.client.get(reverse("login"))
29+
self.assertEqual(response.status_code, 200)
30+
self.assertTemplateUsed(response, "sso/login.html")
31+
32+
def test_login_with_active_session(self):
33+
"""Test login view when session is active"""
34+
session = self.client.session
35+
session["session_active"] = True
36+
session["p_profile"] = {"profile": {"first_name": "Test"}}
37+
session["first_name"] = "Test"
38+
session["raw_profile"] = {"email": "test@example.com"}
39+
session.save()
40+
41+
response = self.client.get(reverse("login"))
42+
self.assertEqual(response.status_code, 200)
43+
self.assertTemplateUsed(response, "sso/login_successful.html")
44+
self.assertIn("p_profile", response.context)
45+
self.assertIn("first_name", response.context)
46+
self.assertIn("raw_profile", response.context)
47+
48+
def test_auth_saml_login(self):
49+
"""Test auth view for SAML login"""
50+
# Create a mock sso object
51+
mock_sso = MagicMock()
52+
mock_sso.get_authorization_url.return_value = "https://api.workos.com/sso/authorize?test=123"
53+
54+
# Create a mock client with sso attribute
55+
mock_client = MagicMock()
56+
mock_client.sso = mock_sso
57+
58+
with patch.object(views.workos, "client", mock_client):
59+
response = self.client.post(
60+
reverse("auth"),
61+
{"login_method": "saml"},
62+
follow=False
63+
)
64+
65+
# Verify get_authorization_url was called with correct params
66+
mock_sso.get_authorization_url.assert_called_once()
67+
call_args = mock_sso.get_authorization_url.call_args
68+
self.assertIn("redirect_uri", call_args.kwargs)
69+
self.assertIn("state", call_args.kwargs)
70+
self.assertIn("organization_id", call_args.kwargs)
71+
self.assertEqual(call_args.kwargs["organization_id"], "xxx")
72+
self.assertNotIn("provider", call_args.kwargs)
73+
74+
# Verify redirect response
75+
self.assertEqual(response.status_code, 302)
76+
self.assertEqual(response.url, "https://api.workos.com/sso/authorize?test=123")
77+
78+
def test_auth_provider_login(self):
79+
"""Test auth view for provider-based login (Google, Microsoft, etc.)"""
80+
# Create a mock sso object
81+
mock_sso = MagicMock()
82+
mock_sso.get_authorization_url.return_value = "https://api.workos.com/sso/authorize?provider=google"
83+
84+
# Create a mock client with sso attribute
85+
mock_client = MagicMock()
86+
mock_client.sso = mock_sso
87+
88+
with patch.object(views.workos, "client", mock_client):
89+
response = self.client.post(
90+
reverse("auth"),
91+
{"login_method": "google"},
92+
follow=False
93+
)
94+
95+
# Verify get_authorization_url was called with correct params
96+
mock_sso.get_authorization_url.assert_called_once()
97+
call_args = mock_sso.get_authorization_url.call_args
98+
self.assertIn("redirect_uri", call_args.kwargs)
99+
self.assertIn("state", call_args.kwargs)
100+
self.assertIn("provider", call_args.kwargs)
101+
self.assertEqual(call_args.kwargs["provider"], "google")
102+
self.assertNotIn("organization_id", call_args.kwargs)
103+
104+
# Verify redirect response
105+
self.assertEqual(response.status_code, 302)
106+
self.assertEqual(response.url, "https://api.workos.com/sso/authorize?provider=google")
107+
108+
def test_auth_callback_success(self):
109+
"""Test auth_callback view with valid code"""
110+
# Mock the profile response
111+
mock_profile = MagicMock()
112+
mock_profile.to_dict.return_value = {
113+
"profile": {
114+
"first_name": "John",
115+
"last_name": "Doe",
116+
"email": "john.doe@example.com"
117+
}
118+
}
119+
120+
# Create a mock sso object
121+
mock_sso = MagicMock()
122+
mock_sso.get_profile_and_token.return_value = mock_profile
123+
124+
# Create a mock client with sso attribute
125+
mock_client = MagicMock()
126+
mock_client.sso = mock_sso
127+
128+
with patch.object(views.workos, "client", mock_client):
129+
response = self.client.get(
130+
reverse("auth_callback"),
131+
{"code": "test_auth_code"},
132+
follow=True
133+
)
134+
135+
# Verify get_profile_and_token was called with the code
136+
mock_sso.get_profile_and_token.assert_called_once_with("test_auth_code")
137+
138+
# Verify session data was set
139+
self.assertTrue(self.client.session.get("session_active"))
140+
self.assertIn("p_profile", self.client.session)
141+
self.assertEqual(self.client.session["first_name"], "John")
142+
self.assertIn("raw_profile", self.client.session)
143+
144+
# Verify redirect to login
145+
self.assertEqual(response.status_code, 200)
146+
self.assertTemplateUsed(response, "sso/login_successful.html")
147+
148+
def test_auth_callback_missing_code(self):
149+
"""Test auth_callback view when code parameter is missing"""
150+
# Create a mock sso object
151+
mock_sso = MagicMock()
152+
153+
# Create a mock client with sso attribute
154+
mock_client = MagicMock()
155+
mock_client.sso = mock_sso
156+
157+
# This should raise a KeyError or return an error
158+
with patch.object(views.workos, "client", mock_client):
159+
with self.assertRaises(KeyError):
160+
self.client.get(reverse("auth_callback"))
161+
162+
def test_logout(self):
163+
"""Test logout view clears session and redirects"""
164+
# Set up a session first
165+
session = self.client.session
166+
session["session_active"] = True
167+
session["p_profile"] = {"profile": {"first_name": "Test"}}
168+
session.save()
169+
170+
# Verify session has data
171+
self.assertTrue(self.client.session.get("session_active"))
172+
173+
# Call logout
174+
response = self.client.get(reverse("logout"), follow=True)
175+
176+
# Verify session is cleared
177+
self.assertFalse(self.client.session.get("session_active"))
178+
self.assertNotIn("p_profile", self.client.session)
179+
180+
# Verify redirect to login
181+
self.assertEqual(response.status_code, 200)
182+
self.assertTemplateUsed(response, "sso/login.html")

python-django-sso-example/sso/views.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
# In workos_django/settings.py, you can use DEBUG=True for local development,
1313
# but you must use DEBUG=False in order to test the full authentication flow
1414
# with the WorkOS API.
15-
workos.base_api_url = (
16-
"http://localhost:8000/" if settings.DEBUG else workos.base_api_url
17-
)
15+
if settings.DEBUG:
16+
os.environ["WORKOS_API_BASE_URL"] = "http://localhost:8000/"
1817

1918
# Constants
2019
# Required: Fill in CUSTOMER_ORGANIZATION_ID for the desired organization from the WorkOS Dashboard

0 commit comments

Comments
 (0)