diff --git a/.env.dev b/.env.dev new file mode 100644 index 0000000..115e8ef --- /dev/null +++ b/.env.dev @@ -0,0 +1,19 @@ +# Committed defaults for the dev environment. +# +# Local development runs against the mock identity provider defined in +# docker-compose.override.yml, because the real one has no redirect URI +# registered for a developer machine. See README.md, "OpenID Connect". +# +# Override any of these in .env.local to point at a different provider. + +###> itk-dev/openid-connect-bundle ### +AZURE_AZ_OIDC_METADATA_URL=http://idp.itksites.local.itkdev.dk/.well-known/openid-configuration +# The mock accepts any client id and secret. +AZURE_AZ_OIDC_CLIENT_ID=client-id +AZURE_AZ_OIDC_CLIENT_SECRET=client-secret +AZURE_AZ_OIDC_REDIRECT_URI=https://itksites.local.itkdev.dk/openid-connect/generic +# The application reaches the mock over http inside the docker network. Never +# true anywhere else: since itk-dev/openid-connect 5.1 this governs every +# endpoint the discovery document announces, not only the metadata URL. +AZURE_AZ_OIDC_ALLOW_HTTP=true +###< itk-dev/openid-connect-bundle ### diff --git a/README.md b/README.md index 64b5416..5a50f68 100644 --- a/README.md +++ b/README.md @@ -113,8 +113,22 @@ Then create a `.env.local` file to set secrets for your local setup. ### OpenID Connect -All users access is controlled by OpenID Connect. For local development you must -add the following to your `.env.local` file: +All user access is controlled by OpenID Connect. Locally the login runs against a +mock identity provider, defined as the `idp` service in `docker-compose.override.yml` +— the real provider has no redirect URI registered for a developer machine. + +Start it with the rest of the stack: + +```shell +docker compose up --detach +``` + +Then log in as `admin` or `editor`: the mock shows a form where you type the subject, +and hands back the claims for it. Both identities are defined in the compose file, and +their claims must include `name` and `upn`, which `AzureOIDCAuthenticator` reads. + +`.env.dev` carries the settings, so there is nothing to add to `.env.local` for an +ordinary setup. To develop against a real provider instead, override them there: ```dotenv ###> itk-dev/openid-connect-bundle ### @@ -122,13 +136,18 @@ AZURE_AZ_OIDC_METADATA_URL= AZURE_AZ_OIDC_CLIENT_ID= AZURE_AZ_OIDC_CLIENT_SECRET= AZURE_AZ_OIDC_REDIRECT_URI=https://itksites.local.itkdev.dk/openid-connect/generic +AZURE_AZ_OIDC_ALLOW_HTTP=false ###< itk-dev/openid-connect-bundle ### ``` > [!NOTE] -> In the `dev` environment the main firewall security is disabled -> (`security.yaml` → `when@dev`), so authentication is not required. -> This is because the current AAK OIDC setup doesn't support `itksites.local.itkdev.dk`. +> `AZURE_AZ_OIDC_ALLOW_HTTP=true` in `.env.dev` is what lets the application talk to +> the mock over http inside the docker network. It must never be true anywhere else: +> since `itk-dev/openid-connect` 5.1 it governs every endpoint the discovery document +> announces, not only the metadata URL. + +The mock accepts the PKCE challenge the bundle sends but does not verify it, so a +successful login here does not prove PKCE works against Azure. ### Fixtures diff --git a/config/packages/security.yaml b/config/packages/security.yaml index e89023b..c730e4c 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -58,13 +58,6 @@ security: - { path: ^/admin, roles: ROLE_ADMIN } # - { path: ^/profile, roles: ROLE_USER } -# Current AAK OIDC setup doesn't support `itksites.local.itkdev.dk` -when@dev: - security: - firewalls: - main: - security: false - when@test: security: password_hashers: diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 73f8b43..be2dcc5 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,4 +1,35 @@ services: + # A mock identity provider, so the OpenID Connect login can be exercised locally. + # The real one has no redirect URI registered for a developer machine. + # + # https://github.com/geigerzaehler/oidc-provider-mock + # + # The container name is the external hostname on purpose: the browser and the + # application then reach the provider by the same name, so the issuer in the + # discovery document matches the one in the ID token. + # + # Claims must cover what AzureOIDCAuthenticator reads — `name` and `upn`. + idp: + image: ghcr.io/geigerzaehler/oidc-provider-mock:latest + container_name: idp.${COMPOSE_DOMAIN:?} + networks: + - app + - frontend + expose: + - "80" + labels: + - "traefik.enable=true" + - "traefik.docker.network=frontend" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME:?}_idp.rule=Host(`idp.${COMPOSE_DOMAIN:?}`)" + - "traefik.http.services.${COMPOSE_PROJECT_NAME:?}_idp.loadbalancer.server.port=80" + command: + - "--port" + - "80" + - "--user-claims" + - '{"sub": "admin", "name": "Admin Jensen", "upn": "admin@example.org", "email": "admin@example.org"}' + - "--user-claims" + - '{"sub": "editor", "name": "Ed Editor", "upn": "editor@example.org", "email": "editor@example.org"}' + rabbit: image: rabbitmq:4-management-alpine networks: