Skip to content

Commit 4879db7

Browse files
feat: IdP Management
JIRA: LX-451, LX-404 risk: low
1 parent 33c3e67 commit 4879db7

File tree

9 files changed

+2463
-6
lines changed

9 files changed

+2463
-6
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# (C) 2024 GoodData Corporation
2+
from __future__ import annotations
3+
4+
from typing import Any, Optional
5+
6+
import attr
7+
from gooddata_api_client.model.json_api_identity_provider_in import JsonApiIdentityProviderIn
8+
from gooddata_api_client.model.json_api_identity_provider_in_attributes import JsonApiIdentityProviderInAttributes
9+
from gooddata_api_client.model.json_api_identity_provider_in_document import JsonApiIdentityProviderInDocument
10+
11+
from gooddata_sdk.catalog.base import Base
12+
from gooddata_sdk.utils import safeget
13+
14+
15+
@attr.s(auto_attribs=True, kw_only=True)
16+
class CatalogIdentityProviderDocument(Base):
17+
data: CatalogIdentityProvider
18+
19+
@staticmethod
20+
def client_class() -> type[JsonApiIdentityProviderInDocument]:
21+
return JsonApiIdentityProviderInDocument
22+
23+
24+
@attr.s(auto_attribs=True, kw_only=True)
25+
class CatalogIdentityProvider(Base):
26+
id: str
27+
attributes: Optional[CatalogIdentityProviderAttributes] = None
28+
29+
@staticmethod
30+
def client_class() -> type[JsonApiIdentityProviderIn]:
31+
return JsonApiIdentityProviderIn
32+
33+
@classmethod
34+
def init(
35+
cls,
36+
identity_provider_id: str,
37+
custom_claim_mapping: Optional[dict[str, str]] = None,
38+
identifiers: Optional[list[str]] = None,
39+
oauth_client_id: Optional[str] = None,
40+
oauth_client_secret: Optional[str] = None,
41+
oauth_issuer_id: Optional[str] = None,
42+
oauth_issuer_location: Optional[str] = None,
43+
saml_metadata: Optional[str] = None,
44+
) -> CatalogIdentityProvider:
45+
return cls(
46+
id=identity_provider_id,
47+
attributes=CatalogIdentityProviderAttributes(
48+
custom_claim_mapping=custom_claim_mapping,
49+
identifiers=identifiers,
50+
oauth_client_id=oauth_client_id,
51+
oauth_client_secret=oauth_client_secret,
52+
oauth_issuer_id=oauth_issuer_id,
53+
oauth_issuer_location=oauth_issuer_location,
54+
saml_metadata=saml_metadata,
55+
),
56+
)
57+
58+
@classmethod
59+
def from_api(cls, entity: dict[str, Any]) -> CatalogIdentityProvider:
60+
ea = entity["attributes"]
61+
attr = CatalogIdentityProviderAttributes(
62+
custom_claim_mapping=safeget(ea, ["custom_claim_mapping"]),
63+
identifiers=safeget(ea, ["identifiers"]),
64+
oauth_client_id=safeget(ea, ["oauth_client_id"]),
65+
oauth_client_secret=safeget(ea, ["oauth_client_secret"]),
66+
oauth_issuer_id=safeget(ea, ["oauth_issuer_id"]),
67+
oauth_issuer_location=safeget(ea, ["oauth_issuer_location"]),
68+
saml_metadata=safeget(ea, ["saml_metadata"]),
69+
)
70+
return cls(
71+
id=entity["id"],
72+
attributes=attr,
73+
)
74+
75+
76+
@attr.s(auto_attribs=True, kw_only=True)
77+
class CatalogIdentityProviderAttributes(Base):
78+
custom_claim_mapping: Optional[dict[str, str]] = None
79+
identifiers: Optional[list[str]] = None
80+
oauth_client_id: Optional[str] = None
81+
oauth_client_secret: Optional[str] = None
82+
oauth_issuer_id: Optional[str] = None
83+
oauth_issuer_location: Optional[str] = None
84+
saml_metadata: Optional[str] = None
85+
86+
@staticmethod
87+
def client_class() -> type[JsonApiIdentityProviderInAttributes]:
88+
return JsonApiIdentityProviderInAttributes
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# (C) 2024 GoodData Corporation
2+
import builtins
3+
from typing import Optional
4+
5+
import attr
6+
from gooddata_api_client.model.declarative_identity_provider import DeclarativeIdentityProvider
7+
8+
from gooddata_sdk.catalog.base import Base
9+
10+
11+
@attr.s(auto_attribs=True, kw_only=True)
12+
class CatalogDeclarativeIdentityProvider(Base):
13+
id: str
14+
custom_claim_mapping: Optional[dict[str, str]] = None
15+
identifiers: Optional[list[str]] = None
16+
oauth_client_id: Optional[str] = None
17+
oauth_client_secret: Optional[str] = None
18+
oauth_issuer_id: Optional[str] = None
19+
oauth_issuer_location: Optional[str] = None
20+
saml_metadata: Optional[str] = None
21+
22+
@staticmethod
23+
def client_class() -> builtins.type[DeclarativeIdentityProvider]:
24+
return DeclarativeIdentityProvider

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

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@
77
from gooddata_api_client.exceptions import NotFoundException
88
from gooddata_api_client.model.declarative_notification_channels import DeclarativeNotificationChannels
99
from gooddata_api_client.model.json_api_csp_directive_in_document import JsonApiCspDirectiveInDocument
10+
from gooddata_api_client.model.json_api_identity_provider_in_document import JsonApiIdentityProviderInDocument
1011
from gooddata_api_client.model.json_api_organization_setting_in_document import JsonApiOrganizationSettingInDocument
1112

