Auth Docker Setup
This page describes a quick local authentication environment for MapStore developers and environment maintainers. It extends the default Docker setup with Keycloak, OpenLDAP and an authentication-aware Nginx proxy, so you can quickly test MapStore login flows and sample user/group mappings.
The stack is intended as a starting point. For the full configuration details, see the dedicated guides for LDAP, OpenID Connect, Keycloak, MapStore authentication and the available infrastructure setups.
Warning
The provided files contain public sample credentials, sample users, a sample Keycloak realm and sample LDAP entries. They are useful only for local development and testing. They are not secrets, they are not secure defaults, and they must be changed before using this setup outside a disposable local environment.
Quick Start
From a clean checkout, copy a MapStore WAR into the repository root. Use an LDAP-profile WAR if you want to test LDAP username/password login:
cp /path/to/your/mapstore-ldap.war mapstore.war
Create the local runtime files from the committed samples:
cp docker/.env.auth.example .env
mkdir -p datadir
cp -R docker/sample-datadir/. datadir/
cp docker/keycloak/realm-mapstore.sample.json docker/keycloak/realm-mapstore.json
Start the stack:
docker compose -f docker-compose.yml -f docker/docker-compose.auth.yml up -d --build
Check the services and open MapStore:
docker compose -f docker-compose.yml -f docker/docker-compose.auth.yml ps
docker ps
- MapStore: http://localhost/mapstore
- Keycloak admin: http://localhost/keycloak/admin/
Stop the stack:
docker compose -f docker-compose.yml -f docker/docker-compose.auth.yml down
For more details, see prerequisites, local runtime files, OpenLDAP initialization, starting the stack, test users and troubleshooting.
Services
The auth Docker setup includes:
- MapStore: the application container, configured with a mounted datadir.
- PostgreSQL/PostGIS: the GeoStore database from the base
docker-compose.yml. - Nginx: the reverse proxy exposed on
http://localhost. - Keycloak: an OpenID Connect identity provider exposed at
http://localhost/keycloak. - OpenLDAP: a sample LDAP directory used to test LDAP users, groups and roles.
The proxy exposes the applications on the same host:
- MapStore: http://localhost/mapstore
- Keycloak: http://localhost/keycloak/
- Keycloak admin console: http://localhost/keycloak/admin/
Prerequisites
Before starting the stack, make sure you have:
- Docker and Docker Compose installed.
- A MapStore WAR available as
mapstore.warin the repository root, or adjust theMAPSTORE_WEBAPP_SRCbuild argument indocker/docker-compose.auth.yml. - A MapStore WAR built with the LDAP profile if you want to test LDAP username/password login. See building and deploying and the LDAP integration guide.
For Keycloak OpenID login only, the sample datadir enables the Keycloak provider through mapstore-ovr.properties. For LDAP login, the MapStore backend must also include the LDAP security configuration.
MapStore WAR source
The auth compose overlay builds the MapStore image with this default argument:
MAPSTORE_WEBAPP_SRC: "mapstore.war"
This means Docker expects a mapstore.war file in the repository root. If the file is missing, the MapStore image build will fail. You can either copy your built WAR to ./mapstore.war or edit docker/docker-compose.auth.yml to point MAPSTORE_WEBAPP_SRC to another local WAR path or a downloadable WAR URL.
cp /path/to/your/mapstore-ldap.war mapstore.war
The root mapstore.war file is ignored by Git and is only used as a local Docker build input.
Prepare Local Runtime Files
From a clean checkout, create the local files that are intentionally not committed:
cp docker/.env.auth.example .env
mkdir -p datadir
cp -R docker/sample-datadir/. datadir/
cp docker/keycloak/realm-mapstore.sample.json docker/keycloak/realm-mapstore.json
Review .env before starting the stack. The most relevant variables are:
KEYCLOAK_ADMINandKEYCLOAK_ADMIN_PASSWORD: credentials for the Keycloak admin console.KEYCLOAK_HOSTNAME: public Keycloak URL used in redirects. The local default ishttp://localhost/keycloak.LDAP_ADMIN_PASSWORD,LDAP_CONFIG_PASSWORDandLDAP_READONLY_PASSWORD: OpenLDAP administrative and read-only bind credentials.DATADIR_PATH: optional path to the MapStore datadir mounted in the container. If omitted,./datadiris used.
Warning
Do not reuse the sample passwords or client secret in shared, staging or production environments. The placeholder values in this repository are intentionally guessable. Update .env, the Keycloak realm, LDIF files and MapStore datadir properties consistently.
The sample datadir contains:
mapstore-ovr.properties: enables Keycloak OpenID login and configures themapstore-serverclient.ldap.properties: sample LDAP connection, search filters and role mapping properties.geostore-datasource-ovr.properties: sample PostgreSQL datasource configuration for GeoStore.configs/localConfig.json.patch: adds Keycloak as an authentication provider in the login UI.
The sample follows the production-oriented OpenID mapping model used by GeoStore 2.6+:
- Identity-provider roles map only to MapStore roles, currently
ADMINorUSER. - Identity-provider groups map to MapStore user groups, such as
KC_ADMINS,KC_USERS,MS_ADMINSorMS_USERS. dropUnmapped=trueis used for sample OpenID group mappings, so only groups explicitly listed ingroupMappingsare created and assigned in MapStore.
The sample mapstore-ovr.properties intentionally separates the internal and public Keycloak URLs:
- Browser-facing authorization and redirect URLs use
http://localhost/..., because the local Nginx proxy exposes both MapStore and Keycloak on that host. - Backend-only token, userinfo, certificate, logout, revocation and introspection URLs use
http://host.docker.internal/keycloak/..., so MapStore calls the same local proxy from inside Docker without depending on the direct Keycloak container network name.
Do not point backend-only MapStore OpenID endpoints at http://localhost/keycloak/... inside this Docker setup. localhost is also the MapStore container itself, so server-side callback operations such as token exchange and key retrieval can fail or depend on host-specific Docker networking behavior. For non-Docker deployments, replace http://host.docker.internal/keycloak with a Keycloak/proxy URL reachable from the MapStore backend.
The sample also enables OpenID global logout and redirects back to http://localhost/mapstore/, so a MapStore logout clears the Keycloak SSO session instead of silently logging the user in again on the next Keycloak login attempt.
Note
The sample Keycloak realm and LDAP credentials are intended for local testing only. Keep docker/keycloak/realm-mapstore.sample.json and the shipped LDIF data as local test data, and replace client secrets and user passwords before using the setup on another machine or in a shared environment.
Note
The sample mapstore-ovr.properties uses keycloakOAuth2Config.autoCreateUser=true so the sample Keycloak users and mapped groups are created and synchronized in a DB-backed GeoStore setup. Set it to false only when the WAR is built in LDAP-direct/read-only user-store mode; in that case, make sure the Keycloak usernames are already available in the external user store.
When you use a MapStore WAR built in LDAP-direct mode, ldap.properties must also define ldap.memberPattern. The shipped sample uses ^uid=([^,]+).*$, which matches the sample OpenLDAP member values such as uid=ldapadmin,ou=people,dc=acme,dc=org.
These files are regular MapStore externalized configuration files. See configuration files and externalized configuration for more details about datadir-based overrides.
Prepare Keycloak
The auth stack imports a Keycloak realm at first startup. The realm defines the mapstore realm, sample users, roles and the confidential OpenID Connect client used by MapStore.
The setup command above copies the sample realm into the filename expected by the compose file:
cp docker/keycloak/realm-mapstore.sample.json docker/keycloak/realm-mapstore.json
The sample realm configures:
- Realm:
mapstore - Client:
mapstore-server - Client secret:
changeme-mapstore-oidc-client-secret-123 - Redirect URI:
http://localhost/mapstore/* - Realm roles:
admin,user - Realm groups:
kc-admins,kc-users - Client mapper: a Group Membership mapper that emits group names in the OIDC
groupsclaim - Sample users:
kcuser,kcadmin
The client and secret must match the values in datadir/mapstore-ovr.properties. If you change the realm file, update the MapStore datadir configuration accordingly. For details about Keycloak OpenID configuration, see the Keycloak section of the OpenID Connect guide.
The sample uses Keycloak realm roles for MapStore role mapping:
keycloakOAuth2Config.rolesClaim=realm_access.roles
keycloakOAuth2Config.roleMappings=admin:ADMIN,user:USER
It uses Keycloak groups for MapStore user-group mapping:
keycloakOAuth2Config.groupsClaim=groups
keycloakOAuth2Config.groupMappings=kc-admins:KC_ADMINS,kc-users:KC_USERS
keycloakOAuth2Config.dropUnmapped=true
This keeps the test bench close to a real customer setup: administrative authority and group membership can be changed independently in the identity provider.
Keycloak Test Users
| Username | Password | Keycloak role | Keycloak group | MapStore role | MapStore group | |
|---|---|---|---|---|---|---|
kcuser |
changeme-kcuser-pw-123 |
kcuser@acme.org |
user |
kc-users |
USER |
KC_USERS |
kcadmin |
changeme-kcadmin-pw-123 |
kcadmin@acme.org |
admin |
kc-admins |
ADMIN |
KC_ADMINS |
The Keycloak admin console is available at http://localhost/keycloak/admin/ with the KEYCLOAK_ADMIN and KEYCLOAK_ADMIN_PASSWORD values configured in .env. The admin user belongs to the Keycloak master realm and is used to manage Keycloak, not to log in to MapStore.
Optional Microsoft Entra Provider
The sample mapstore-ovr.properties includes a commented Microsoft Entra template. It is intentionally disabled because every Entra tenant requires tenant-specific IDs and a real client secret. To enable it in a local copied datadir:
- Change
oidc_providers=keycloaktooidc_providers=keycloak,microsoft. - Uncomment the
microsoftOAuth2Config.*block. - Fill in
clientId,clientSecretand the tenant-specificdiscoveryUrl. - Add a Microsoft entry to
datadir/configs/localConfig.json.patchwith"provider": "microsoft". - Register
http://localhost/mapstore/rest/geostore/openid/microsoft/callbackas a Web redirect URI in the Entra app registration. - Add readable user claims such as
email,preferred_usernameandunique_name, then setmicrosoftOAuth2Config.principalKeyto a claim that is actually present in the token returned by your tenant.
The Microsoft login entry should use the same provider name as the backend prefix:
{
"type": "openID",
"provider": "microsoft",
"title": "Microsoft"
}
For a realistic client-style setup, use Entra App Roles for MapStore ADMIN / USER role mapping and Entra security groups for MapStore user-group mapping. Avoid using the same App Role claim for both roles and groups unless you are deliberately testing a shortcut.
The sample uses microsoftOAuth2Config.principalKey=email because the local Microsoft Entra test token includes a readable email claim while preferred_username may be absent from the token/userinfo data used by this GeoStore 2.6 flow. For a client tenant, inspect the actual returned claims and prefer a stable readable value such as email, preferred_username or unique_name.
Entra Role Mapping
In the App Registration, create app roles like these:
| Display name | Value | Allowed member types | MapStore role |
|---|---|---|---|
MapStore Admin |
MapStore.Admin |
Users/Groups | ADMIN |
MapStore User |
MapStore.User |
Users/Groups | USER |
Assign users or groups to these roles from Enterprise applications -> your application -> Users and groups. The token should then contain a roles claim. Configure MapStore with:
microsoftOAuth2Config.rolesClaim=roles
microsoftOAuth2Config.roleMappings=MapStore.Admin:ADMIN,MapStore.User:USER
microsoftOAuth2Config.authenticatedDefaultRole=USER
MapStore.User is optional when authenticatedDefaultRole=USER is present, but keeping it in the test bench lets you verify both explicit user and admin mappings.
Entra Group Mapping
Create or choose Entra security groups for MapStore groups, for example:
| Entra group | MapStore group |
|---|---|
MS_ADMINS |
MS_ADMINS |
MS_USERS |
MS_USERS |
For the most stable production-like mapping, use the Entra group Object ID values in groupMappings:
microsoftOAuth2Config.groupsClaim=groups
microsoftOAuth2Config.groupMappings=<MS_ADMINS_GROUP_OBJECT_ID>:MS_ADMINS,<MS_USERS_GROUP_OBJECT_ID>:MS_USERS
microsoftOAuth2Config.dropUnmapped=true
To get the groups claim in the token, configure the Entra app registration to emit group claims. A practical setup is:
- Open App registrations -> your app -> Token configuration.
- Add a Groups claim.
- Prefer groups assigned to the application when available, so the token contains only groups relevant to this app.
- Assign the
MS_ADMINSandMS_USERSgroups to the Enterprise Application.
By default, Entra emits group Object IDs. That is usually the safest value to map because display names can change. If a client explicitly wants display names, configure the app manifest to emit cloud display names for app-assigned groups and use those display names in groupMappings instead:
{
"groupMembershipClaims": "ApplicationGroup",
"optionalClaims": {
"idToken": [
{
"name": "groups",
"additionalProperties": ["cloud_displayname"]
}
]
}
}
When group claims are enabled broadly, users in many groups can hit Entra's group overage behavior and the token may omit the normal groups list. For this test bench, prefer app-assigned groups and dropUnmapped=true so the MapStore side stays deterministic.
Prepare OpenLDAP
OpenLDAP is initialized from docker/openldap/ldap-init.ldif when the LDAP data volume is empty. The repository ships the complete bootstrap data in that single file, so it is the source of truth for organizational units, users, groups and roles.
The LDAP bootstrap file defines:
- Organizational units, such as
ou=peopleandou=groups. - Sample users, including
ldapadminandldapuser. - LDAP groups and roles, including
ROLE_ADMIN,ROLE_USER,LDAP_ADMINSandLDAP_USERS.
MapStore/GeoStore also assigns users to its default everyone group; that group is not bootstrapped from the LDAP LDIF files.
The LDIF file is mounted by the compose overlay, copied into the OpenLDAP bootstrap directory at container startup and imported only when the LDAP volumes are empty. If you edit ldap-init.ldif after the first startup, remove the LDAP volumes before starting again.
docker compose -f docker-compose.yml -f docker/docker-compose.auth.yml down
docker volume rm mapstore2_ldap_data mapstore2_ldap_config
docker compose -f docker-compose.yml -f docker/docker-compose.auth.yml up -d
Note
Docker Compose may use a different volume prefix depending on the project directory or COMPOSE_PROJECT_NAME. Run docker volume ls if the volume names differ.
LDAP Test Users
| Login | Password | MapStore role | LDAP / MapStore groups |
|---|---|---|---|
ldapadmin |
changeme-ldapadmin-pw-123 |
ADMIN |
ROLE_ADMIN, LDAP_ADMINS, everyone |
ldapuser |
changeme-ldapuser-pw-123 |
USER |
ROLE_USER, LDAP_USERS, everyone |
Log in with the LDAP uid, for example ldapadmin, not the full DN. With ldap.convertToUpperCase=true, synchronized user and group names may appear uppercase in MapStore.
For a full explanation of LDAP synchronized and direct modes, see the LDAP integration guide.
Start The Stack
Start MapStore with the auth compose overlay:
docker compose -f docker-compose.yml -f docker/docker-compose.auth.yml up -d --build
Check the running services:
docker compose -f docker-compose.yml -f docker/docker-compose.auth.yml ps
docker ps
Open http://localhost/mapstore when the services are ready.
To stop the stack:
docker compose -f docker-compose.yml -f docker/docker-compose.auth.yml down
To remove containers and volumes for a clean re-import:
docker compose -f docker-compose.yml -f docker/docker-compose.auth.yml down -v
Test Login
For Keycloak OpenID login:
- Open http://localhost/mapstore.
- Click login and choose Keycloak.
- Log in with
kcuser/changeme-kcuser-pw-123orkcadmin/changeme-kcadmin-pw-123. - Keycloak redirects back to MapStore.
For LDAP login, use the standard username/password form with one of the LDAP users, such as ldapadmin / changeme-ldapadmin-pw-123. This requires a MapStore WAR built and configured with LDAP support. See LDAP integration with MapStore.
Troubleshooting
- Keycloak realm not imported: Keycloak imports realm files only on first startup. Remove the
keycloak_datavolume and restart the stack. - LDAP users not found: confirm
docker/openldap/ldap-init.ldifexists before first startup. If the LDAP volume already exists, remove the LDAP volumes and restart. - MapStore waits for LDAP healthcheck: the LDAP container now uses a root DSE healthcheck, so this usually points to an LDAP startup problem rather than missing sample users.
- OIDC login returns 500 before reaching Keycloak: check the MapStore logs for
authorizationUri is null. In this Docker setup,keycloakOAuth2Config.authorizationUrimust be configured explicitly and should point to the public browser URLhttp://localhost/keycloak/realms/mapstore/protocol/openid-connect/auth. - OIDC callback returns 500 after Keycloak login: make sure backend-only endpoints such as
accessTokenUri,checkTokenEndpointUrl,idTokenUri,revokeEndpointandintrospectionEndpointpoint tohttp://host.docker.internal/keycloak/..., nothttp://localhost/keycloak/.... - Keycloak login is automatic after MapStore logout: this means the Keycloak SSO session is still active. The sample sets
keycloakOAuth2Config.globalLogoutEnabled=trueandkeycloakOAuth2Config.postLogoutRedirectUri=http://localhost/mapstore/so MapStore logout also asks Keycloak to end the realm session. - Redirect or callback errors: check that the Keycloak redirect URI matches
http://localhost/mapstore/*and thatkeycloakOAuth2Config.redirectUriin the datadir points tohttp://localhost/mapstore/rest/geostore/openid/keycloak/callback. In LDAP-direct mode, keepkeycloakOAuth2Config.autoCreateUser=false; otherwise the Keycloak callback can fail while trying to sync users and groups through the LDAP-backed GeoStore DAOs. - 502 Bad Gateway during login or callback: the auth proxy config in
docker/mapstore.auth.confincreases proxy buffers for Keycloak and MapStore callback responses. Restart the proxy if you edit the file. - LDAP LDIF changes are ignored: LDIF bootstrap runs only on an empty LDAP volume. Remove LDAP volumes before restarting.
- LDAP login does not appear to work: confirm the WAR was built with the LDAP profile and that
ldap.propertiesis available in the datadir.