diff --git a/catalog-rest-service/src/main/resources/json/schema/metadataIngestion/workflow.json b/catalog-rest-service/src/main/resources/json/schema/metadataIngestion/workflow.json index 2e2d73ccf29..45f17ded454 100644 --- a/catalog-rest-service/src/main/resources/json/schema/metadataIngestion/workflow.json +++ b/catalog-rest-service/src/main/resources/json/schema/metadataIngestion/workflow.json @@ -73,6 +73,26 @@ "additionalProperties": false, "required": ["clientId", "secretKey", "domain"] }, + "customOidcSSOConfig": { + "description": "Custom OIDC SSO client security configs.", + "type": "object", + "properties": { + "clientId": { + "description": "Custom OIDC Client ID.", + "type": "string" + }, + "secretKey": { + "description": "Custom OIDC Client Secret Key.", + "type": "string" + }, + "tokenEndpoint": { + "description": "Custom OIDC token endpoint.", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["clientId", "secretKey", "tokenEndpoint"] + }, "openMetadataServerConfig": { "description": "OpenMetadata Server Connection Details.", "type": "object", @@ -85,7 +105,7 @@ "authProvider": { "description": "OpenMetadata Server Authentication Provider. Make sure configure same auth providers as the one configured on OpenMetadaata server.", "type": "string", - "enum": ["no-auth", "google", "okta", "auth0"], + "enum": ["no-auth", "google", "okta", "auth0", "custom-oidc"], "default": "no-auth" }, "securityConfig": { @@ -99,6 +119,9 @@ }, { "$ref": "#/definitions/auth0SSOConfig" + }, + { + "$ref": "#/definitions/customOidcSSOConfig" } ] }, diff --git a/ingestion/src/metadata/ingestion/ometa/ometa_api.py b/ingestion/src/metadata/ingestion/ometa/ometa_api.py index 4df4ab18ff0..ae681b3b128 100644 --- a/ingestion/src/metadata/ingestion/ometa/ometa_api.py +++ b/ingestion/src/metadata/ingestion/ometa/ometa_api.py @@ -63,6 +63,7 @@ from metadata.ingestion.ometa.mixins.version_mixin import OMetaVersionMixin from metadata.ingestion.ometa.openmetadata_rest import ( Auth0AuthenticationProvider, AzureAuthenticationProvider, + CustomOIDCAuthenticationProvider, GoogleAuthenticationProvider, NoOpAuthenticationProvider, OktaAuthenticationProvider, @@ -157,6 +158,10 @@ class OpenMetadata( self._auth_provider: AuthenticationProvider = ( AzureAuthenticationProvider.create(self.config) ) + elif self.config.authProvider.value == "custom-oidc": + self._auth_provider: AuthenticationProvider = ( + CustomOIDCAuthenticationProvider.create(self.config) + ) else: self._auth_provider: AuthenticationProvider = ( NoOpAuthenticationProvider.create(self.config) diff --git a/ingestion/src/metadata/ingestion/ometa/openmetadata_rest.py b/ingestion/src/metadata/ingestion/ometa/openmetadata_rest.py index c2efe28953b..9929e816788 100644 --- a/ingestion/src/metadata/ingestion/ometa/openmetadata_rest.py +++ b/ingestion/src/metadata/ingestion/ometa/openmetadata_rest.py @@ -17,8 +17,9 @@ import json import logging import sys import traceback -from typing import List +from typing import List, Tuple +import requests from pydantic import BaseModel from metadata.generated.schema.entity.data.dashboard import Dashboard @@ -30,6 +31,7 @@ from metadata.generated.schema.entity.services.databaseService import DatabaseSe from metadata.generated.schema.entity.tags.tagCategory import Tag from metadata.generated.schema.metadataIngestion.workflow import ( Auth0SSOConfig, + CustomOidcSSOConfig, GoogleSSOConfig, OktaSSOConfig, OpenMetadataServerConfig, @@ -323,3 +325,51 @@ class AzureAuthenticationProvider(AuthenticationProvider): def get_access_token(self): self.auth_token() return self.generated_auth_token, self.expiry + + +class CustomOIDCAuthenticationProvider(AuthenticationProvider): + """ + Custom OIDC authentication implementation + + Args: + config (MetadataServerConfig): + + Attributes: + config (MetadataServerConfig) + """ + + def __init__(self, config: OpenMetadataServerConfig) -> None: + self.config = config + self.security_config: CustomOidcSSOConfig = self.config.securityConfig + + self.generated_auth_token = None + self.expiry = None + + @classmethod + def create( + cls, config: OpenMetadataServerConfig + ) -> "CustomOIDCAuthenticationProvider": + return cls(config) + + def auth_token(self) -> None: + data = { + "grant_type": "client_credentials", + "client_id": self.security_config.clientId, + "client_secret": self.security_config.secretKey, + } + response = requests.post( + url=self.security_config.tokenEndpoint, + data=data, + ) + if response.ok: + response_json = response.json() + self.generated_auth_token = response_json["access_token"] + self.expiry = response_json["expires_in"] + else: + raise APIError( + error={"message": response.text}, http_error=response.status_code + ) + + def get_access_token(self) -> Tuple[str, int]: + self.auth_token() + return self.generated_auth_token, self.expiry