Configuration

Load the configuration

Canaille can be configured either by a environment variables, environment file, or by a configuration file.

Configuration file

CONFIG

The configuration can be written in toml configuration file which path is passed in the CONFIG environment variable.

config.toml
SECRET_KEY = "very-secret"

[CANAILLE]
NAME = "My organization"

[CANAILLE_SQL]
DATABASE_URI = "postgresql://user:password@localhost/database"
...

You can have a look at the example file for inspiration.

Environment variables

In addition, parameters that have not been set in the configuration file can be read from environment variables. The way environment variables are parsed can be read from the pydantic-settings documentation.

Tip

For environment vars, the separator between sections and variables is a double underscore: __. For instance, the NAME var in the CANAILLE section shown above is CANAILLE__NAME.

Environment file

Any environment variable can also be written in an environment file, which path should be passed in the ENV_FILE environment variable. For instance, set ENV_FILE=.env to load a .env file.

.env
SECRET_KEY="very-secret"
CANAILLE__NAME="My organization"
CANAILLE_SQL__DATABASE_URI="postgresql://user:password@localhost/database"

Configuration methods priority

If a same configuration option is defined by different ways, here is how Canaille will choose which one to use:

  • environment vars have priority over the environment file and the configuration file;

  • environment file will have priority over the configuration file;

  • if no configuration method is used, Canaille will look for a canaille.toml configuration file in the current working directory.

Parameters

canaille.app.configuration.RootSettings[source]

The top-level namespace contains the configuration settings unrelated to Canaille.

The configuration parameters from the following libraries can be used:

config.toml
SECRET_KEY = "very-secret"
SERVER_NAME = "auth.mydomain.example"
PREFERRED_URL_SCHEME = "https"
DEBUG = false

[CANAILLE]
NAME = "My organization"
...
CACHE_TYPE: str = 'SimpleCache'

The cache type.

The default SimpleCache is a lightweight in-memory cache. See the Flask-Caching documentation for further details.

DEBUG: bool = False

The Flask DEBUG configuration setting.

This enables debug options.

Danger

This is useful for development but should be absolutely avoided in production environments.

PREFERRED_URL_SCHEME: str = 'https'

The Flask PREFERRED_URL_SCHEME configuration setting.

This sets the url scheme by which canaille will be served.

SECRET_KEY: str | None = None

The Flask SECRET_KEY configuration setting.

You MUST set a value before deploying in production.

SERVER_NAME: str | None = None

The Flask SERVER_NAME configuration setting.

This sets domain name on which canaille will be served.

canaille.core.configuration.CoreSettings[source]

The settings from the CANAILLE namespace.

Those are all the configuration parameters that controls the behavior of Canaille.

ACL: dict[str, ACLSettings] | None = {'DEFAULT': ACLSettings(PERMISSIONS=[<Permission.EDIT_SELF: 'edit_self'>, <Permission.USE_OIDC: 'use_oidc'>], READ=['user_name', 'groups', 'lock_date'], WRITE=['photo', 'given_name', 'family_name', 'display_name', 'password', 'phone_numbers', 'emails', 'profile_url', 'formatted_address', 'street', 'postal_code', 'locality', 'region', 'preferred_language', 'employee_number', 'department', 'title', 'organization'], FILTER=None)}

Mapping of permission groups. See ACLSettings for more details.

The ACL name can be freely chosen. For example:

[CANAILLE.ACL.DEFAULT]
PERMISSIONS = ["edit_self", "use_oidc"]
READ = ["user_name", "groups"]
WRITE = ["given_name", "family_name"]

[CANAILLE.ACL.ADMIN]
WRITE = ["user_name", "groups"]
ADMIN_EMAIL: str | None = None

Administration email contact.

In certain special cases (example : questioning about password corruption), it is necessary to provide an administration contact email.

EMAIL_CONFIRMATION: bool = True

If True, users will need to click on a confirmation link sent by email when they want to add a new email.

By default, this is true if SMTP is configured, else this is false. If explicitly set to true and SMTP is disabled, the email field will be read-only.

EMAIL_OTP: bool = False

If True, then users will need to authenticate themselves via a one-time password sent to their primary email address.

ENABLE_INTRUDER_LOCKOUT: bool = False

If True, then users will have to wait for an increasingly long time between each failed login attempt.

