Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support SSO provider config from infrahub.toml #4749

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 48 additions & 6 deletions backend/infrahub/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,14 @@ class SecurityOIDCProvider2(SecurityOIDCSettings):
model_config = SettingsConfigDict(env_prefix="INFRAHUB_OIDC_PROVIDER2_")


class SecurityOIDCProviderSettings(BaseModel):
"""This class is meant to facilitate configuration of OIDC providers when loading configuration from a infrahub.toml file."""

google: Optional[SecurityOIDCGoogle] = Field(default=None)
provider1: Optional[SecurityOIDCProvider1] = Field(default=None)
provider2: Optional[SecurityOIDCProvider2] = Field(default=None)


class SecurityOAuth2BaseSettings(BaseSettings):
"""Baseclass for typing"""

Expand Down Expand Up @@ -490,6 +498,14 @@ class SecurityOAuth2Google(SecurityOAuth2Settings):
display_label: str = Field(default="Google")


class SecurityOAuth2ProviderSettings(BaseModel):
"""This class is meant to facilitate configuration of OAuth2 providers when loading configuration from a infrahub.toml file."""

google: Optional[SecurityOAuth2Google] = Field(default=None)
provider1: Optional[SecurityOAuth2Provider1] = Field(default=None)
provider2: Optional[SecurityOAuth2Provider2] = Field(default=None)


class MiscellaneousSettings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="INFRAHUB_MISC_")
print_query_details: bool = False
Expand Down Expand Up @@ -535,7 +551,9 @@ class SecuritySettings(BaseSettings):
default_factory=generate_uuid, description="The secret key used to validate authentication tokens"
)
oauth2_providers: list[Oauth2Provider] = Field(default_factory=list, description="The selected OAuth2 providers")
oauth2_provider_settings: SecurityOAuth2ProviderSettings = Field(default_factory=SecurityOAuth2ProviderSettings)
oidc_providers: list[OIDCProvider] = Field(default_factory=list, description="The selected OIDC providers")
oidc_provider_settings: SecurityOIDCProviderSettings = Field(default_factory=SecurityOIDCProviderSettings)
_oauth2_settings: dict[str, SecurityOAuth2Settings] = PrivateAttr(default_factory=dict)
_oidc_settings: dict[str, SecurityOIDCSettings] = PrivateAttr(default_factory=dict)

Expand All @@ -547,9 +565,21 @@ def check_oauth2_provider_settings(self) -> Self:
Oauth2Provider.GOOGLE: SecurityOAuth2Google,
}
for oauth2_provider in self.oauth2_providers:
provider = mapped_providers[oauth2_provider]()
if isinstance(provider, SecurityOAuth2Settings):
self._oauth2_settings[oauth2_provider.value] = provider
match oauth2_provider:
case Oauth2Provider.GOOGLE:
if self.oauth2_provider_settings.google:
self._oauth2_settings[oauth2_provider.value] = self.oauth2_provider_settings.google
case Oauth2Provider.PROVIDER1:
if self.oauth2_provider_settings.provider1:
self._oauth2_settings[oauth2_provider.value] = self.oauth2_provider_settings.provider1
case Oauth2Provider.PROVIDER2:
if self.oauth2_provider_settings.provider2:
self._oauth2_settings[oauth2_provider.value] = self.oauth2_provider_settings.provider2

if oauth2_provider.value not in self._oauth2_settings:
provider = mapped_providers[oauth2_provider]()
if isinstance(provider, SecurityOAuth2Settings):
self._oauth2_settings[oauth2_provider.value] = provider

return self

Expand All @@ -561,9 +591,21 @@ def check_oidc_provider_settings(self) -> Self:
OIDCProvider.PROVIDER2: SecurityOIDCProvider2,
}
for oidc_provider in self.oidc_providers:
provider = mapped_providers[oidc_provider]()
if isinstance(provider, SecurityOIDCSettings):
self._oidc_settings[oidc_provider.value] = provider
match oidc_provider:
case OIDCProvider.GOOGLE:
if self.oidc_provider_settings.google:
self._oidc_settings[oidc_provider.value] = self.oidc_provider_settings.google
case OIDCProvider.PROVIDER1:
if self.oidc_provider_settings.provider1:
self._oidc_settings[oidc_provider.value] = self.oidc_provider_settings.provider1
case OIDCProvider.PROVIDER2:
if self.oidc_provider_settings.provider2:
self._oidc_settings[oidc_provider.value] = self.oidc_provider_settings.provider2

