Skip to content

Commit c53dacc

Browse files
feat: IdP management updates
- Add new fields for IdPs - Add link from org to IdP + org to/from api funcs - Add switch_active_identity_provider for new action endpoint JIRA: LX-1187 risk: low
1 parent 2626b04 commit c53dacc

File tree

4 files changed

+115
-3
lines changed

4 files changed

+115
-3
lines changed

gooddata-sdk/gooddata_sdk/catalog/organization/entity_model/identity_provider.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from gooddata_api_client.model.json_api_identity_provider_in_attributes import JsonApiIdentityProviderInAttributes
99
from gooddata_api_client.model.json_api_identity_provider_in_document import JsonApiIdentityProviderInDocument
1010
from gooddata_api_client.model.json_api_identity_provider_patch import JsonApiIdentityProviderPatch
11-
from gooddata_api_client.model.json_api_identity_provider_patch_attributes import JsonApiIdentityProviderPatchAttributes
1211
from gooddata_api_client.model.json_api_identity_provider_patch_document import JsonApiIdentityProviderPatchDocument
1312

1413
from gooddata_sdk.catalog.base import Base
@@ -43,6 +42,11 @@ def init(
4342
oauth_client_secret: Optional[str] = None,
4443
oauth_issuer_location: Optional[str] = None,
4544
saml_metadata: Optional[str] = None,
45+
idp_type: Optional[str] = None,
46+
oauth_issuer_id: Optional[str] = None,
47+
oauth_subject_id_claim: Optional[str] = None,
48+
oauth_custom_auth_attributes: Optional[dict[str, str]] = None,
49+
oauth_custom_scopes: Optional[list[str]] = None,
4650
) -> CatalogIdentityProvider:
4751
return cls(
4852
id=identity_provider_id,
@@ -53,6 +57,11 @@ def init(
5357
oauth_client_secret=oauth_client_secret,
5458
oauth_issuer_location=oauth_issuer_location,
5559
saml_metadata=saml_metadata,
60+
idp_type=idp_type,
61+
oauth_issuer_id=oauth_issuer_id,
62+
oauth_subject_id_claim=oauth_subject_id_claim,
63+
oauth_custom_auth_attributes=oauth_custom_auth_attributes,
64+
oauth_custom_scopes=oauth_custom_scopes,
5665
),
5766
)
5867

@@ -66,6 +75,11 @@ def from_api(cls, entity: dict[str, Any]) -> CatalogIdentityProvider:
6675
oauth_client_secret=safeget(ea, ["oauth_client_secret"]),
6776
oauth_issuer_location=safeget(ea, ["oauth_issuer_location"]),
6877
saml_metadata=safeget(ea, ["saml_metadata"]),
78+
idp_type=safeget(ea, ["idp_type"]),
79+
oauth_issuer_id=safeget(ea, ["oauth_issuer_id"]),
80+
oauth_subject_id_claim=safeget(ea, ["oauth_subject_id_claim"]),
81+
oauth_custom_auth_attributes=safeget(ea, ["oauth_custom_auth_attributes"]),
82+
oauth_custom_scopes=safeget(ea, ["oauth_custom_scopes"]),
6983
)
7084
return cls(
7185
id=entity["id"],
@@ -76,7 +90,7 @@ def from_api(cls, entity: dict[str, Any]) -> CatalogIdentityProvider:
7690
def to_api_patch(cls, identity_provider_id: str, attributes: dict) -> JsonApiIdentityProviderPatchDocument:
7791
return JsonApiIdentityProviderPatchDocument(
7892
data=JsonApiIdentityProviderPatch(
79-
id=identity_provider_id, attributes=JsonApiIdentityProviderPatchAttributes(**attributes)
93+
id=identity_provider_id, attributes=JsonApiIdentityProviderInAttributes(**attributes)
8094
)
8195
)
8296

@@ -89,6 +103,11 @@ class CatalogIdentityProviderAttributes(Base):
89103
oauth_client_secret: Optional[str] = None
90104
oauth_issuer_location: Optional[str] = None
91105
saml_metadata: Optional[str] = None
106+
idp_type: Optional[str] = None
107+
oauth_issuer_id: Optional[str] = None
108+
oauth_subject_id_claim: Optional[str] = None
109+
oauth_custom_auth_attributes: Optional[dict[str, str]] = None
110+
oauth_custom_scopes: Optional[list[str]] = None
92111

93112
@staticmethod
94113
def client_class() -> type[JsonApiIdentityProviderInAttributes]:

gooddata-sdk/gooddata_sdk/catalog/organization/entity_model/organization.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
# (C) 2022 GoodData Corporation
22
from __future__ import annotations
33

4-
from typing import Optional
4+
from typing import Any, Optional
55

66
import attr
7+
from gooddata_api_client.model.json_api_identity_provider_to_one_linkage import JsonApiIdentityProviderToOneLinkage
78
from gooddata_api_client.model.json_api_organization_in import JsonApiOrganizationIn
89
from gooddata_api_client.model.json_api_organization_in_attributes import JsonApiOrganizationInAttributes
910
from gooddata_api_client.model.json_api_organization_in_document import JsonApiOrganizationInDocument
11+
from gooddata_api_client.model.json_api_organization_in_relationships import JsonApiOrganizationInRelationships
12+
from gooddata_api_client.model.json_api_organization_in_relationships_identity_provider import (
13+
JsonApiOrganizationInRelationshipsIdentityProvider,
14+
)
1015

1116
from gooddata_sdk.catalog.base import Base
17+
from gooddata_sdk.utils import safeget
1218

1319

1420
@attr.s(auto_attribs=True, kw_only=True)
@@ -30,11 +36,49 @@ def to_api(self, oauth_client_secret: Optional[str] = None) -> JsonApiOrganizati
3036
class CatalogOrganization(Base):
3137
id: str
3238
attributes: CatalogOrganizationAttributes
39+
identity_provider_id: Optional[str] = None
3340

3441
@staticmethod
3542
def client_class() -> type[JsonApiOrganizationIn]:
3643
return JsonApiOrganizationIn
3744

45+
@classmethod
46+
def from_api(cls, entity: dict[str, Any]) -> CatalogOrganization:
47+
ea = entity.get("attributes", {})
48+
er = entity.get("relationships", {})
49+
50+
attributes = CatalogOrganizationAttributes(
51+
name=safeget(ea, ["name"]),
52+
hostname=safeget(ea, ["hostname"]),
53+
allowed_origins=safeget(ea, ["allowed_origins"]),
54+
oauth_issuer_location=safeget(ea, ["oauth_issuer_location"]),
55+
oauth_client_id=safeget(ea, ["oauth_client_id"]),
56+
)
57+
58+
identity_provider_id = safeget(er, ["identityProvider", "data", "id"])
59+
60+
return cls(
61+
id=entity["id"],
62+
attributes=attributes,
63+
identity_provider_id=identity_provider_id,
64+
)
65+
66+
def to_api(self) -> JsonApiOrganizationIn:
67+
kwargs = {}
68+
if self.identity_provider_id:
69+
kwargs["relationships"] = JsonApiOrganizationInRelationships(
70+
identity_provider=JsonApiOrganizationInRelationshipsIdentityProvider(
71+
data=JsonApiIdentityProviderToOneLinkage(id=self.identity_provider_id, type="identityProvider")
72+
)
73+
)
74+
75+
return JsonApiOrganizationIn(
76+
id=self.id,
77+
type="organization",
78+
attributes=self.attributes.to_api(),
79+
**kwargs,
80+
)
81+
3882

3983
@attr.s(auto_attribs=True, kw_only=True)
4084
class CatalogOrganizationAttributes(Base):

gooddata-sdk/gooddata_sdk/catalog/organization/layout/identity_provider.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ class CatalogDeclarativeIdentityProvider(Base):
1717
oauth_client_secret: Optional[str] = None
1818
oauth_issuer_location: Optional[str] = None
1919
saml_metadata: Optional[str] = None
20+
idp_type: Optional[str] = None
21+
oauth_issuer_id: Optional[str] = None
22+
oauth_subject_id_claim: Optional[str] = None
23+
oauth_custom_auth_attributes: Optional[dict[str, str]] = None
24+
oauth_custom_scopes: Optional[list[str]] = None
2025

2126
@staticmethod
2227
def client_class() -> builtins.type[DeclarativeIdentityProvider]:

gooddata-sdk/gooddata_sdk/catalog/organization/service.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import annotations
33

44
import functools
5+
import json
56
from typing import Any, Optional
67

78
from gooddata_api_client.exceptions import NotFoundException
@@ -747,3 +748,46 @@ def put_declarative_export_templates(self, export_templates: list[CatalogDeclara
747748
self._layout_api.set_export_templates(
748749
declarative_export_templates=DeclarativeExportTemplates(export_templates=api_export_templates)
749750
)
751+
752+
def switch_active_identity_provider(self, identity_provider_id: str) -> None:
753+
"""Switch the active identity provider for the organization.
754+
755+
Args:
756+
identity_provider_id (str):
757+
Identity provider identification string e.g. "auth0"
758+
759+
Returns:
760+
None
761+
762+
Raises:
763+
ValueError:
764+
Identity provider does not exist or operation failed.
765+
"""
766+
try:
767+
# Prepare the request payload
768+
request_data = {"idpId": identity_provider_id}
769+
770+
# Make the request using the client's POST request method
771+
response = self._client._do_post_request(
772+
data=json.dumps(request_data).encode("utf-8"),
773+
endpoint="api/v1/actions/organization/switchActiveIdentityProvider",
774+
content_type="application/json",
775+
)
776+
777+
# Check for successful response
778+
if response.status_code not in (200, 204):
779+
if response.status_code == 404:
780+
raise ValueError(
781+
f"Cannot switch to identity provider {identity_provider_id}. "
782+
f"This identity provider does not exist."
783+
)
784+
else:
785+
raise ValueError(
786+
f"Failed to switch active identity provider. "
787+
f"Status code: {response.status_code}, Response: {response.text}"
788+
)
789+
790+
except Exception as e:
791+
if isinstance(e, ValueError):
792+
raise
793+
raise ValueError(f"Error switching active identity provider: {str(e)}")

0 commit comments

Comments
 (0)