1213
from gooddata_sdk.catalog.catalog_service_base import CatalogServiceBase
1314
from gooddata_sdk.catalog.organization.entity_model.directive import CatalogCspDirective
15+
from gooddata_sdk.catalog.organization.entity_model.identity_provider import CatalogIdentityProvider
1416
from gooddata_sdk.catalog.organization.entity_model.jwk import CatalogJwk, CatalogJwkDocument
1517
from gooddata_sdk.catalog.organization.entity_model.organization import CatalogOrganizationDocument
1618
from gooddata_sdk.catalog.organization.entity_model.setting import CatalogOrganizationSetting
19+
from gooddata_sdk.catalog.organization.layout.identity_provider import CatalogDeclarativeIdentityProvider
1720
from gooddata_sdk.catalog.organization.layout.notification_channel import CatalogDeclarativeNotificationChannel
1821
from gooddata_sdk.client import GoodDataApiClient
19-
from gooddata_sdk.utils import load_all_entities
22+
from gooddata_sdk.utils import load_all_entities, load_all_entities_dict
2023

2124

2225
class CatalogOrganizationService(CatalogServiceBase):
@@ -188,7 +191,7 @@ def create_organization_setting(self, organization_setting: CatalogOrganizationS
188191
189192
Args:
190193
organization_setting (CatalogOrganizationSettings):
191-
A catalog organization setting an object to be created.
194+
A catalog organization setting object to be created.
192195
193196
Returns:
194197
None
@@ -225,7 +228,7 @@ def update_organization_setting(self, organization_setting: CatalogOrganizationS
225228
226229
Args:
227230
organization_setting (CatalogOrganizationSettings):
228-
A catalog organization setting an object to be updated.
231+
A catalog organization setting object to be updated.
229232
230233
Returns:
231234
None
@@ -249,7 +252,7 @@ def list_csp_directives(self) -> list[CatalogCspDirective]:
249252
"""Returns a list of all csp directives in the current organization.
250253
251254
Returns:
252-
list[CatalogOrganizationSettings]:
255+
list[CatalogCspDirective]:
253256
List of csp directives in the current organization.
254257
"""
255258
get_csp_directives = functools.partial(
@@ -277,7 +280,7 @@ def create_csp_directive(self, csp_directive: CatalogCspDirective) -> None:
277280
278281
Args:
279282
csp_directive (CatalogCspDirective):
280-
A catalog csp directive an object to be created.
283+
A catalog csp directive object to be created.
281284
282285
Returns:
283286
None
@@ -309,7 +312,7 @@ def update_csp_directive(self, csp_directive: CatalogCspDirective) -> None:
309312
310313
Args:
311314
csp_directive (CatalogCspDirective):
312-
A catalog csp directive an object to be updated.
315+
A catalog csp directive object to be updated.
313316
314317
Returns:
315318
None
@@ -324,6 +327,95 @@ def update_csp_directive(self, csp_directive: CatalogCspDirective) -> None:
324327
except NotFoundException:
325328
raise ValueError(f"Can not update {csp_directive.id} csp directive. This csp directive does not exist.")
326329

330+
def list_identity_providers(self) -> list[CatalogIdentityProvider]:
331+
"""Returns a list of all identity providers in the current organization.
332+
333+
Returns:
334+
list[CatalogIdentityProvider]:
335+
List of identity providers in the current organization.
336+
"""
337+
get_identity_providers = functools.partial(
338+
self._entities_api.get_all_entities_identity_providers,
339+
_check_return_type=False,
340+
)
341+
identity_providers = load_all_entities_dict(get_identity_providers, camel_case=False)
342+
return [
343+
CatalogIdentityProvider.from_dict(identity_provider, camel_case=False)
344+
for identity_provider in identity_providers["data"]
345+
]
346+
347+
def get_identity_provider(self, identity_provider_id: str) -> CatalogIdentityProvider:
348+
"""Get an individual identity provider.
349+
350+
Args:
351+
identity_provider_id (str):
352+
Identity provider identification string e.g. "demo"
353+
354+
Returns:
355+
CatalogIdentityProvider:
356+
Catalog identity provider object containing structure of the identity provider.
357+
"""
358+
identity_provider_api = self._entities_api.get_entity_identity_providers(id=identity_provider_id).data
359+
return CatalogIdentityProvider.from_api(identity_provider_api)
360+
361+
def create_identity_provider(self, identity_provider: CatalogIdentityProvider) -> None:
362+
"""Create a new identity provider.
363+
364+
Args:
365+
identity_provider (CatalogIdentityProvider):
366+
A catalog identity provider object to be created.
367+
368+
Returns:
369+
None
370+
"""
371+
identity_provider_document = JsonApiIdentityProviderInDocument(data=identity_provider.to_api())
372+
self._entities_api.create_entity_identity_providers(
373+
json_api_identity_provider_in_document=identity_provider_document
374+
)
375+
376+
def delete_identity_provider(self, identity_provider_id: str) -> None:
377+
"""Delete an identity provider.
378+
379+
Args:
380+
identity_provider_id (str):
381+
Identity provider identification string e.g. "demo"
382+
383+
Returns:
384+
None
385+
386+
Raises:
387+
ValueError:
388+
Identity provider does not exist.
389+
"""
390+
try:
391+
self._entities_api.delete_entity_identity_providers(identity_provider_id)
392+
except NotFoundException:
393+
raise ValueError(
394+
f"Can not delete {identity_provider_id} identity provider. " f"This identity provider does not exist."
395+
)
396+
397+
def update_identity_provider(self, identity_provider: CatalogIdentityProvider) -> None:
398+
"""Update an identity provider.
399+
400+
Args:
401+
identity_provider (CatalogIdentityProvider):
402+
A catalog identity provider object to be updated.
403+
404+
Returns:
405+
None
406+
407+
Raises:
408+
ValueError:
409+
Identity provider does not exist.
410+
"""
411+
try:
412+
identity_provider_document = JsonApiIdentityProviderInDocument(data=identity_provider.to_api())
413+
self._entities_api.update_entity_identity_providers(identity_provider.id, identity_provider_document)
414+
except NotFoundException:
415+
raise ValueError(
416+
f"Can not update {identity_provider.id} identity provider. " f"This identity provider does not exist."
417+
)
418+
327419
# Layout APIs
328420

329421
def get_declarative_notification_channels(self) -> list[CatalogDeclarativeNotificationChannel]:
@@ -354,3 +446,29 @@ def put_declarative_notification_channels(
354446
"""
355447
api_ncs = [nc.to_api() for nc in notification_channels]
356448
self._layout_api.set_notification_channels(DeclarativeNotificationChannels(notification_channels=api_ncs))
449+
450+
def get_declarative_identity_providers(self) -> list[CatalogDeclarativeIdentityProvider]:
451+
"""
452+
Get all declarative identity providers in the current organization.
453+
454+
Returns:
455+
list[CatalogDeclarativeIdentityProvider]:
456+
List of declarative identity providers.
457+
"""
458+
return [
459+
CatalogDeclarativeIdentityProvider.from_api(idp) for idp in self._layout_api.get_identity_providers_layout()
460+
]
461+
462+
def put_declarative_identity_providers(self, identity_providers: list[CatalogDeclarativeIdentityProvider]) -> None:
463+
"""
464+
Put declarative identity providers in the current organization.
465+
466+
Args:
467+
identity_providers (list[CatalogDeclarativeIdentityProvider]):
468+
List of declarative identity providers.
469+
470+
Returns:
471+
None
472+
"""
473+
api_idps = [idp.to_api() for idp in identity_providers]
474+
self._layout_api.set_identity_providers(declarative_identity_provider=api_idps)

0 commit comments

Comments
 (0)