if oidc_provider.value not in self._oidc_settings:
provider = mapped_providers[oidc_provider]()
if isinstance(provider, SecurityOIDCSettings):
self._oidc_settings[oidc_provider.value] = provider

return self

Expand Down
154 changes: 126 additions & 28 deletions docs/docs/guides/sso.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
---
title: Configuring Single sign-on
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Configuring Single sign-on

In Infrahub you can configure SSO using either Open ID Connect (OIDC) or can use OAuth2.
Expand Down Expand Up @@ -40,31 +43,80 @@ Aside from the display label and icon all the other entries will be provided by

An example of what the configuration could look like:

```bash
export INFRAHUB_OAUTH2_PROVIDER1_CLIENT_ID=infrahub-sso
export INFRAHUB_OAUTH2_PROVIDER1_CLIENT_SECRET=edPf4IaquQaqns7t3s95mLhKKYdwL1up
export INFRAHUB_OAUTH2_PROVIDER1_AUTHORIZATION_URL=http://localhost:8180/realms/infrahub/protocol/openid-connect/auth
export INFRAHUB_OAUTH2_PROVIDER1_TOKEN_URL=http://localhost:8180/realms/infrahub/protocol/openid-connect/token
export INFRAHUB_OAUTH2_PROVIDER1_USERINFO_URL=http://localhost:8180/realms/infrahub/protocol/openid-connect/userinfo
export INFRAHUB_OAUTH2_PROVIDER1_DISPLAY_LABEL="Internal Server (Keycloak)"
export INFRAHUB_OAUTH2_PROVIDER1_ICON="mdi:security-lock-outline"
```
<Tabs groupId="provider1-configuration">
<TabItem value="Environment Variables" default>

```bash
export INFRAHUB_OAUTH2_PROVIDER1_CLIENT_ID=infrahub-sso
export INFRAHUB_OAUTH2_PROVIDER1_CLIENT_SECRET=edPf4IaquQaqns7t3s95mLhKKYdwL1up
export INFRAHUB_OAUTH2_PROVIDER1_AUTHORIZATION_URL=http://localhost:8180/realms/infrahub/protocol/openid-connect/auth
export INFRAHUB_OAUTH2_PROVIDER1_TOKEN_URL=http://localhost:8180/realms/infrahub/protocol/openid-connect/token
export INFRAHUB_OAUTH2_PROVIDER1_USERINFO_URL=http://localhost:8180/realms/infrahub/protocol/openid-connect/userinfo
export INFRAHUB_OAUTH2_PROVIDER1_DISPLAY_LABEL="Internal Server (Keycloak)"
export INFRAHUB_OAUTH2_PROVIDER1_ICON="mdi:security-lock-outline"
```

</TabItem>
<TabItem value="infrahub.toml" default>

```toml
[security.oauth2_provider_settings.provider1]
client_id = "infrahub-sso"
client_secret = "edPf4IaquQaqns7t3s95mLhKKYdwL1up"
authorization_url = "http://localhost:8180/realms/infrahub/protocol/openid-connect/auth"
token_url = "http://localhost:8180/realms/infrahub/protocol/openid-connect/token"
userinfo_url = "http://localhost:8180/realms/infrahub/protocol/openid-connect/userinfo"
scopes = ["openid", "profile", "email"]
display_label = "Internal Server (Keycloak)"
icon = "mdi:security-lock-outline"
```

</TabItem>
</Tabs>

This could be the configuration of a Keycloak provider, please refer to the documentation of your intended provider for guides on how to create a client and access the required information.

## Activating the OAuth2 provider

In order to activate the above provider we need to add it to the list of active OAuth2 providers.

```bash
export INFRAHUB_SECURITY_OAUTH2_PROVIDERS='["provider1"]'
```
<Tabs groupId="provider1-configuration">
<TabItem value="Environment Variables" default>

