Skip to content

Commit 89a2a21

Browse files
authored
Recalculate SSO Mappings (#745)
1 parent 25e6de9 commit 89a2a21

File tree

4 files changed

+100
-0
lines changed

4 files changed

+100
-0
lines changed

descope/management/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ class MgmtV1:
179179
sso_settings_path = "/v1/mgmt/sso/settings"
180180
sso_metadata_path = "/v1/mgmt/sso/metadata"
181181
sso_mapping_path = "/v1/mgmt/sso/mapping"
182+
sso_recalculate_mappings_path = "/v1/mgmt/sso/recalculate-mappings"
182183
sso_load_settings_path = "/v2/mgmt/sso/settings" # v2 only
183184
sso_configure_oidc_settings = "/v1/mgmt/sso/oidc"
184185
sso_configure_saml_settings = "/v1/mgmt/sso/saml"

descope/management/sso_settings.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,33 @@ def load_settings(
199199
)
200200
return response.json()
201201

202+
def recalculate_sso_mappings(
203+
self,
204+
tenant_id: str,
205+
sso_id: Optional[str] = None,
206+
):
207+
"""
208+
Recalculate SSO group to role mappings for all users in a tenant.
209+
210+
This method triggers a recalculation of user roles based on the current SSO group mappings.
211+
It will update the roles for all users in the tenant who have SSO group mappings.
212+
213+
Args:
214+
tenant_id (str): The tenant ID (required)
215+
sso_id (str): Optional, specify to recalculate mappings for a specific SSO configuration
216+
217+
Raise:
218+
AuthException: raised if recalculation operation fails
219+
"""
220+
body = {"tenantId": tenant_id}
221+
if sso_id:
222+
body["ssoId"] = sso_id
223+
224+
self._http.post(
225+
uri=MgmtV1.sso_recalculate_mappings_path,
226+
body=body,
227+
)
228+
202229
def delete_settings(
203230
self,
204231
tenant_id: str,

samples/management/sso_sample_app.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ def main():
120120
except AuthException as e:
121121
logging.info(f"Load SSO settings failed {e}")
122122

123+
try:
124+
logging.info("Recalculating SSO mappings for tenant")
125+
descope_client.mgmt.sso.recalculate_sso_mappings(tenant_id)
126+
except AuthException as e:
127+
logging.info(f"Recalculate SSO mappings failed {e}")
128+
123129
# All the following code is DEPRECATED (keeping just for backward compatibility)
124130
try:
125131
logging.info("Get SSO settings for tenant")

tests/management/test_sso_settings.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,3 +781,69 @@ def test_mapping(self):
781781
verify=True,
782782
timeout=DEFAULT_TIMEOUT_SECONDS,
783783
)
784+
785+
def test_recalculate_sso_mappings(self):
786+
client = DescopeClient(
787+
self.dummy_project_id,
788+
self.public_key_dict,
789+
False,
790+
self.dummy_management_key,
791+
)
792+
793+
# Test failed flows
794+
with patch("requests.post") as mock_post:
795+
mock_post.return_value.ok = False
796+
self.assertRaises(
797+
AuthException,
798+
client.mgmt.sso.recalculate_sso_mappings,
799+
"tenant-id",
800+
)
801+
802+
# Test success flow with sso_id
803+
with patch("requests.post") as mock_post:
804+
network_resp = mock.Mock()
805+
network_resp.ok = True
806+
network_resp.json.return_value = {
807+
"affectedUserIds": ["user1", "user2", "user3"]
808+
}
809+
mock_post.return_value = network_resp
810+
client.mgmt.sso.recalculate_sso_mappings("tenant-id", "sso-456")
811+
mock_post.assert_called_with(
812+
f"{common.DEFAULT_BASE_URL}{MgmtV1.sso_recalculate_mappings_path}",
813+
headers={
814+
**common.default_headers,
815+
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
816+
"x-descope-project-id": self.dummy_project_id,
817+
},
818+
params=None,
819+
json={
820+
"tenantId": "tenant-id",
821+
"ssoId": "sso-456",
822+
},
823+
allow_redirects=False,
824+
verify=True,
825+
timeout=DEFAULT_TIMEOUT_SECONDS,
826+
)
827+
828+
# Test success flow without sso_id
829+
with patch("requests.post") as mock_post:
830+
network_resp = mock.Mock()
831+
network_resp.ok = True
832+
network_resp.json.return_value = {"affectedUserIds": ["user1"]}
833+
mock_post.return_value = network_resp
834+
client.mgmt.sso.recalculate_sso_mappings("tenant-id")
835+
mock_post.assert_called_with(
836+
f"{common.DEFAULT_BASE_URL}{MgmtV1.sso_recalculate_mappings_path}",
837+
headers={
838+
**common.default_headers,
839+
"Authorization": f"Bearer {self.dummy_project_id}:{self.dummy_management_key}",
840+
"x-descope-project-id": self.dummy_project_id,
841+
},
842+
params=None,
843+
json={
844+
"tenantId": "tenant-id",
845+
},
846+
allow_redirects=False,
847+
verify=True,
848+
timeout=DEFAULT_TIMEOUT_SECONDS,
849+
)

0 commit comments

Comments
 (0)