ENABLE_PASSWORD_COMPROMISSION_CHECK: bool = False

If True, Canaille will check if passwords appears in compromission databases such as HIBP when users choose a new one.

ENABLE_PASSWORD_RECOVERY: bool = True

If False, then users cannot ask for a password recovery link by email.

ENABLE_REGISTRATION: bool = False

If True, then users can freely create an account at this instance.

If email verification is available, users must confirm their email before the account is created.

FAVICON: str | None = None

You favicon.

If unset and LOGO is set, then the logo will be used.

HIDE_INVALID_LOGINS: bool = True

If True, when users try to sign in with an invalid login, a message is shown indicating that the password is wrong, but does not give a clue whether the login exists or not.

If False, when a user tries to sign in with an invalid login, a message is shown indicating that the login does not exist.

HTMX: bool = True

Accelerates webpages loading with asynchronous requests.

INVITATION_EXPIRATION: int = 172800

The validity duration of registration invitations, in seconds.

Defaults to 2 days.

JAVASCRIPT: bool = True

Enables Javascript to smooth the user experience.

LANGUAGE: str | None = None

If a language code is set, it will be used for every user.

If unset, the language is guessed according to the users browser.

LOGGING: str | dict | None = None

Configures the logging output using the python logging configuration format:

For example:

[CANAILLE.LOGGING]
version = 1
formatters.default.format = "[%(asctime)s] - $(ip)s - %(levelname)s in %(module)s: %(message)s"
root = {level = "INFO", handlers = ["canaille"]}

[CANAILLE.LOGGING.handlers.canaille]
class = "logging.handlers.WatchedFileHandler"
filename = "/var/log/canaille.log"
formatter = "default"
LOGIN_ATTRIBUTES: list[str] | dict[str, str] = ['user_name', 'emails']

The attributes users can use to identify themselves, generally a combination of user_name, emails and phone_numbers.

  • When this is a list, it expects the attribute names to match.

  • When this is a dict, keys are expected to be the attribute names to match, and values are a Jinja string with a login variable available. This can be used to tune the user input, and for example remove a domain name.

LOGIN_ATTRIBUTES = ["user_name", "emails"]
LOGIN_ATTRIBUTES = {user_name = "{{ login | replace('@example.org', '') }}", emails = "{{ login }}"}

The logo of your organization, this is useful to make your organization recognizable on login screens.

MAX_PASSWORD_LENGTH: int = 1000

User password maximum length.

Note

There is a technical limit of 4096 characters with the SQL backend. If the value is 0, None, or greater than 4096, then 4096 will be retained.

MIN_PASSWORD_LENGTH: int = 8

User password minimum length.

If 0 or None, password won’t have a minimum length.

NAME: str = 'Canaille'

Your organization name.

Used for display purpose.

OTP_METHOD: OTPMethod | None = None

If OTP_METHOD is defined, then users will need to authenticate themselves using a one-time password (OTP) via an authenticator app. If set to TOTP, the application will use time one-time passwords, If set to HOTP, the application will use HMAC-based one-time passwords.

PASSWORD_COMPROMISSION_CHECK_API_URL: str = 'https://api.pwnedpasswords.com/range/'

Have i been pwned api url for compromission checks.

PASSWORD_LIFETIME: str | None = None

Password validity duration.

If set, user passwords expire after this delay. Users are forced to change their password when the lifetime of the password is over. The duration value is expressed in ISO8601 format. For example, delay of 60 days is written “P60D”.

SENTRY_DSN: str | None = None

A Sentry DSN to collect the exceptions.

This is useful for tracking errors in test and production environments.

SMPP: SMPPSettings | None = None

The settings related to SMPP configuration.

If unset, sms-related features like sms one-time passwords won’t be enabled.

SMS_OTP: bool = False

If True, then users will need to authenticate themselves via a one-time password sent to their primary phone number.

SMTP: SMTPSettings | None = None

The settings related to SMTP and mail configuration.

If unset, mail-related features like password recovery won’t be enabled.

THEME: Annotated[Path, PathType(path_type=dir)] | None = None

A path to a theme.

See the theming documentation for more details.

TIMEZONE: str | None = None

The timezone in which datetimes will be displayed to the users (e.g. CEST).

If unset, the server timezone will be used.

canaille.core.configuration.SMTPSettings[source]

