🧑💻(demo) configure people as an IdP
This configures local environment to test login through people: - Keycloak configuration of the IdP (people) - Add Keycloak Application in people The only user who can login for now is "admin".
This commit is contained in:
29
bin/Tiltfile
29
bin/Tiltfile
@@ -59,6 +59,35 @@ cmd_button('Migrate db',
|
|||||||
text='Run database migration',
|
text='Run database migration',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Command to reset DB
|
||||||
|
reset_db = '''
|
||||||
|
set -eu
|
||||||
|
# get k8s pod name from tilt resource name
|
||||||
|
POD_NAME="$(tilt get kubernetesdiscovery desk-backend -ojsonpath='{.status.pods[0].name}')"
|
||||||
|
kubectl -n desk exec "$POD_NAME" -- python manage.py flush --no-input
|
||||||
|
kubectl -n desk exec "$POD_NAME" -- python manage.py createsuperuser --username admin@example.com --password admin
|
||||||
|
'''
|
||||||
|
cmd_button('Reset DB',
|
||||||
|
argv=['sh', '-c', reset_db],
|
||||||
|
resource='desk-backend',
|
||||||
|
icon_name='developer_board',
|
||||||
|
text='Reset DB',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Command to create demo data
|
||||||
|
populate_people_with_demo_data = '''
|
||||||
|
set -eu
|
||||||
|
# get k8s pod name from tilt resource name
|
||||||
|
POD_NAME="$(tilt get kubernetesdiscovery desk-backend -ojsonpath='{.status.pods[0].name}')"
|
||||||
|
kubectl -n desk exec "$POD_NAME" -- python manage.py create_demo --force
|
||||||
|
'''
|
||||||
|
cmd_button('Populate with demo data',
|
||||||
|
argv=['sh', '-c', populate_people_with_demo_data],
|
||||||
|
resource='desk-backend',
|
||||||
|
icon_name='developer_board',
|
||||||
|
text='Populate with demo data',
|
||||||
|
)
|
||||||
|
|
||||||
# Command to created domain/users/access from people to dimail
|
# Command to created domain/users/access from people to dimail
|
||||||
populate_dimail_from_people = '''
|
populate_dimail_from_people = '''
|
||||||
set -eu
|
set -eu
|
||||||
|
|||||||
@@ -129,6 +129,8 @@ services:
|
|||||||
image: quay.io/keycloak/keycloak:20.0.1
|
image: quay.io/keycloak/keycloak:20.0.1
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker/auth/realm.json:/opt/keycloak/data/import/realm.json
|
- ./docker/auth/realm.json:/opt/keycloak/data/import/realm.json
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
command:
|
command:
|
||||||
- start-dev
|
- start-dev
|
||||||
- --features=preview
|
- --features=preview
|
||||||
|
|||||||
@@ -1652,8 +1652,130 @@
|
|||||||
"enabledEventTypes": [],
|
"enabledEventTypes": [],
|
||||||
"adminEventsEnabled": false,
|
"adminEventsEnabled": false,
|
||||||
"adminEventsDetailsEnabled": false,
|
"adminEventsDetailsEnabled": false,
|
||||||
"identityProviders": [],
|
"identityProviders": [
|
||||||
"identityProviderMappers": [],
|
{
|
||||||
|
"alias": "oidc-people-local",
|
||||||
|
"displayName": "People OIDC (local)",
|
||||||
|
"internalId": "47aa6d7c-8ac5-4178-934e-66f78e510ee4",
|
||||||
|
"providerId": "oidc",
|
||||||
|
"enabled": true,
|
||||||
|
"updateProfileFirstLoginMode": "on",
|
||||||
|
"trustEmail": false,
|
||||||
|
"storeToken": false,
|
||||||
|
"addReadTokenRoleOnCreate": false,
|
||||||
|
"authenticateByDefault": false,
|
||||||
|
"linkOnly": false,
|
||||||
|
"firstBrokerLoginFlowAlias": "first broker login",
|
||||||
|
"config": {
|
||||||
|
"hideOnLoginPage": "false",
|
||||||
|
"userInfoUrl": "http://app-dev:8000/o/userinfo/",
|
||||||
|
"validateSignature": "true",
|
||||||
|
"acceptsPromptNoneForwardFromClient": "false",
|
||||||
|
"clientId": "people-idp",
|
||||||
|
"tokenUrl": "http://app-dev:8000/o/token/",
|
||||||
|
"uiLocales": "false",
|
||||||
|
"jwksUrl": "http://app-dev:8000/o/.well-known/jwks.json",
|
||||||
|
"backchannelSupported": "false",
|
||||||
|
"issuer": "http://app-dev:8000/o",
|
||||||
|
"useJwksUrl": "true",
|
||||||
|
"loginHint": "true",
|
||||||
|
"pkceEnabled": "true",
|
||||||
|
"pkceMethod": "S256",
|
||||||
|
"authorizationUrl": "http://localhost:8071/o/authorize/",
|
||||||
|
"clientAuthMethod": "client_secret_post",
|
||||||
|
"disableUserInfo": "false",
|
||||||
|
"syncMode": "IMPORT",
|
||||||
|
"clientSecret": "local-tests-only",
|
||||||
|
"passMaxAge": "false",
|
||||||
|
"defaultScope": "openid given_name usual_name email siret",
|
||||||
|
"allowedClockSkew": "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"identityProviderMappers": [
|
||||||
|
{
|
||||||
|
"id": "e55dc88c-7bb5-46fb-95ad-1df701a96282",
|
||||||
|
"name": "Sub",
|
||||||
|
"identityProviderAlias": "oidc-people-local",
|
||||||
|
"identityProviderMapper": "oidc-username-idp-mapper",
|
||||||
|
"config": {
|
||||||
|
"template": "${CLAIM.sub}",
|
||||||
|
"are.claim.values.regex": "false",
|
||||||
|
"claims": "[{\"key\":\"\",\"value\":\"\"}]",
|
||||||
|
"syncMode": "FORCE",
|
||||||
|
"attributes": "[]",
|
||||||
|
"target": "BROKER_ID"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7e489676-8cba-49e4-aa1e-dcd1462d33f7",
|
||||||
|
"name": "given_name",
|
||||||
|
"identityProviderAlias": "oidc-people-local",
|
||||||
|
"identityProviderMapper": "hardcoded-attribute-idp-mapper",
|
||||||
|
"config": {
|
||||||
|
"claims": "[{\"key\":\"\",\"value\":\"\"}]",
|
||||||
|
"syncMode": "FORCE",
|
||||||
|
"are.claim.values.regex": "false",
|
||||||
|
"attributes": "[]",
|
||||||
|
"attribute": "firstName"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "30b6b3bc-5738-4936-bf88-c540b8805998",
|
||||||
|
"name": "usual_name",
|
||||||
|
"identityProviderAlias": "oidc-people-local",
|
||||||
|
"identityProviderMapper": "oidc-user-attribute-idp-mapper",
|
||||||
|
"config": {
|
||||||
|
"template": "${ALIAS}.${CLAIM.preferred_username}",
|
||||||
|
"are.claim.values.regex": "false",
|
||||||
|
"claims": "[{\"key\":\"profile\",\"value\":\"lastName\"}]",
|
||||||
|
"syncMode": "FORCE",
|
||||||
|
"claim": "profile",
|
||||||
|
"user.attribute": "lastName",
|
||||||
|
"attributes": "[]",
|
||||||
|
"target": "LOCAL"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b67caa26-4571-4cfe-9c15-68e022645fc5",
|
||||||
|
"name": "Username",
|
||||||
|
"identityProviderAlias": "oidc-people-local",
|
||||||
|
"identityProviderMapper": "oidc-username-idp-mapper",
|
||||||
|
"config": {
|
||||||
|
"template": "${CLAIM.email | lowercase}",
|
||||||
|
"are.claim.values.regex": "false",
|
||||||
|
"claims": "[{\"key\":\"\",\"value\":\"\"}]",
|
||||||
|
"syncMode": "FORCE",
|
||||||
|
"attributes": "[]",
|
||||||
|
"target": "BROKER_USERNAME"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4eef21ce-b5f7-4753-bd58-4e50eb2b5f31",
|
||||||
|
"name": "Email",
|
||||||
|
"identityProviderAlias": "oidc-people-local",
|
||||||
|
"identityProviderMapper": "oidc-user-attribute-idp-mapper",
|
||||||
|
"config": {
|
||||||
|
"are.claim.values.regex": "false",
|
||||||
|
"claims": "[{\"key\":\"\",\"value\":\"\"}]",
|
||||||
|
"syncMode": "FORCE",
|
||||||
|
"claim": "email",
|
||||||
|
"user.attribute": "email",
|
||||||
|
"attributes": "[]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "084cdd0e-0794-4388-8474-84c9a7c1b9c8",
|
||||||
|
"name": "siret",
|
||||||
|
"identityProviderAlias": "oidc-people-local",
|
||||||
|
"identityProviderMapper": "oidc-user-attribute-idp-mapper",
|
||||||
|
"config": {
|
||||||
|
"syncMode": "FORCE",
|
||||||
|
"claim": "siret",
|
||||||
|
"user.attribute": "siret"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"components": {
|
"components": {
|
||||||
"org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
|
"org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
|
||||||
{
|
{
|
||||||
@@ -2195,7 +2317,7 @@
|
|||||||
"authenticatorConfig": "review profile config",
|
"authenticatorConfig": "review profile config",
|
||||||
"authenticator": "idp-review-profile",
|
"authenticator": "idp-review-profile",
|
||||||
"authenticatorFlow": false,
|
"authenticatorFlow": false,
|
||||||
"requirement": "REQUIRED",
|
"requirement": "DISABLED",
|
||||||
"priority": 10,
|
"priority": 10,
|
||||||
"autheticatorFlow": false,
|
"autheticatorFlow": false,
|
||||||
"userSetupAllowed": false
|
"userSetupAllowed": false
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from django.core.management.base import BaseCommand, CommandError
|
|||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
|
|
||||||
from faker import Faker
|
from faker import Faker
|
||||||
|
from oauth2_provider.models import Application
|
||||||
from treebeard.mp_tree import MP_Node
|
from treebeard.mp_tree import MP_Node
|
||||||
|
|
||||||
from core import models
|
from core import models
|
||||||
@@ -133,6 +134,25 @@ class Timeit:
|
|||||||
return elapsed_time
|
return elapsed_time
|
||||||
|
|
||||||
|
|
||||||
|
def create_oidc_people_idp_client():
|
||||||
|
"""Configure the OIDC client for the People Identity Provider if missing."""
|
||||||
|
try:
|
||||||
|
Application.objects.get(client_id="people-idp")
|
||||||
|
except Application.DoesNotExist:
|
||||||
|
application = Application(
|
||||||
|
client_id="people-idp",
|
||||||
|
client_secret="local-tests-only",
|
||||||
|
client_type=Application.CLIENT_CONFIDENTIAL,
|
||||||
|
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
|
||||||
|
name="People Identity Provider",
|
||||||
|
algorithm=Application.RS256_ALGORITHM,
|
||||||
|
redirect_uris="http://localhost:8083/realms/people/broker/oidc-people-local/endpoint",
|
||||||
|
skip_authorization=True,
|
||||||
|
)
|
||||||
|
application.clean()
|
||||||
|
application.save()
|
||||||
|
|
||||||
|
|
||||||
def create_demo(stdout): # pylint: disable=too-many-locals
|
def create_demo(stdout): # pylint: disable=too-many-locals
|
||||||
"""
|
"""
|
||||||
Create a database with demo data for developers to work in a realistic environment.
|
Create a database with demo data for developers to work in a realistic environment.
|
||||||
@@ -315,6 +335,10 @@ def create_demo(stdout): # pylint: disable=too-many-locals
|
|||||||
|
|
||||||
queue.flush()
|
queue.flush()
|
||||||
|
|
||||||
|
# OIDC configuration
|
||||||
|
if settings.OAUTH2_PROVIDER.get("OIDC_ENABLED", False):
|
||||||
|
create_oidc_people_idp_client()
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
"""A management command to create a demo database."""
|
"""A management command to create a demo database."""
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.test import override_settings
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -11,6 +10,7 @@ from core import models
|
|||||||
|
|
||||||
from demo import defaults
|
from demo import defaults
|
||||||
from mailbox_manager import models as mailbox_models
|
from mailbox_manager import models as mailbox_models
|
||||||
|
from people.settings import Base
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
@@ -23,10 +23,13 @@ TEST_NB_OBJECTS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override_settings(DEBUG=True)
|
|
||||||
@mock.patch.dict(defaults.NB_OBJECTS, TEST_NB_OBJECTS)
|
@mock.patch.dict(defaults.NB_OBJECTS, TEST_NB_OBJECTS)
|
||||||
def test_commands_create_demo():
|
def test_commands_create_demo(settings):
|
||||||
"""The create_demo management command should create objects as expected."""
|
"""The create_demo management command should create objects as expected."""
|
||||||
|
settings.DEBUG = True
|
||||||
|
settings.OAUTH2_PROVIDER["OIDC_ENABLED"] = True
|
||||||
|
settings.OAUTH2_PROVIDER["OIDC_RSA_PRIVATE_KEY"] = Base.generate_temporary_rsa_key()
|
||||||
|
|
||||||
call_command("create_demo")
|
call_command("create_demo")
|
||||||
|
|
||||||
# Monique Test, Jeanne Test and Jean Something (quick fix for e2e)
|
# Monique Test, Jeanne Test and Jean Something (quick fix for e2e)
|
||||||
@@ -37,7 +40,7 @@ def test_commands_create_demo():
|
|||||||
|
|
||||||
assert models.Team.objects.count() == TEST_NB_OBJECTS["teams"]
|
assert models.Team.objects.count() == TEST_NB_OBJECTS["teams"]
|
||||||
assert models.TeamAccess.objects.count() >= TEST_NB_OBJECTS["teams"]
|
assert models.TeamAccess.objects.count() >= TEST_NB_OBJECTS["teams"]
|
||||||
assert mailbox_models.MailDomain.objects.count() == TEST_NB_OBJECTS["domains"]
|
assert mailbox_models.MailDomain.objects.count() == TEST_NB_OBJECTS["domains"] + 1
|
||||||
|
|
||||||
# 3 domain access for each user with domain rights
|
# 3 domain access for each user with domain rights
|
||||||
# 3 x 3 domain access for each user with both rights
|
# 3 x 3 domain access for each user with both rights
|
||||||
|
|||||||
Reference in New Issue
Block a user