# The Flask secret key for cookies. You MUST change this. SECRET_KEY = "change me before you go in production" # The interface on which canaille will be served # SERVER_NAME = "auth.mydomain.example" # PREFERRED_URL_SCHEME = "https" [CANAILLE] # Your organization name. # NAME = "Canaille" # You can display a logo to be recognized on login screens # LOGO = "/static/img/canaille-head.webp" # Your favicon. If unset the LOGO will be used. # FAVICON = "/static/img/canaille-c.webp" # The name of a theme in the 'theme' directory, or a path path # to a theme. Defaults to 'default'. Theming is done with # https://github.com/tktech/flask-themer # THEME = "default" # If unset, language is detected # LANGUAGE = "en" # The timezone in which datetimes will be displayed to the users. # If unset, the server timezone will be used. # TIMEZONE = UTC # If you have a sentry instance, you can set its dsn here: # SENTRY_DSN = "https://examplePublicKey@o0.ingest.sentry.io/0" # Enables javascript to smooth the user experience # JAVASCRIPT = true # Accelerates webpages with async requests # HTMX = true # If EMAIL_CONFIRMATION is set to 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 ENABLE_REGISTRATION is 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 HIDE_INVALID_LOGINS is set to true (the default), when a user # tries 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 HIDE_INVALID_LOGINS is set to 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 ENABLE_PASSWORD_RECOVERY is false, then users cannot ask for a password # recovery link by email. This option is true by default. # ENABLE_PASSWORD_RECOVERY = true # If ENABLE_INTRUDER_LOCKOUT is true, then users will have to wait for an # increasingly long time between each failed login attempt. This option is false by default. # 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. # Two options are supported : "TOTP" for time one-time password, # and "HOTP" for HMAC-based one-time password. # This option is deactivated by default. # OTP_METHOD = "TOTP" # If EMAIL_OTP is true, then users will need to authenticate themselves # via a one-time password sent to their primary email address. # This option is false by default. # EMAIL_OTP = false # If SMS_OTP is true, then users will need to authenticate themselves # via a one-time password sent to their primary phone number. # This option is false by default. # SMS_OTP = false # The validity duration of registration invitations, in seconds. # Defaults to 2 days # INVITATION_EXPIRATION = 172800 # LOGGING configures the logging output: # - if unset, everything is logged in the standard output # the log level is debug if DEBUG is True, else this is INFO # - if this is a dictionary, it is passed to the python dictConfig method: # https://docs.python.org/3/library/logging.config.html#logging.config.dictConfig # - if this is a string, it is passed to the python fileConfig method # https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig # Minimum length for user password. # It is possible not to set a minimum, by entering None or 0. # MIN_PASSWORD_LENGTH = 8 # Maximum length for user password. # There is a technical limit with passlib used by sql database of 4096 # characters. If the value entered is 0 or 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 = "admin@mydomain.example" # If :py:data:`True`, Canaille will check for password compromise on HIBP # every time a new password is register. # (https://haveibeenpwned.com/) # ENABLE_PASSWORD_COMPROMISSION_CHECK = False # Have i been pwned api url for compromission checks. # This url should not be modified. # API_URL_HIBP = "https://api.pwnedpasswords.com/range/" # [CANAILLE_SQL] # The SQL database connection string # Details on https://docs.sqlalchemy.org/en/20/core/engines.html # DATABASE_URI = "postgresql://user:password@localhost/database" # [CANAILLE_LDAP] # URI = "ldap://ldap" # ROOT_DN = "dc=mydomain,dc=tld" # BIND_DN = "cn=admin,dc=mydomain,dc=tld" # BIND_PW = "admin" # TIMEOUT = # Where to search for users? # USER_BASE = "ou=users,dc=mydomain,dc=tld" # The object class to use for creating new users # Note : If you plan on using TOTP/HOTP authentication, use : USER_CLASS = ["inetOrgPerson", "oathHOTPToken"] # USER_CLASS = "inetOrgPerson" # The attribute to identify an object in the User dn. # USER_RDN = "uid" # Filter to match users on sign in. Jinja syntax is supported # and a `login` variable is available containing the value # passed in the login field. # USER_FILTER = "(|(uid={{ login }})(mail={{ login }}))" # Where to search for groups? # GROUP_BASE = "ou=groups,dc=mydomain,dc=tld" # The object class to use for creating new groups # GROUP_CLASS = "groupOfNames" # The attribute to identify an object in the User dn. # GROUP_RDN = "cn" # The attribute to use to identify a group # GROUP_NAME_ATTRIBUTE = "cn" [CANAILLE.ACL] # 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' parameter can be: # - absent, 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'} # # The 'PERMISSIONS' parameter that is an list of items the users in the access # control will be able to manage. 'PERMISSIONS' is optional. Values can be: # - "edit_self" to allow users to edit their own profile # - "use_oidc" to allow OpenID Connect authentication # - "manage_oidc" to allow OpenID Connect client managements # - "manage_users" to allow other users management # - "manage_groups" to allow group edition and creation # - "delete_account" allows a user to delete his own account. If used with # manage_users, the user can delete any account # - "impersonate_users" to allow a user to take the identity of another user # # The 'READ' and 'WRITE' attributes are the LDAP attributes of the user # object that users will be able to read and/or write. [CANAILLE.ACL.DEFAULT] PERMISSIONS = ["edit_self", "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", ] [CANAILLE.ACL.ADMIN] FILTER = {groups = "admins"} PERMISSIONS = [ "manage_users", "manage_groups", "manage_oidc", "delete_account", "impersonate_users", ] WRITE = [ "groups", "lock_date", ] [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 = [ # "xxxxxxx-yyyyyyy-zzzzzz", # ] # REQUIRE_NONCE force the nonce exchange during the authentication flows. # This adds security but may not be supported by all clients. # REQUIRE_NONCE = true [CANAILLE_OIDC.JWT] # PRIVATE_KEY and PUBLIC_KEY are the private and # the public key. You can generate a RSA keypair with: # openssl genrsa -out private.pem 4096 # openssl rsa -in private.pem -pubout -outform PEM -out public.pem # If the variables are unset, and debug mode is enabled, # a in-memory keypair will be used. # PRIVATE_KEY = "..." # PUBLIC_KEY = "..." # The URI of the identity provider # ISS = "https://auth.mydomain.example" # The key type parameter # KTY = "RSA" # The key algorithm # ALG = "RS256" # The time the JWT will be valid, in seconds # EXP = 3600 [CANAILLE_OIDC.JWT.MAPPING] # Mapping between JWT fields and LDAP attributes from your # User objectClass. # {attribute} will be replaced by the user ldap attribute value. # Default values fits inetOrgPerson. # SUB = "{{ user.user_name }}" # NAME = "{{ user.formatted_name }}" # PHONE_NUMBER = "{{ user.phone_numbers[0] }}" # EMAIL = "{{ user.preferred_email }}" # GIVEN_NAME = "{{ user.given_name }}" # FAMILY_NAME = "{{ user.family_name }}" # PREFERRED_USERNAME = "{{ user.display_name }}" # LOCALE = "{{ user.preferred_language }}" # ADDRESS = "{{ user.formatted_address }}" # PICTURE = "{% if user.photo %}{{ url_for('core.account.photo', user=user, field='photo', _external=True) }}{% endif %}" # WEBSITE = "{{ user.profile_url }}" # The SMTP server options. If not set, mail related features such as # user invitations, and password reset emails, will be disabled. [CANAILLE.SMTP] # HOST = "localhost" # PORT = 25 # TLS = false # SSL = false # LOGIN = "" # PASSWORD = "" # FROM_ADDR = "admin@mydomain.example" # The SMPP server options. If not set, sms related features such as # sms one-time passwords will be disabled. [CANAILLE.SMPP] # HOST = "localhost" # PORT = 2775 # LOGIN = "" # PASSWORD = ""