The SMTP configuration. Belong in the CANAILLE.SMTP namespace.

If unset, mail related features will be disabled, such as mail verification or password recovery emails.

By default, Canaille will try to send mails from localhost without authentication.

FROM_ADDR: str | None = None

The sender for Canaille mails.

Some mail provider might require a valid sender address.

HOST: str | None = 'localhost'

The SMTP host.

LOGIN: str | None = None

The SMTP login.

PASSWORD: str | None = None

The SMTP password.

PORT: int | None = 25

The SMTP port.

SSL: bool | None = False

Whether to use SSL to connect to the SMTP server.

TLS: bool | None = False

Whether to use TLS to connect to the SMTP server.

canaille.core.configuration.SMPPSettings[source]

The SMPP configuration. Belong in the CANAILLE.SMPP namespace.

If not set, sms related features such as sms one-time passwords will be disabled.

HOST: str | None = 'localhost'

The SMPP host.

LOGIN: str | None = None

The SMPP login.

PASSWORD: str | None = None

The SMPP password.

PORT: int | None = 2775

The SMPP port. Use 8775 for SMPP over TLS (recommended).

canaille.core.configuration.ACLSettings[source]

Access Control List settings. Belong in the CANAILLE.ACL namespace.

You can define access controls that define what users can do on canaille. An access control consists in a FILTER to match users, a list of PERMISSIONS matched users will be able to perform, and fields users will be able to READ and WRITE. Users matching several filters will cumulate permissions.

FILTER: dict[str, str] | list[dict[str, str]] | None = None

FILTER can be:

  • None, in which case all the users will match this access control

  • a mapping where keys are user attributes name and the values those user attribute values. All the values must be matched for the user to be part of the access control.

  • a list of those mappings. If a user values match at least one mapping, then the user will be part of the access control

Here are some examples:

FILTER = {user_name = 'admin'}
FILTER = [
    {groups = 'admins},
    {groups = 'moderators'},
]
PERMISSIONS: list[Permission] = [Permission.EDIT_SELF, Permission.USE_OIDC]

A list of Permission users in the access control will be able to manage.

For example:

PERMISSIONS = [
    "manage_users",
    "manage_groups",
    "manage_oidc",
    "delete_account",
    "impersonate_users",
]
READ: list[str] = ['user_name', 'groups', 'lock_date']

A list of User attributes that users in the ACL will be able to read.

WRITE: list[str] = ['photo', 'given_name', 'family_name', 'display_name', 'password', 'phone_numbers', 'emails', 'profile_url', 'formatted_address', 'street', 'postal_code', 'locality', 'region', 'preferred_language', 'employee_number', 'department', 'title', 'organization']

A list of User attributes that users in the ACL will be able to edit.

class canaille.core.configuration.Permission(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]

The permissions that can be assigned to users.

The permissions are intended to be used in ACLSettings.

DELETE_ACCOUNT = 'delete_account'

Allows users to delete their account.

If used with MANAGE_USERS, users can delete any account.

EDIT_SELF = 'edit_self'

Allows users to edit their own profile.

IMPERSONATE_USERS = 'impersonate_users'

Allows users to take the identity of another user.

MANAGE_GROUPS = 'manage_groups'

Allows group edition and creation.

MANAGE_OIDC = 'manage_oidc'

Allows OpenID Connect client managements.

MANAGE_USERS = 'manage_users'

Allows other users management.

USE_OIDC = 'use_oidc'

Allows OpenID Connect authentication.

canaille.oidc.configuration.OIDCSettings[source]

OpenID Connect settings.

Belong in the CANAILLE_OIDC namespace.

DYNAMIC_CLIENT_REGISTRATION_OPEN: bool = False

Whether a token is needed for the RFC7591 dynamical client registration.

If True, no token is needed to register a client. If False, dynamical client registration needs a token defined in DYNAMIC_CLIENT_REGISTRATION_TOKENS.

DYNAMIC_CLIENT_REGISTRATION_TOKENS: list[str] | None = None

A list of tokens that can be used for dynamic client registration.

JWT: JWTSettings = JWTSettings(PRIVATE_KEY=None, PUBLIC_KEY=None, ISS=None, KTY='RSA', ALG='RS256', EXP=3600, MAPPING=JWTMappingSettings(SUB='{{ user.user_name }}', NAME='{% if user.formatted_name %}{{ user.formatted_name }}{% endif %}', PHONE_NUMBER='{% if user.phone_numbers %}{{ user.phone_numbers[0] }}{% endif %}', EMAIL='{% if user.preferred_email %}{{ user.preferred_email }}{% endif %}', GIVEN_NAME='{% if user.given_name %}{{ user.given_name }}{% endif %}', FAMILY_NAME='{% if user.family_name %}{{ user.family_name }}{% endif %}', PREFERRED_USERNAME='{% if user.display_name %}{{ user.display_name }}{% endif %}', LOCALE='{% if user.preferred_language %}{{ user.preferred_language }}{% endif %}', ADDRESS='{% if user.formatted_address %}{{ user.formatted_address }}{% endif %}', PICTURE="{% if user.photo %}{{ url_for('core.account.photo', user=user, field='photo', _external=True) }}{% endif %}", WEBSITE='{% if user.profile_url %}{{ user.profile_url }}{% endif %}'))

JSON Web Token settings.

REQUIRE_NONCE: bool = True

Force the nonce exchange during the authentication flows.

This adds security but may not be supported by all clients.

canaille.oidc.configuration.JWTSettings[source]

JSON Web Token settings. Belong in the CANAILLE_OIDC.JWT namespace.

You can generate a RSA keypair with:

openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -pubout -outform PEM -out public.pem
ALG: str = 'RS256'

The key algorithm.

EXP: int = 3600

The time the JWT will be valid, in seconds.

ISS: str | None = None

The URI of the identity provider.

KTY: str = 'RSA'

The key type.

MAPPING: JWTMappingSettings | None = JWTMappingSettings(SUB='{{ user.user_name }}', NAME='{% if user.formatted_name %}{{ user.formatted_name }}{% endif %}', PHONE_NUMBER='{% if user.phone_numbers %}{{ user.phone_numbers[0] }}{% endif %}', EMAIL='{% if user.preferred_email %}{{ user.preferred_email }}{% endif %}', GIVEN_NAME='{% if user.given_name %}{{ user.given_name }}{% endif %}', FAMILY_NAME='{% if user.family_name %}{{ user.family_name }}{% endif %}', PREFERRED_USERNAME='{% if user.display_name %}{{ user.display_name }}{% endif %}', LOCALE='{% if user.preferred_language %}{{ user.preferred_language }}{% endif %}', ADDRESS='{% if user.formatted_address %}{{ user.formatted_address }}{% endif %}', PICTURE="{% if user.photo %}{{ url_for('core.account.photo', user=user, field='photo', _external=True) }}{% endif %}", WEBSITE='{% if user.profile_url %}{{ user.profile_url }}{% endif %}')
PRIVATE_KEY: str | None = None

The private key.

If None and debug mode is enabled, then an in-memory key will be used.

PUBLIC_KEY: str | None = None

The public key.

If None and debug mode is enabled, then an in-memory key will be used.

canaille.oidc.configuration.JWTMappingSettings[source]

Mapping between the user model and the JWT fields.

Fields are evaluated with jinja. A user var is available.

ADDRESS: str | None = '{% if user.formatted_address %}{{ user.formatted_address }}{% endif %}'
EMAIL: str | None = '{% if user.preferred_email %}{{ user.preferred_email }}{% endif %}'
FAMILY_NAME: str | None = '{% if user.family_name %}{{ user.family_name }}{% endif %}'
GIVEN_NAME: str | None = '{% if user.given_name %}{{ user.given_name }}{% endif %}'
LOCALE: str | None = '{% if user.preferred_language %}{{ user.preferred_language }}{% endif %}'
NAME: str | None = '{% if user.formatted_name %}{{ user.formatted_name }}{% endif %}'
PHONE_NUMBER: str | None = '{% if user.phone_numbers %}{{ user.phone_numbers[0] }}{% endif %}'
PICTURE: str | None = "{% if user.photo %}{{ url_for('core.account.photo', user=user, field='photo', _external=True) }}{% endif %}"
PREFERRED_USERNAME: str | None = '{% if user.display_name %}{{ user.display_name }}{% endif %}'
SUB: str | None = '{{ user.user_name }}'
WEBSITE: str | None = '{% if user.profile_url %}{{ user.profile_url }}{% endif %}'
canaille.scim.configuration.SCIMSettings[source]

SCIM settings.

ENABLE_SERVER: bool = True

Whether the SCIM server API is enabled.

When enabled, services plugged to Canaille can update users and groups using the API.

canaille.backends.sql.configuration.SQLSettings[source]

Settings related to the SQL backend.

Belong in the CANAILLE_SQL namespace.

AUTO_MIGRATE: bool = True

Whether to automatically apply database migrations.

If True, database migrations will be automatically applied when Canaille web application is launched. If False, migrations must be applied manually with canaille db upgrade.

Note

When running the CLI, migrations will never be applied.

DATABASE_URI: str [Required]

The SQL server URI. For example:

DATABASE_URI = "postgresql://user:password@localhost/database_name"
PASSWORD_SCHEMES: str = 'pbkdf2_sha512'

Password hashing scheme.

Defines password hashing scheme in SQL database. examples : “mssql2000”, “ldap_salted_sha1”, “pbkdf2_sha512”

canaille.backends.ldap.configuration.LDAPSettings[source]

Settings related to the LDAP backend.

Belong in the CANAILLE_LDAP namespace.

BIND_DN: str = 'cn=admin,dc=example,dc=org'

The LDAP bind DN.

BIND_PW: str = 'admin'

The LDAP bind password.

GROUP_BASE: str [Required]

The LDAP node under which groups will be looked for and saved.

For instance “ou=groups,dc=example,dc=org”.

GROUP_CLASS: str = 'groupOfNames'

The object class to use for creating new groups.

GROUP_NAME_ATTRIBUTE: str = 'cn'

The attribute to use to identify a group.

GROUP_RDN: str = 'cn'

The attribute to identify an object in the Group DN.

ROOT_DN: str = 'dc=example,dc=org'

The LDAP root DN.

TIMEOUT: float = 0.0

The LDAP connection timeout.

URI: str = 'ldap://localhost'

The LDAP server URI.

USER_BASE: str [Required]

The LDAP node under which users will be looked for and saved.

For instance ou=users,dc=example,dc=org.

USER_CLASS: list[str] = ['inetOrgPerson']

The object class to use for creating new users.

USER_RDN: str = 'uid'

The attribute to identify an object in the User DN.

Example file

Here is a configuration file example that can be generated with the canaille config dump command:

config.toml
# The Flask SECRET_KEY configuration setting.
#
# You MUST set a value before deploying in production.
# SECRET_KEY =

# The Flask SERVER_NAME configuration setting.
#
# This sets domain name on which canaille will be served.
# SERVER_NAME =

# The Flask PREFERRED_URL_SCHEME configuration setting.
#
# This sets the url scheme by which canaille will be served.
# PREFERRED_URL_SCHEME = "https"

# The Flask DEBUG configuration setting.
#
# This enables debug options.
#
#     This is useful for development but should be absolutely
#     avoided in production environments.
# DEBUG = false

# The cache type.
#
# The default SimpleCache is a lightweight in-memory cache. See the Flask-Caching
# documentation for further details.
# CACHE_TYPE = "SimpleCache"

[CANAILLE]
# Your organization name.
#
# Used for display purpose.
# NAME = "Canaille"

# The logo of your organization, this is useful to make your organization
# recognizable on login screens.
# LOGO =

# You favicon.
#
# If unset and LOGO is set, then the logo will be used.
# FAVICON =

# A path to a theme.
#
# See the theming documentation for more details.
# THEME =

# If a language code is set, it will be used for every user.
#
# If unset, the language is guessed according to the users browser.
# LANGUAGE =

# The timezone in which datetimes will be displayed to the users (e.g. CEST).
#
# If unset, the server timezone will be used.
# TIMEZONE =

# A Sentry (https://sentry.io) DSN to collect the exceptions.
#
# This is useful for tracking errors in test and production environments.
# SENTRY_DSN =

# Enables Javascript to smooth the user experience.
# JAVASCRIPT = true

# Accelerates webpages loading with asynchronous requests.
# HTMX = true

# If True, users will need to click on a confirmation link sent by email when they
# want to add a new email.
#
# By default, this is true if SMTP is configured, else this is false. If
# explicitly set to true and SMTP is disabled, the email field will be read-only.
# EMAIL_CONFIRMATION = true

# If True, then users can freely create an account at this instance.
#
# If email verification is available, users must confirm their email before the
# account is created.
# ENABLE_REGISTRATION = false

# If True, when users try to sign in with an invalid login, a message is shown
# indicating that the password is wrong, but does not give a clue whether the
# login exists or not.
#
# If False, when a user tries to sign in with an invalid login, a message is shown
# indicating that the login does not exist.
# HIDE_INVALID_LOGINS = true

# If False, then users cannot ask for a password recovery link by email.
# ENABLE_PASSWORD_RECOVERY = true

# If True, then users will have to wait for an increasingly long time between each
# failed login attempt.
# ENABLE_INTRUDER_LOCKOUT = false

# If OTP_METHOD is defined, then users will need to authenticate themselves using
# a one-time password (OTP) via an authenticator app. If set to TOTP, the
# application will use time one-time passwords, If set to HOTP, the application
# will use HMAC-based one-time passwords.
# OTP_METHOD =

# If True, then users will need to authenticate themselves via a one-time password
# sent to their primary email address.
# EMAIL_OTP = false

# If True, then users will need to authenticate themselves via a one-time password
# sent to their primary phone number.
# SMS_OTP = false

# The validity duration of registration invitations, in seconds.
#
# Defaults to 2 days.
# INVITATION_EXPIRATION = 172800

# User password minimum length.
#
# If 0 or None, password won't have a minimum length.
# MIN_PASSWORD_LENGTH = 8

# User password maximum length.
#
#     There is a technical limit of 4096 characters with the SQL backend.
#     If the value is 0, None, or greater than 4096,
#     then 4096 will be retained.
# MAX_PASSWORD_LENGTH = 1000

# Administration email contact.
#
# In certain special cases (example : questioning about password corruption), it
# is necessary to provide an administration contact email.
# ADMIN_EMAIL =

# If True, Canaille will check if passwords appears in compromission databases
# such as HIBP (https://haveibeenpwned.com) when users choose a new one.
# ENABLE_PASSWORD_COMPROMISSION_CHECK = false

# Have i been pwned api url for compromission checks.
# PASSWORD_COMPROMISSION_CHECK_API_URL = "https://api.pwnedpasswords.com/range/"

# Password validity duration.
#
# If set, user passwords expire after this delay. Users are forced to change their
# password when the lifetime of the password is over. The duration value is
# expressed in ISO8601 format (https://en.wikipedia.org/wiki/ISO_8601#Durations).
# For example, delay of 60 days is written "P60D".
# PASSWORD_LIFETIME =

# Configures the logging output using the python logging configuration format:
#
# - If None, everything is logged in the standard error output.
#   The log level is DEBUG if the DEBUG
#   setting is True, else this is INFO.
# - If this is a dict, it is passed to logging.config.dictConfig:
# - If this is a str, it is expected to be a file path that will be passed
#   to logging.config.fileConfig.
#
# For example:
#
#     [CANAILLE.LOGGING]
#     version = 1
#     formatters.default.format = "[%(asctime)s] - $(ip)s - %(levelname)s in %(module)s: %(message)s"
#     root = {level = "INFO", handlers = ["canaille"]}
#
#     [CANAILLE.LOGGING.handlers.canaille]
#     class = "logging.handlers.WatchedFileHandler"
#     filename = "/var/log/canaille.log"
#     formatter = "default"
# LOGGING =

# The settings related to SMTP and mail configuration.
#
# If unset, mail-related features like password recovery won't be enabled.

[CANAILLE.SMTP]
# The SMTP host.
# HOST = "localhost"

# The SMTP port.
# PORT = 25

# Whether to use TLS to connect to the SMTP server.
# TLS = false

# Whether to use SSL to connect to the SMTP server.
# SSL = false

# The SMTP login.
# LOGIN =

# The SMTP password.
# PASSWORD =

# The sender for Canaille mails.
#
# Some mail provider might require a valid sender address.
# FROM_ADDR =

# The settings related to SMPP configuration.
#
# If unset, sms-related features like sms one-time passwords won't be enabled.

[CANAILLE.SMPP]
# The SMPP host.
# HOST = "localhost"

# The SMPP port. Use 8775 for SMPP over TLS (recommended).
# PORT = 2775

# The SMPP login.
# LOGIN =

# The SMPP password.
# PASSWORD =

[CANAILLE_SQL]
# The SQL server URI. For example:
#
#     DATABASE_URI = "postgresql://user:password@localhost/database_name"
# DATABASE_URI =
DATABASE_URI = "sqlite:///canaille.sqlite"

# Password hashing scheme.
#
# Defines password hashing scheme in SQL database. examples : "mssql2000",
# "ldap_salted_sha1", "pbkdf2_sha512"
# PASSWORD_SCHEMES = "pbkdf2_sha512"

# Whether to automatically apply database migrations.
#
# If True, database migrations will be automatically applied when Canaille web
# application is launched. If False, migrations must be applied manually with
# canaille db upgrade.
#
#     When running the CLI, migrations will never be applied.
# AUTO_MIGRATE = true

[CANAILLE_LDAP]
# The LDAP server URI.
# URI = "ldap://localhost"

# The LDAP root DN.
# ROOT_DN = "dc=example,dc=org"

# The LDAP bind DN.
# BIND_DN = "cn=admin,dc=example,dc=org"

# The LDAP bind password.
# BIND_PW = "admin"

# The LDAP connection timeout.
# TIMEOUT = 0.0

# The LDAP node under which users will be looked for and saved.
#
# For instance `ou=users,dc=example,dc=org`.
# USER_BASE =
USER_BASE = "ou=users,dc=example,dc=org"

# The attribute to identify an object in the User DN.
# USER_RDN = "uid"

# The LDAP node under which groups will be looked for and saved.
#
# For instance `"ou=groups,dc=example,dc=org"`.
# GROUP_BASE =
GROUP_BASE = "ou=groups,dc=example,dc=org"

# The object class to use for creating new groups.
# GROUP_CLASS = "groupOfNames"

# The attribute to identify an object in the Group DN.
# GROUP_RDN = "cn"

# The attribute to use to identify a group.
# GROUP_NAME_ATTRIBUTE = "cn"

[CANAILLE_OIDC]
# Whether a token is needed for the RFC7591 dynamical client registration.
#
# If True, no token is needed to register a client. If False, dynamical client
# registration needs a token defined in DYNAMIC_CLIENT_REGISTRATION_TOKENS.
# DYNAMIC_CLIENT_REGISTRATION_OPEN = false

# A list of tokens that can be used for dynamic client registration.
# DYNAMIC_CLIENT_REGISTRATION_TOKENS =

# Force the nonce exchange during the authentication flows.
#
# This adds security but may not be supported by all clients.
# REQUIRE_NONCE = true

# JSON Web Token settings.

[CANAILLE_OIDC.JWT]
# The private key.
#
# If None and debug mode is enabled, then an in-memory key will be used.
# PRIVATE_KEY =

# The public key.
#
# If None and debug mode is enabled, then an in-memory key will be used.
# PUBLIC_KEY =

# The URI of the identity provider.
# ISS =

# The key type.
# KTY = "RSA"

# The key algorithm.
# ALG = "RS256"

# The time the JWT will be valid, in seconds.
# EXP = 3600

[CANAILLE_OIDC.JWT.MAPPING]
# SUB = "{{ user.user_name }}"

# NAME = "{% if user.formatted_name %}{{ user.formatted_name }}{% endif %}"

# PHONE_NUMBER = "{% if user.phone_numbers %}{{ user.phone_numbers[0] }}{% endif %}"

# EMAIL = "{% if user.preferred_email %}{{ user.preferred_email }}{% endif %}"

# GIVEN_NAME = "{% if user.given_name %}{{ user.given_name }}{% endif %}"

# FAMILY_NAME = "{% if user.family_name %}{{ user.family_name }}{% endif %}"

# PREFERRED_USERNAME = "{% if user.display_name %}{{ user.display_name }}{% endif %}"

# LOCALE = "{% if user.preferred_language %}{{ user.preferred_language }}{% endif %}"

# ADDRESS = "{% if user.formatted_address %}{{ user.formatted_address }}{% endif %}"

# PICTURE = "{% if user.photo %}{{ url_for('core.account.photo', user=user, field='photo', _external=True) }}{% endif %}"

# WEBSITE = "{% if user.profile_url %}{{ user.profile_url }}{% endif %}"

[CANAILLE_SCIM]
# Whether the SCIM server API is enabled.
#
# When enabled, services plugged to Canaille can update users and groups using the
# API.
# ENABLE_SERVER = true