Skip to content

Commit

Permalink
🚧[#114] partial implementation of new setup config
Browse files Browse the repository at this point in the history
  • Loading branch information
Coperh committed Nov 15, 2024
1 parent da465fe commit 539ab50
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 100 deletions.
Empty file.
56 changes: 56 additions & 0 deletions mozilla_django_oidc_db/setup_configuration/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from typing import Optional

from django_setup_configuration.fields import DjangoModelRef
from django_setup_configuration.models import ConfigurationModel
from pydantic import AnyUrl

from mozilla_django_oidc_db.models import OpenIDConnectConfig


class AdminOIDCConfigurationModel(ConfigurationModel):

# claim_mapping: Optional[str] = None # JSON

# Arrays are overridden to make the typing simpler (the underlying Django field is an ArrayField, which is non-standard)
username_claim: Optional[list[str]] = DjangoModelRef(
OpenIDConnectConfig, "username_claim"
)
groups_claim: Optional[list[str]] = DjangoModelRef(
OpenIDConnectConfig, "groups_claim"
)
superuser_group_names: Optional[list[str]] = DjangoModelRef(
OpenIDConnectConfig, "superuser_group_names"
)

# Endpoints
oidc_op_authorization_endpoint: Optional[AnyUrl] = DjangoModelRef(
OpenIDConnectConfig, "oidc_op_authorization_endpoint", required=False
)
oidc_op_token_endpoint: Optional[AnyUrl] = DjangoModelRef(
OpenIDConnectConfig, "oidc_op_token_endpoint", required=False
)
oidc_op_user_endpoint: Optional[AnyUrl] = DjangoModelRef(
OpenIDConnectConfig, "oidc_op_user_endpoint", required=False
)

class Meta:
django_model_refs = {
OpenIDConnectConfig: [
"oidc_rp_client_id",
"oidc_rp_client_secret",
"oidc_op_authorization_endpoint",
"oidc_op_token_endpoint",
"oidc_op_user_endpoint",
"oidc_token_use_basic_auth",
"oidc_rp_idp_sign_key",
"oidc_op_logout_endpoint",
"oidc_use_nonce",
"oidc_nonce_size",
"oidc_state_size",
"oidc_keycloak_idp_hint",
"userinfo_claims_source",
"sync_groups",
"sync_groups_glob_pattern",
"make_users_staff",
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,32 @@
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import RequestFactory
from django.utils.module_loading import import_string
from django.utils.translation import gettext as _

from django_setup_configuration.config_settings import ConfigSettings
from django_setup_configuration.configuration import BaseConfigurationStep
from django_setup_configuration.exceptions import ConfigurationRunFailed, SelfTestFailed

from .forms import OIDCSetupConfigForm
from .models import OpenIDConnectConfig
from .utils import create_missing_groups
from mozilla_django_oidc_db.forms import OIDCSetupConfigForm
from mozilla_django_oidc_db.models import OpenIDConnectConfig
from mozilla_django_oidc_db.setup_configuration.models import (
AdminOIDCConfigurationModel,
)
from mozilla_django_oidc_db.utils import create_missing_groups


class AdminOIDCConfigurationStep(BaseConfigurationStep):
class AdminOIDCConfigurationStep(BaseConfigurationStep[AdminOIDCConfigurationModel]):
"""
Configure admin login via OpenID Connect
"""

verbose_name = _("Configuration for admin login via OpenID Connect")
verbose_name = "Configuration for admin login via OpenID Connect"
config_model = AdminOIDCConfigurationModel
namespace = "ADMIN_OIDC"
enable_setting = "ADMIN_OIDC_CONFIG_ENABLE"

config_settings = ConfigSettings(
enable_setting="OIDC_DB_CONFIG_ENABLE",
display_name=_("Admin OIDC Configuration"),
namespace="OIDC_DB",
models=[OpenIDConnectConfig],
update_fields=True,
required_settings=["OIDC_DB_SETUP_CONFIG_ADMIN_AUTH"],
)

def is_configured(self) -> bool:
def is_configured(self, model) -> bool:
return OpenIDConnectConfig.get_solo().enabled

def configure(self):
def execute(self, model: AdminOIDCConfigurationModel) -> None:
config = OpenIDConnectConfig.get_solo()

all_settings = {
Expand All @@ -41,7 +36,7 @@ def configure(self):
"enabled": True,
"claim_mapping": config.claim_mapping, # JSONFormField widget cannot handle blank values with object schema
"sync_groups_glob_pattern": config.sync_groups_glob_pattern,
**settings.OIDC_DB_SETUP_CONFIG_ADMIN_AUTH,
**model.model_dump(),
}

if groups := all_settings.get("default_groups"):
Expand All @@ -58,10 +53,9 @@ def configure(self):
"Admin OIDC configuration field validation failed",
form.errors.as_json(),
)

form.save()

def test_configuration(self):
def validate_result(self, model: AdminOIDCConfigurationModel):

request_factory = RequestFactory()
request = request_factory.get("/irrelevant")
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Changelog = "https://github.com/maykinmedia/mozilla-django-oidc-db/blob/master/C

[project.optional-dependencies]
setupconfig = [
"django-setup-configuration>=0.3.0",
"django-setup-configuration@git+https://github.com/maykinmedia/django-setup-configuration.git@d594a467c43c3323adf118d4a6a249d89dad2535",
]
tests = [
"psycopg2",
Expand Down
2 changes: 1 addition & 1 deletion testapp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@

OIDC_DB_CONFIG_ENABLE = True
SETUP_CONFIGURATION_STEPS = [
"mozilla_django_oidc_db.setup_config.AdminOIDCConfigurationStep",
"mozilla_django_oidc_db.setup_configuration.steps.AdminOIDCConfigurationStep",
]
except ImportError:
pass
59 changes: 14 additions & 45 deletions tests/setupconfig/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import pytest
from django_setup_configuration.test_utils import load_step_config_from_source

from mozilla_django_oidc_db.models import UserInformationClaimsSources

from ..conftest import KEYCLOAK_BASE_URL
from mozilla_django_oidc_db.setup_configuration.steps import AdminOIDCConfigurationStep

"""
Key cloak credentials are setup for the keycloak docker-compose.yml.
Expand All @@ -16,51 +15,21 @@


@pytest.fixture
def setup_config_discovery(settings):
settings.OIDC_DB_SETUP_CONFIG_ADMIN_AUTH = {
"oidc_rp_client_id": "testid",
"oidc_rp_client_secret": "7DB3KUAAizYCcmZufpHRVOcD0TOkNO3I",
"oidc_op_discovery_endpoint": KEYCLOAK_BASE_URL,
}
def setup_config_discovery_model(settings):
return load_step_config_from_source(
AdminOIDCConfigurationStep, "tests/setupconfig/files/discovery.yml"
)


@pytest.fixture
def setup_config_defaults(settings):
settings.OIDC_DB_SETUP_CONFIG_ADMIN_AUTH = {
"oidc_rp_client_id": "client-id",
"oidc_rp_client_secret": "secret",
"oidc_op_authorization_endpoint": f"{KEYCLOAK_BASE_URL}protocol/openid-connect/auth",
"oidc_op_token_endpoint": f"{KEYCLOAK_BASE_URL}protocol/openid-connect/token",
"oidc_op_user_endpoint": f"{KEYCLOAK_BASE_URL}protocol/openid-connect/userinfo",
}
def setup_config_defaults_model(settings):
return load_step_config_from_source(
AdminOIDCConfigurationStep, "tests/setupconfig/files/defaults.yml"
)


@pytest.fixture
def setup_config_full(settings):

settings.OIDC_DB_SETUP_CONFIG_ADMIN_AUTH = {
"oidc_rp_client_id": "client-id",
"oidc_rp_client_secret": "secret",
"oidc_rp_scopes_list": ["open_id", "email", "profile", "extra_scope"],
"oidc_rp_sign_algo": "RS256",
"oidc_rp_idp_sign_key": "key",
"oidc_op_discovery_endpoint": None,
"oidc_op_jwks_endpoint": f"{KEYCLOAK_BASE_URL}protocol/openid-connect/certs",
"oidc_op_authorization_endpoint": (
f"{KEYCLOAK_BASE_URL}protocol/openid-connect/auth"
),
"oidc_op_token_endpoint": f"{KEYCLOAK_BASE_URL}protocol/openid-connect/token",
"oidc_op_user_endpoint": f"{KEYCLOAK_BASE_URL}protocol/openid-connect/userinfo",
"username_claim": ["claim_name"],
"groups_claim": ["groups_claim_name"],
"claim_mapping": {"first_name": ["given_name"]},
"sync_groups": False,
"sync_groups_glob_pattern": "local.groups.*",
"default_groups": ["local.groups.Admins", "local.groups.Read-only"],
"make_users_staff": True,
"superuser_group_names": ["superuser"],
"oidc_use_nonce": False,
"oidc_nonce_size": 48,
"oidc_state_size": 48,
"userinfo_claims_source": UserInformationClaimsSources.id_token,
}
def setup_config_full_model():
return load_step_config_from_source(
AdminOIDCConfigurationStep, "tests/setupconfig/files/full_setup.yml"
)
7 changes: 7 additions & 0 deletions tests/setupconfig/files/defaults.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ADMIN_OIDC_CONFIG_ENABLE: True
ADMIN_OIDC:
oidc_rp_client_id: client-id
oidc_rp_client_secret: secret
oidc_op_authorization_endpoint: http://localhost:8080/realms/test/protocol/openid-connect/auth
oidc_op_token_endpoint: http://localhost:8080/realms/test/protocol/openid-connect/token
oidc_op_user_endpoint: http://localhost:8080/realms/test/protocol/openid-connect/userinfo
5 changes: 5 additions & 0 deletions tests/setupconfig/files/discovery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ADMIN_OIDC_CONFIG_ENABLE: True
ADMIN_OIDC:
oidc_rp_client_id: testid
oidc_rp_client_secret: 7DB3KUAAizYCcmZufpHRVOcD0TOkNO3I
oidc_op_discovery_endpoint: http://localhost:8080/realms/test/
5 changes: 5 additions & 0 deletions tests/setupconfig/files/discovery_disabled.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ADMIN_OIDC_CONFIG_ENABLE: False
ADMIN_OIDC:
oidc_rp_client_id: testid
oidc_rp_client_secret: 7DB3KUAAizYCcmZufpHRVOcD0TOkNO3I
oidc_op_discovery_endpoint: http://localhost:8080/realms/test/
2 changes: 2 additions & 0 deletions tests/setupconfig/files/empty.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ADMIN_OIDC_CONFIG_ENABLE: True
ADMIN_OIDC: {}
36 changes: 36 additions & 0 deletions tests/setupconfig/files/full_setup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
ADMIN_OIDC_CONFIG_ENABLE: True
ADMIN_OIDC:
oidc_rp_client_id: client-id
oidc_rp_client_secret: secret
oidc_rp_scopes_list:
- open_id
- email
- profile
- extra_scope
oidc_rp_sign_algo: RS256
oidc_rp_idp_sign_key: key
oidc_op_discovery_endpoint:
oidc_op_jwks_endpoint: http://localhost:8080/realms/test/protocol/openid-connect/certs
oidc_op_authorization_endpoint: http://localhost:8080/realms/test/protocol/openid-connect/auth
oidc_op_token_endpoint: http://localhost:8080/realms/test/protocol/openid-connect/token
oidc_op_user_endpoint: http://localhost:8080/realms/test/protocol/openid-connect/userinfo
username_claim:
- claim_name
groups_claim:
- groups_claim_name
claim_mapping:
first_name:
- given_name
sync_groups: false
sync_groups_glob_pattern: local.groups.*
default_groups:
- local.groups.Admins
- local.groups.Read-only
make_users_staff: true
superuser_group_names:
- superuser
oidc_use_nonce: false
oidc_nonce_size: 48
oidc_state_size: 48
userinfo_claims_source: id_token

Loading

0 comments on commit 539ab50

Please sign in to comment.