-
-
Notifications
You must be signed in to change notification settings - Fork 0
Single Sign On
Authenticating users against an external identity provider — OIDC or LDAP/Active Directory — instead of local IRIS accounts.
SSO is configured only in .env. There is no GUI for it. If you are looking for
OIDC settings under Advanced → Server Settings, they are not there and are not
missing by oversight — see Why SSO is not in the GUI.
SSO replaces the login method. Multi-factor authentication is a separate feature, toggled in the interface, and is documented in Multi-Factor Authentication. Note that OIDC logins bypass IRIS MFA entirely — with SSO you enforce a second factor at your identity provider.
One setting selects the mechanism, read at process start:
IRIS_AUTHENTICATION_TYPE=local # local | ldap | oidc | oidc_proxy| Value | What it does |
|---|---|
local |
Username and password checked against the IRIS database. The default. |
ldap |
Password checked by binding to an LDAP/AD server. |
oidc |
Full OIDC authorization-code flow — iris-ng redirects to your IdP. This is normal SSO. |
oidc_proxy |
For deployments already behind an authenticating reverse proxy (oauth2-proxy). iris-ng trusts the proxy and introspects its token. |
AuthenticationType in configuration.py is an enum listing only local and
oidc_proxy. It is vestigial — the real dispatch is a string comparison, and all four
values above work.
Configuration is read in this order: Azure Key Vault → environment variable →
config.ini. Each setting belongs to a section, and the environment variable name is
<SECTION>_<OPTION>.
This matters because it is easy to get wrong, and a misnamed variable is silently ignored — it falls through to the default rather than raising:
| Section / option | Environment variable |
|---|---|
OIDC / ISSUER_URL
|
OIDC_ISSUER_URL |
LDAP / SERVER
|
LDAP_SERVER |
IRIS / AUTHENTICATION_LOCAL_FALLBACK
|
IRIS_AUTHENTICATION_LOCAL_FALLBACK |
IRIS / NEW_USERS_DEFAULT_GROUP
|
IRIS_NEW_USERS_DEFAULT_GROUP |
IRIS / AUTHENTICATION_CREATE_USER_IF_NOT_EXIST
|
IRIS_AUTHENTICATION_CREATE_USER_IF_NOT_EXIST |
The upstream DFIR-IRIS documentation writes the fallback setting as
AUTHENTICATION_LOCAL_FALLBACK, without theIRIS_prefix. That name does not work — the loader looks forIRIS_AUTHENTICATION_LOCAL_FALLBACK.
IRIS_AUTHENTICATION_LOCAL_FALLBACK (default True) keeps the local username/password
form available when the external provider fails or does not recognise the account.
Leave it enabled until SSO is proven working. With it set to False and
oidc, /login redirects straight to the IdP, so a broken IdP configuration means
nobody can log in — including the administrator who would fix it. Because the setting
lives in .env rather than the database, recovery is always possible without being
logged in: edit the file and recreate the container.
Create a confidential client (web application) with the authorization-code flow.
The redirect URI is built from the request host, so it is your instance's external URL
plus /oidc-authorize:
https://iris.example.com/oidc-authorize
Register that exact value. The login entry point is /oidc-login.
IRIS_AUTHENTICATION_TYPE=oidc
OIDC_ISSUER_URL=https://idp.example.com/realms/dfir
OIDC_CLIENT_ID=iris-ng
OIDC_CLIENT_SECRET=<client secret>
# Optional — override only if your IdP does not publish them at the issuer
OIDC_AUTH_ENDPOINT=
OIDC_TOKEN_ENDPOINT=
OIDC_END_SESSION_ENDPOINT=
# Optional — defaults shown
OIDC_SCOPES=openid email profile
OIDC_MAPPING_USERNAME=preferred_username
OIDC_MAPPING_EMAIL=email
# Keep the local login form available while you test
IRIS_AUTHENTICATION_LOCAL_FALLBACK=True
# Create IRIS accounts for IdP users on first login
IRIS_AUTHENTICATION_CREATE_USER_IF_NOT_EXIST=TrueApply with a recreate, not a restart — docker restart does not re-read env_file:
docker compose -f docker-compose.dev.yml up -d --force-recreate --no-deps app worker ai_workerConfirm what the app actually parsed:
docker logs iriswebapp_app 2>&1 | grep -i "Authentication mechanism\|local fallback\|Create user"Two claims are read from the ID token, each falling back to the other if absent:
-
login —
OIDC_MAPPING_USERNAME, else the email claim -
display name —
OIDC_MAPPING_EMAIL, else the username claim
The resulting login is matched against the existing IRIS user column. An account
created locally with the same login is adopted rather than duplicated, which is how you
migrate existing analysts onto SSO without losing case attribution.
preferred_username suits Keycloak. Entra ID (Azure AD) does not emit it by default —
use OIDC_MAPPING_USERNAME=email, or add an optional claim in the app registration.
This is the step people miss. With IRIS_AUTHENTICATION_CREATE_USER_IF_NOT_EXIST=True,
a first-time IdP user gets an IRIS account created automatically — added to organisation 1,
with a random unusable password, and no group.
Default access in IRIS-NG is deny_all, so that user logs in successfully and then sees
nothing at all: no cases, an empty dashboard. It reads like a broken install rather than
a permissions gap.
IRIS_NEW_USERS_DEFAULT_GROUP (default Analysts) does not help here — it is
applied only on the LDAP provisioning path, not the OIDC one. After a user's first
login, assign a group under Advanced → Access Control → Users.
If you would rather not have surprise accounts appear, set
IRIS_AUTHENTICATION_CREATE_USER_IF_NOT_EXIST=False. Unknown users are then rejected
with User not found in IRIS, and you create accounts ahead of time with logins that
match the IdP claim.
Use oidc_proxy only when something in front of iris-ng (oauth2-proxy, for example) has
already authenticated the request:
IRIS_AUTHENTICATION_TYPE=oidc_proxy
OIDC_IRIS_DISCOVERY_URL=https://idp.example.com/realms/dfir/.well-known/openid-configuration
OIDC_IRIS_CLIENT_ID=iris-ng
OIDC_IRIS_CLIENT_SECRET=<client secret>
OIDC_IRIS_ADMIN_ROLE_NAME=iris-admin
OIDC_IRIS_INIT_ADMINISTRATOR_EMAIL=admin@example.com
OIDC_IRIS_AUDIENCE=
OIDC_IRIS_TOKEN_VERIFY_MODE=signatureNote the distinct OIDC_IRIS_* names — this mode does not reuse the OIDC_* names above.
This mode fetches the discovery URL at startup and calls exit(0) if that fails. The
container stops rather than starting with degraded auth. If the app exits immediately
after enabling oidc_proxy, check the log for OIDC ERROR before suspecting anything
else — an unreachable IdP or an untrusted TLS chain both land here. Set TLS_ROOT_CA to
a CA bundle path if your IdP uses an internal CA.
IRIS_AUTHENTICATION_TYPE=ldap
LDAP_SERVER=dc01.example.com
LDAP_PORT=636
LDAP_AUTHENTICATION_TYPE=SIMPLE # or NTLM
LDAP_USER_PREFIX=uid=
LDAP_USER_SUFFIX=ou=people,dc=example,dc=com
LDAP_USE_SSL=True
LDAP_VALIDATE_CERTIFICATE=True
LDAP_TLS_VERSION=1.2 # 1.0 | 1.1 | 1.2 only
IRIS_AUTHENTICATION_LOCAL_FALLBACK=TrueThe bind DN is assembled as <USER_PREFIX><username>,<USER_SUFFIX>. With
LDAP_AUTHENTICATION_TYPE=NTLM the username is passed through unmodified, so use
DOMAIN\user form and leave the prefix and suffix empty.
LDAP_TLS_VERSION accepts only 1.0, 1.1 or 1.2 — anything else raises at startup.
There is no TLS 1.3 option.
When LDAP_USE_SSL=True, these are resolved relative to certificates/ldap/ inside
the container, and each is checked for existence at startup:
LDAP_SERVER_CERTIFICATE=ldap-server.pem
LDAP_CA_CERTIFICATE=ca.pem
LDAP_PRIVATE_KEY=client-key.pem
LDAP_PRIVATE_KEY_PASSWORD=
LDAP_CUSTOM_TLS_CONFIG=TrueGiving an absolute path fails: the app looks for
certificates/ldap/<the whole string you provided>. Mount the files into
certificates/ldap/ and reference them by bare filename.
To create IRIS accounts for directory users on first login, these are required and are validated at startup:
IRIS_AUTHENTICATION_CREATE_USER_IF_NOT_EXIST=True
LDAP_SEARCH_DN=ou=people,dc=example,dc=com
LDAP_ATTRIBUTE_IDENTIFIER=uid # sAMAccountName on AD
LDAP_ATTRIBUTE_DISPLAY_NAME=displayName # optional
LDAP_ATTRIBUTE_MAIL=mail # optional
IRIS_NEW_USERS_DEFAULT_GROUP=AnalystsUnlike OIDC, the LDAP path does put new users in IRIS_NEW_USERS_DEFAULT_GROUP, so
they arrive with working access. If LDAP_ATTRIBUTE_MAIL is unset, the address is
synthesised as <login>@ldap to satisfy the uniqueness constraint.
LDAP logins are not exempt from IRIS MFA — the two compose, and enrolment confirms the user's password against the directory. See Multi-Factor Authentication.
The MFA toggle is a database column, so it can live on the settings page. The SSO settings cannot, for three reasons:
- They are read at module import, before the database connection exists — the same file supplies the Postgres credentials used to build that connection.
-
oidc_proxyperforms network I/O at import time, fetching the discovery document before the application starts. -
They include secrets. The server-settings model is serialised by its schema and
returned by the settings endpoint, so an IdP client secret stored there would be
readable through the API. This is the same reasoning that keeps
SECRET_KEYin a separate table.
There is also a safety argument for leaving at least the authentication type in a file: a bad auth configuration saved through the browser can lock out every account, and a file-based setting can always be fixed without logging in.
| Symptom | Cause |
|---|---|
App exits right after enabling oidc_proxy
|
Discovery URL unreachable or untrusted TLS. configuration.py calls exit(0) on failure. docker logs iriswebapp_app | grep "OIDC ERROR". |
| SSO login works, user sees no cases | Auto-provisioned OIDC user has no group. Assign one under Access Control → Users. |
User not found in IRIS after IdP login |
IRIS_AUTHENTICATION_CREATE_USER_IF_NOT_EXIST is false, or the username claim does not match the IRIS login. |
User not active in IRIS |
The account exists but is disabled in IRIS. The IdP does not re-enable it. |
| Setting appears ignored | Wrong variable name. The pattern is <SECTION>_<OPTION> — note IRIS_AUTHENTICATION_LOCAL_FALLBACK carries the prefix. A misnamed variable falls through to the default silently. |
.env edit had no effect |
docker restart does not re-read env_file. Use up -d --force-recreate --no-deps app worker ai_worker. |
Unable to read LDAP certificate file |
The value must be a bare filename resolved under certificates/ldap/, not an absolute path. |
Unsupported LDAP TLS version |
Only 1.0, 1.1, 1.2 are accepted. |
| MFA prompt never appears for SSO users | Expected — OIDC logins skip MFA. Enforce it at the IdP. |
Check what the application actually parsed at startup:
docker logs iriswebapp_app 2>&1 | grep -iE "Authentication mechanism|local fallback|Create user during"- Multi-Factor Authentication — TOTP, enrolment, recovery
- Security — hardening checklist and review history
- TLS Certificates — serving iris-ng over your own certificate
- Getting Started — installation and first administrator account