Skip to content

Commit 8e5270e

Browse files
committed
feat(IdP): support dynamically loaded IdP plugins
1 parent 423dc85 commit 8e5270e

File tree

3 files changed

+36
-37
lines changed

3 files changed

+36
-37
lines changed

redshift_connector/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
import typing
33

4+
from redshift_connector import plugin
45
from redshift_connector.config import DEFAULT_PROTOCOL_VERSION
56
from redshift_connector.core import BINARY, Connection, Cursor
67
from redshift_connector.error import (

redshift_connector/iam_helper.py

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,7 @@
1111
CredentialsHolder,
1212
)
1313
from redshift_connector.error import InterfaceError
14-
from redshift_connector.plugin import (
15-
AdfsCredentialsProvider,
16-
AzureCredentialsProvider,
17-
BrowserAzureCredentialsProvider,
18-
BrowserSamlCredentialsProvider,
19-
OktaCredentialsProvider,
20-
PingCredentialsProvider,
21-
SamlCredentialsProvider,
22-
)
14+
from redshift_connector.plugin import SamlCredentialsProvider
2315
from redshift_connector.redshift_property import RedshiftProperty
2416

2517
_logger: logging.Logger = logging.getLogger(__name__)
@@ -30,6 +22,14 @@ class SSLMode(Enum):
3022
VERIFY_FULL: str = "verify-full"
3123

3224

25+
def dynamic_plugin_import(name: str):
26+
components = name.split(".")
27+
mod = __import__(components[0])
28+
for comp in components[1:]:
29+
mod = getattr(mod, comp)
30+
return mod
31+
32+
3333
# Helper function to handle IAM connection properties. If any IAM related connection property
3434
# is specified, all other <b>required</b> IAM properties must be specified
3535
def set_iam_properties(
@@ -226,29 +226,27 @@ def set_iam_properties(
226226

227227
# Helper function to create the appropriate credential providers.
228228
def set_iam_credentials(info: RedshiftProperty) -> None:
229-
provider: typing.Optional[typing.Union[SamlCredentialsProvider, AWSCredentialsProvider]] = None
229+
klass: typing.Optional[SamlCredentialsProvider] = None
230+
provider: typing.Union[SamlCredentialsProvider, AWSCredentialsProvider]
230231
# case insensitive comparison
231232
if info.credentials_provider is not None:
232-
if info.credentials_provider.lower() == "OktaCredentialsProvider".lower():
233-
provider = OktaCredentialsProvider()
234-
provider.add_parameter(info)
235-
elif info.credentials_provider.lower() == "AzureCredentialsProvider".lower():
236-
provider = AzureCredentialsProvider()
237-
provider.add_parameter(info)
238-
elif info.credentials_provider.lower() == "BrowserAzureCredentialsProvider".lower():
239-
provider = BrowserAzureCredentialsProvider()
240-
provider.add_parameter(info)
241-
elif info.credentials_provider.lower() == "PingCredentialsProvider".lower():
242-
provider = PingCredentialsProvider()
243-
provider.add_parameter(info)
244-
elif info.credentials_provider.lower() == "BrowserSamlCredentialsProvider".lower():
245-
provider = BrowserSamlCredentialsProvider()
246-
provider.add_parameter(info)
247-
elif info.credentials_provider.lower() == "AdfsCredentialsProvider".lower():
248-
provider = AdfsCredentialsProvider()
249-
provider.add_parameter(info)
250-
else:
251-
raise InterfaceError("Invalid credentials provider" + info.credentials_provider)
233+
try:
234+
klass = dynamic_plugin_import(info.credentials_provider)
235+
provider = klass() # type: ignore
236+
provider.add_parameter(info) # type: ignore
237+
except (AttributeError, ModuleNotFoundError):
238+
_logger.debug("Failed to load user defined plugin: {}".format(info.credentials_provider))
239+
try:
240+
klass = dynamic_plugin_import("redshift_connector.plugin.{}".format(info.credentials_provider))
241+
provider = klass() # type: ignore
242+
provider.add_parameter(info) # type: ignore
243+
except (AttributeError, ModuleNotFoundError):
244+
_logger.debug(
245+
"Failed to load pre-defined IdP plugin from redshift_connector.plugin: {}".format(
246+
info.credentials_provider
247+
)
248+
)
249+
raise InterfaceError("Invalid credentials provider " + info.credentials_provider)
252250
else: # indicates AWS Credentials will be used
253251
provider = AWSCredentialsProvider()
254252
provider.add_parameter(info)
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from .adfs_credentials_provider import *
2-
from .azure_credentials_provider import *
3-
from .browser_azure_credentials_provider import *
4-
from .browser_saml_credentials_provider import *
5-
from .okta_credentials_provider import *
6-
from .ping_credentials_provider import *
7-
from .saml_credentials_provider import *
1+
from .adfs_credentials_provider import AdfsCredentialsProvider
2+
from .azure_credentials_provider import AzureCredentialsProvider
3+
from .browser_azure_credentials_provider import BrowserAzureCredentialsProvider
4+
from .browser_saml_credentials_provider import BrowserSamlCredentialsProvider
5+
from .okta_credentials_provider import OktaCredentialsProvider
6+
from .ping_credentials_provider import PingCredentialsProvider
7+
from .saml_credentials_provider import SamlCredentialsProvider

0 commit comments

Comments
 (0)