```bash
export INFRAHUB_SECURITY_OAUTH2_PROVIDERS='["provider1"]'
```

</TabItem>
<TabItem value="infrahub.toml" default>

```toml
[security]
oauth2_providers = ["provider1"]
```

</TabItem>
</Tabs>

Alternatively if you are setting up multiple providers each with their different settings:

```bash
export INFRAHUB_SECURITY_OAUTH2_PROVIDERS='["provider1","provider2"]'
```
<Tabs groupId="provider1-configuration">
<TabItem value="Environment Variables" default>

```bash
export INFRAHUB_SECURITY_OAUTH2_PROVIDERS='["provider1","provider2"]'
```

</TabItem>
<TabItem value="infrahub.toml" default>

```toml
[security]
oauth2_providers = ["provider1", "provider2"]
```

</TabItem>
</Tabs>

## Setting up OIDC in Infrahub

Expand All @@ -89,29 +141,75 @@ Aside from the display label and icon all the other entries will be provided by

An example of what the configuration could look like:

```bash
export INFRAHUB_OIDC_PROVIDER1_CLIENT_ID=infrahub-sso
export INFRAHUB_OIDC_PROVIDER1_CLIENT_SECRET=edPf4IaquQaqns7t3s95mLhKKYdwL1up
export INFRAHUB_OIDC_PROVIDER1_DISCOVERY_URL=http://localhost:8180/realms/infrahub/.well-known/openid-configuration
export INFRAHUB_OIDC_PROVIDER1_DISPLAY_LABEL="Internal Server (Keycloak)"
export INFRAHUB_OIDC_PROVIDER1_ICON="mdi:security-lock-outline"
```
<Tabs groupId="provider1-configuration">
<TabItem value="Environment Variables" default>

```bash
export INFRAHUB_OIDC_PROVIDER1_CLIENT_ID=infrahub-sso
export INFRAHUB_OIDC_PROVIDER1_CLIENT_SECRET=edPf4IaquQaqns7t3s95mLhKKYdwL1up
export INFRAHUB_OIDC_PROVIDER1_DISCOVERY_URL=http://localhost:8180/realms/infrahub/.well-known/openid-configuration
export INFRAHUB_OIDC_PROVIDER1_DISPLAY_LABEL="Internal Server (Keycloak)"
export INFRAHUB_OIDC_PROVIDER1_ICON="mdi:security-lock-outline"
```

</TabItem>
<TabItem value="infrahub.toml" default>

```toml
[security.oidc_provider_settings.provider1]
client_id = "infrahub-sso"
client_secret = "edPf4IaquQaqns7t3s95mLhKKYdwL1up"
discovery_url = "http://localhost:8180/realms/infrahub/.well-known/openid-configuration"
display_label = "Internal Server (Keycloak)"
icon = "mdi:security-lock-outline"
```

</TabItem>
</Tabs>

This could be the configuration of a Keycloak provider, please refer to the documentation of your intended provider for guides on how to create a client and access the required information.

## Activating the OIDC provider

In order to activate the above provider we need to add it to the list of active OIDC providers.

```bash
export INFRAHUB_SECURITY_OIDC_PROVIDERS='["provider1"]'
```
<Tabs groupId="provider1-configuration">
<TabItem value="Environment Variables" default>

```bash
export INFRAHUB_SECURITY_OIDC_PROVIDERS='["provider1"]'
```

</TabItem>
<TabItem value="infrahub.toml" default>

```toml
[security]
oidc_providers = ["provider1"]
```

</TabItem>
</Tabs>

Alternatively if you are setting up multiple providers each with their different settings:

```bash
export INFRAHUB_SECURITY_OIDC_PROVIDERS='["provider1","provider2"]'
```
<Tabs groupId="provider1-configuration">
<TabItem value="Environment Variables" default>

```bash
export INFRAHUB_SECURITY_OIDC_PROVIDERS='["provider1","provider2"]'
```

</TabItem>
<TabItem value="infrahub.toml" default>

```toml
[security]
oidc_providers = ["provider1", "provider2"]
```

</TabItem>
</Tabs>

## Configuring the redirect URI in the identity provider

Expand Down
Loading