Skip to content

LDAP Auth provider

Description

This auth provider checks for user credentials in LDAP, and and then issues an access token.

All requests to backend should be made with passing this access token. If token is expired, then new auth token should be issued.

After successful auth, username is saved to backend database. It is then used for creating audit records for any object change, see changed_by field.

Warning

Until token is valid, no requests will be made to LDAP to check if user exists and not locked. So do not set access token expiration time for too long (e.g. longer than a day).

Strategies

Note

Basic LDAP terminology is explained here: LDAP Overview

There are 2 strategies to check for user in LDAP:

  • Try to call bind request in LDAP with DN (DistinguishedName) and user password. DN is generated using bind_dn_template
  • First try to lookup for user (search request) in LDAP to get user's DN using some query, and then try to call bind using this DN. See lookup settings

By default, lookup strategy is used, as it can find user in a complex LDAP/ActiveDirectory environment. For example:

  • search for user by uid, e.g. (uid={login}) or (sAMAccountName={login})
  • search for user by several attributes, e.g. (|(uid={login})(mail={login}@domain.com))
  • filter for entries, like (&(uid={login})(objectClass=person)
  • filter for users matching a specific group or some other condition, like (&(uid={login})(memberOf=cn=MyPrettyGroup,ou=Groups,dc=mycompany,dc=com))

After user is found in LDAP, its uid_attribute is used for audit records.

Interaction schema

sequenceDiagram
participant "Client"
participant "Backend"
participant "LDAP"

activate "Client"
alt Successful case
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : DN = bind_dn_template(login)
"Backend" ->> "LDAP"  : Call bind(DN, password)
"LDAP" ->> "Backend"  : Successful
"Backend" ->> "Backend" : Check user in internal backend database,\nusername = login
"Backend" ->> "Backend" : Create user if not exist
"Backend" ->> "Client"  : Generate and return access_token

else Wrong credentials | User blocker in LDAP
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : DN = bind_dn_template(login)
"Backend" ->> "LDAP"  : Call bind(DN, password)
"LDAP" --x "Backend"  : Bind error
"Backend" --x "Client"  : 401 Unauthorized

else User is blocked in internal backend database
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : DN = bind_dn_template(login)
"Backend" ->> "LDAP"  : Call bind(DN, password)
"Backend" ->> "Backend" : Check user in internal backend database,\nusername = login
"Backend" --x "Client"  : 404 Not found

else User is deleted in internal backend database
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : DN = bind_dn_template(login)
"Backend" ->> "LDAP"  : Call bind(DN, password)
"LDAP" ->> "Backend"  : Return user info
"Backend" ->> "Backend" : Check user in internal backend database,\nusername = login
"Backend" --x "Client"  : 404 Not found

else LDAP is unavailable
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : DN = bind_dn_template(login)
"Backend" --x "LDAP" : Call bind(DN, password)
"Backend" --x "Client" : 503 Service unavailable
end

alt Successful case
"Client" ->> "Backend"  : access_token
"Backend" ->> "Backend" : Validate token
"Backend" ->> "Backend" : Check user in internal backend database
"Backend" ->> "Backend" : Get data
"Backend" ->> "Client"  : Return data

else Token is expired
"Client" ->> "Backend"  : access_token
"Backend" ->> "Backend" : Validate token
"Backend" --x "Client"  : 401 Unauthorized

else User is blocked
"Client" ->> "Backend"  : access_token
"Backend" ->> "Backend" : Validate token
"Backend" ->> "Backend" : Check user in internal backend database
"Backend" --x "Client"  : 401 Unauthorized

else
"Client" ->> "Backend"  : access_token
"Backend" ->> "Backend" : Validate token
"Backend" ->> "Backend" : Check user in internal backend database
"Backend" --x "Client"  : 404 Not found
end

deactivate "Client"
sequenceDiagram
participant "Client"
participant "Backend"
participant "LDAP"

"Backend" ->  "LDAP" : bind(lookup.username, lookup.password)
activate "LDAP"
Note right of "LDAP" : Open connection \npool for\nsearch queries\n(optional, recommended)

activate "Client"
alt Successful case
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : query = query_template(login)
"Backend" ->> "LDAP" : Call search(query, base_dn, attributes=*)
activate "LDAP"
"LDAP" ->> "Backend" : Return user DN and uid_attribute
deactivate "LDAP"
"Backend" ->> "LDAP"  : Call bind(DN, password)
"LDAP" ->> "Backend"  : Successful
"Backend" ->> "Backend" : Check user in internal backend database,\nusername = uid_attribute from LDAP response
"Backend" ->> "Backend" : Create user if not exist
"Backend" ->> "Client"  : Generate and return access_token

else Wrong credentials | User blocker in LDAP
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : query = query_template(login)
"Backend" ->> "LDAP" : Call search(query, base_dn, attributes=*)
activate "LDAP"
"LDAP" ->> "Backend" : Return user DN and uid_attribute
deactivate "LDAP"
"Backend" ->> "LDAP"  : Call bind(DN, password)
"LDAP" --x "Backend"  : Bind error
"Backend" --x "Client"  : 401 Unauthorized

else User is blocked in internal backend database
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : query = query_template(login)
"Backend" ->> "LDAP" : Call search(query, base_dn, attributes=*)
activate "LDAP"
"LDAP" ->> "Backend" : Return user DN and uid_attribute
deactivate "LDAP"
"Backend" ->> "LDAP"  : Call bind(DN, password)
"LDAP" ->> "Backend"  : Successful
"Backend" ->> "Backend" : Check user in internal backend database,\nusername = uid_attribute from LDAP response
"Backend" --x "Client"  : 404 Not found

else User is deleted in internal backend database
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : query = query_template(login)
"Backend" ->> "LDAP" : Call search(query, base_dn, attributes=*)
activate "LDAP"
"LDAP" ->> "Backend" : Return user DN and uid_attribute
deactivate "LDAP"
"Backend" ->> "LDAP"  : Call bind(DN, password)
"LDAP" ->> "Backend"  : Successful
"Backend" ->> "Backend" : Check user in internal backend database,\nusername = uid_attribute from LDAP response
"Backend" --x "Client"  : 404 Not found

else LDAP is unavailable
"Client" ->> "Backend"  : login + password
"Backend" ->> "Backend" : query = query_template(login)
"Backend" --x "LDAP" : Call search(query, base_dn, attributes=*)
"Backend" --x "Client" : 503 Service unavailable
end

alt Successful case
"Client" ->> "Backend"  : access_token
"Backend" ->> "Backend" : Validate token
"Backend" ->> "Backend" : Check user in internal backend database
"Backend" ->> "Backend" : Get data
"Backend" ->> "Client"  : Return data

else Token is expired
"Client" ->> "Backend"  : access_token
"Backend" ->> "Backend" : Validate token
"Backend" --x "Client"  : 401 Unauthorized

else User is blocked
"Client" ->> "Backend"  : access_token
"Backend" ->> "Backend" : Validate token
"Backend" ->> "Backend" : Check user in internal backend database
"Backend" --x "Client"  : 401 Unauthorized

else User is deleted
"Client" ->> "Backend"  : access_token
"Backend" ->> "Backend" : Validate token
"Backend" ->> "Backend" : Check user in internal backend database
"Backend" --x "Client"  : 404 Not found
end

deactivate "LDAP"
deactivate "Client"

Basic configuration

LDAPAuthProviderSettings

Settings for LDAPAuthProvider.

Examples:

config.yml
auth:
  provider: horizon.backend.providers.auth.ldap.LDAPAuthProvider
  access_token:
    secret_key: secret
  ldap:
    url: ldap://ldap.domain.com:389
    base_dn: ou=users,dc=example,dc=com
    lookup:
      enabled: true
      pool:
        enabled: true
      credentials:
        user: uid=techuser,ou=users,dc=example,dc=com
        password: somepassword

Parameters:

LDAPSettings

Settings related to LDAP interaction.

Examples:

config.yml
auth:
  ldap:
    url: ldap://ldap.domain.com:389
    base_dn: ou=users,dc=example,dc=com
    uid_attribute: sAMAccountName

Parameters:

  • url

    (AnyUrl) –

    LDAP URL to connect to

  • timeout_seconds

    (int | None, default: 10 ) –

    LDAP request timeout, in seconds. None means no timeout

  • auth_mechanism

    (Literal['SIMPLE', 'DIGEST-MD5'], default: 'SIMPLE' ) –

    LDAP auth mechanism, used for bind request

  • base_dn

    (str) –

    Organization DN, e.g. ou=users,dc=example,dc=com

  • uid_attribute

    (str, default: 'uid' ) –

    Attribute containing username.

    Usually uid (LDAP) or sAMAccountName (ActiveDirectory).

  • bind_dn_template

    (str, default: '{uid_attribute}={login},{base_dn}' ) –

    Template for building DN string, used for checking credentials in LDAP. You can pass any DN value supported by LDAP.

    Supported substitution values:

  • lookup

    (LDAPLookupSettings, default: <dynamic> ) –

    LDAP search options

JWTSettings

Settings related to JWT tokens.

Examples:

config.yml
auth:
  access_token:
    secret_key: somesecret
    expire_seconds: 3600  # 1 hour

Parameters:

  • secret_key

    (SecretStr) –

    Secret key for signing JWT tokens.

    Can be any string. It is recommended to generate random value for every application instance.

  • security_algorithm

    (str, default: 'HS256' ) –

    Algorithm used for signing JWT tokens.

    See authlib documentation.

  • expire_seconds

    (int, default: 36000 ) –

    Token expiration time, in seconds

LDAPConnectionPoolSettings

Settings related to LDAP connection pool.

Examples:

config.yml
auth:
  ldap:
    lookup:
      pool:
        enabled: true
        max: 10

Parameters:

  • enabled

    (bool, default: True ) –

    Set to True to enable connection pool

  • initial

    (int, default: 1 ) –

    Initial size of connection pool

  • max

    (int, default: 10 ) –

    Maximum size of connection pool

LDAPLookupSettings

Settings related to LDAP lookup.

Examples:

config.yml
auth:
  ldap:
    lookup:
      enabled: true
      pool:
        enabled: true
      credentials:
        user: uid=techuser,ou=users,dc=example,dc=com
        password: somepassword
      query_template: (uid={login})

Parameters:

  • enabled

    (bool, default: True ) –

    Set to True to enable lookup

  • check_on_startup

    (bool, default: True ) –

    If True, and LDAP is not available during application start, abort application startup

  • pool

    (LDAPConnectionPoolSettings, default: <dynamic> ) –

    LDAP connection pool settings

  • credentials

    (LDAPCredentials | None, default: None ) –

    Credentials used for connecting to LDAP while performing user lookup

  • query_template

    (str, default: '({uid_attribute}={login})' ) –

    LDAP query send in lookup request.

    Usually lookup is performed against attributes uid (LDAP) or sAMAccountName (ActiveDirectory). You can also pass any query string supported by LDAP. See Bonsai documentation.

    Supported substitution values:

  • scope

    (Literal['BASE', 'ONELEVEL', 'SUBTREE'], default: 'ONELEVEL' ) –

    Lookup scope. Use SUBTREE for ActiveDirectory.

    See Bonsai documentation.

LDAPCredentials

LDAP lookup query is executed using this credentials (instead of login and password provided by user).

Examples:

config.yml
auth:
  ldap:
    lookup:
      credentials:
        user: uid=techuser,ou=users,dc=example,dc=com
        password: somepassword

Parameters:

  • user

    (str) –

    DN of user which is used for calling lookup query in LDAP

  • password

    (SecretStr) –

    This user password