Skip to content

Commit 95bade5

Browse files
dorshaclaude
andauthored
feat: add FGA mappings support to SSO tenant settings (#1539)
Adds FGAGroupMapping and FGAGroupMappingRelation types and wires fgaMappings (plus configFGATenantIDResourcePrefix/Suffix for SAML variants) into the OIDC/SAML/SAML-by-metadata configure requests, matching the management.proto contract. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e0205bf commit 95bade5

3 files changed

Lines changed: 346 additions & 1 deletion

File tree

descope/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
)
3838
from descope.management.sso_settings import (
3939
AttributeMapping,
40+
FGAGroupMapping,
41+
FGAGroupMappingRelation,
4042
OIDCAttributeMapping,
4143
RoleMapping,
4244
SSOOIDCSettings,
@@ -85,6 +87,8 @@
8587
"SAMLIDPGroupsMappingInfo",
8688
"SAMLIDPRoleGroupMappingInfo",
8789
"AttributeMapping",
90+
"FGAGroupMapping",
91+
"FGAGroupMappingRelation",
8892
"OIDCAttributeMapping",
8993
"RoleMapping",
9094
"SSOOIDCSettings",

descope/management/sso_settings.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Optional
1+
from typing import Dict, List, Optional
22

33
from descope._http_base import HTTPBase
44
from descope.management.common import MgmtV1
@@ -12,6 +12,22 @@ def __init__(self, groups: List[str], role_name: str):
1212
self.role_name = role_name
1313

1414

15+
class FGAGroupMappingRelation:
16+
"""A single FGA relation that maps an IDP group to an FGA resource/relation."""
17+
18+
def __init__(self, resource: str, relation_definition: str, namespace: str):
19+
self.resource = resource
20+
self.relation_definition = relation_definition
21+
self.namespace = namespace
22+
23+
24+
class FGAGroupMapping:
25+
"""A list of FGA relations to apply for an IDP group."""
26+
27+
def __init__(self, relations: Optional[List[FGAGroupMappingRelation]] = None):
28+
self.relations = relations
29+
30+
1531
class AttributeMapping:
1632
"""Map Descope user attributes to IDP user attributes"""
1733

@@ -93,6 +109,7 @@ def __init__(
93109
grant_type: Optional[str] = None,
94110
issuer: Optional[str] = None,
95111
groups_priority: Optional[List[str]] = None, # list of group names in priority order (first = highest priority)
112+
fga_mappings: Optional[Dict[str, FGAGroupMapping]] = None, # map of IDP group name -> FGA relations
96113
):
97114
self.name = name
98115
self.client_id = client_id
@@ -110,6 +127,7 @@ def __init__(
110127
self.grant_type = grant_type
111128
self.issuer = issuer
112129
self.groups_priority = groups_priority
130+
self.fga_mappings = fga_mappings
113131

114132

115133
class SSOSAMLSettings:
@@ -127,6 +145,9 @@ def __init__(
127145
default_sso_roles: Optional[List[str]] = None,
128146
idp_additional_certs: Optional[List[str]] = None,
129147
groups_priority: Optional[List[str]] = None, # list of group names in priority order (first = highest priority)
148+
fga_mappings: Optional[Dict[str, FGAGroupMapping]] = None, # map of IDP group name -> FGA relations
149+
config_fga_tenant_id_resource_prefix: Optional[str] = None,
150+
config_fga_tenant_id_resource_suffix: Optional[str] = None,
130151
# NOTICE - the following fields should be overridden only in case of SSO migration, otherwise, do not modify these fields
131152
sp_acs_url: Optional[str] = None,
132153
sp_entity_id: Optional[str] = None,
@@ -141,6 +162,9 @@ def __init__(
141162
self.sp_acs_url = sp_acs_url
142163
self.sp_entity_id = sp_entity_id
143164
self.groups_priority = groups_priority
165+
self.fga_mappings = fga_mappings
166+
self.config_fga_tenant_id_resource_prefix = config_fga_tenant_id_resource_prefix
167+
self.config_fga_tenant_id_resource_suffix = config_fga_tenant_id_resource_suffix
144168

145169

146170
class SSOSAMLSettingsByMetadata:
@@ -155,6 +179,9 @@ def __init__(
155179
role_mappings: Optional[List[RoleMapping]] = None,
156180
default_sso_roles: Optional[List[str]] = None,
157181
groups_priority: Optional[List[str]] = None, # list of group names in priority order (first = highest priority)
182+
fga_mappings: Optional[Dict[str, FGAGroupMapping]] = None, # map of IDP group name -> FGA relations
183+
config_fga_tenant_id_resource_prefix: Optional[str] = None,
184+
config_fga_tenant_id_resource_suffix: Optional[str] = None,
158185
# NOTICE - the following fields should be overridden only in case of SSO migration, otherwise, do not modify these fields
159186
sp_acs_url: Optional[str] = None,
160187
sp_entity_id: Optional[str] = None,
@@ -166,6 +193,9 @@ def __init__(
166193
self.sp_acs_url = sp_acs_url
167194
self.sp_entity_id = sp_entity_id
168195
self.groups_priority = groups_priority
196+
self.fga_mappings = fga_mappings
197+
self.config_fga_tenant_id_resource_prefix = config_fga_tenant_id_resource_prefix
198+
self.config_fga_tenant_id_resource_suffix = config_fga_tenant_id_resource_suffix
169199

170200

171201
class SSOSettings(HTTPBase):
@@ -497,6 +527,27 @@ def _attribute_mapping_to_dict(
497527
"customAttributes": attribute_mapping.custom_attributes,
498528
}
499529

530+
@staticmethod
531+
def _fga_mappings_to_dict(
532+
fga_mappings: Optional[Dict[str, FGAGroupMapping]],
533+
) -> Optional[dict]:
534+
if fga_mappings is None:
535+
return None
536+
result: dict = {}
537+
for group_name, mapping in fga_mappings.items():
538+
relations = []
539+
if mapping is not None and mapping.relations:
540+
for relation in mapping.relations:
541+
relations.append(
542+
{
543+
"resource": relation.resource,
544+
"relationDefinition": relation.relation_definition,
545+
"namespace": relation.namespace,
546+
}
547+
)
548+
result[group_name] = {"relations": relations}
549+
return result
550+
500551
@staticmethod
501552
def _compose_configure_oidc_settings_body(
502553
tenant_id: str,
@@ -538,6 +589,7 @@ def _compose_configure_oidc_settings_body(
538589
"grantType": settings.grant_type,
539590
"issuer": settings.issuer,
540591
"groupsPriority": settings.groups_priority,
592+
"fgaMappings": SSOSettings._fga_mappings_to_dict(settings.fga_mappings),
541593
},
542594
"domains": domains,
543595
}
@@ -566,6 +618,9 @@ def _compose_configure_saml_settings_body(
566618
"roleMappings": SSOSettings._role_mapping_to_dict(settings.role_mappings),
567619
"defaultSSORoles": settings.default_sso_roles,
568620
"groupsPriority": settings.groups_priority,
621+
"fgaMappings": SSOSettings._fga_mappings_to_dict(settings.fga_mappings),
622+
"configFGATenantIDResourcePrefix": settings.config_fga_tenant_id_resource_prefix,
623+
"configFGATenantIDResourceSuffix": settings.config_fga_tenant_id_resource_suffix,
569624
},
570625
"redirectUrl": redirect_url,
571626
"domains": domains,
@@ -592,6 +647,9 @@ def _compose_configure_saml_settings_by_metadata_body(
592647
"roleMappings": SSOSettings._role_mapping_to_dict(settings.role_mappings),
593648
"defaultSSORoles": settings.default_sso_roles,
594649
"groupsPriority": settings.groups_priority,
650+
"fgaMappings": SSOSettings._fga_mappings_to_dict(settings.fga_mappings),
651+
"configFGATenantIDResourcePrefix": settings.config_fga_tenant_id_resource_prefix,
652+
"configFGATenantIDResourceSuffix": settings.config_fga_tenant_id_resource_suffix,
595653
},
596654
"redirectUrl": redirect_url,
597655
"domains": domains,

0 commit comments

Comments
 (0)