Understanding Password Policy with Keycloak and LDAP : both Keycloak and LDAP servers provide password policy support.

This article discusses keycloak and Ldap password policies and what is the best route to choose when performing Keycloak/LDAP integration.

The end user should either choose Keycloak Password Policy or LDAP password Policy.

Using a mix of both should be totally ruled out.

1) Using Keycloak password policy

https://www.keycloak.org/docs/latest/server_admin/index.html#_password-policies

1.1) keycloak password policy at realm level

Keycloak password Policy has to be configured at the realm level

1.2) keycloak password policy types

Keycloak defines the following policy types (cf screenshot below) with configurable values, but none of them is enforcedDigits

  • The number of digits required to be in the password string.

Lowercase Characters

  • The number of lower case letters required to be in the password string.

Uppercase Characters

  • The number of upper case letters required to be in the password string.

Special Characters

  • The number of special characters like ‘?!#%$’ required to be in the password string.

Not Username

  • When set, the password is not allowed to be the same as the username.

Regular Expression

  • Define one or more Perl regular expression patterns that passwords must match.

Expire Password

  • The number of days for which the password is valid. After the number of days has expired, the user is required to change their password.

Not Recently Used

  • This policy saves a history of previous passwords. The number of old passwords stored is configurable. When a user changes their password they cannot use any stored passwords.

Password Blacklist

Understanding Password Policy  with Keycloak and LDAP
1.3) When shall keycloak password policy be used ?

When keycloak password policy is used:

  • The password policy is enforced/applies to all the user of the realm
  • When a user within the realm can originate from different origins (different user federation, identity providers), defining a common password policy provides a unified view of the users with all having/sharing the same password policy.
1.4) Keycloak password policy main limitations

The main limitations of keycloak password policy are:

  • No account control mecanism
  • granularity which applies to the realm

Those main keycloak password policy limitations are overcome when controlling the password policy at LDAP level.

2) Using LDAP Password policy with keycloak

2.1) LDAP password policy definition

LDAP password policy is defined by Password Policy for LDAP Directories (draft-behera-ldap-password-policy-10.txt)

https://tools.ietf.org/html/draft-behera-ldap-password-policy-10

2.2) Configuring LDAP password policy

The configuration of an LDAP password policy s outside the scope of this document, and specific is specific to each LDAP provider

2.3) Keycloak integration with LDAP
  • Users can be can be synchronized/ imported within Keycloak
    (all the attributes mapped, but the password)
  • User bind authentication is always done against the LDAP
2.4) LDAP errors within keycloak (Default)

By default, when an error is generated at the ldap level, keycloak reports “Invalid credentials”.
There is no customization done (but windows) to make the distinguo between the different errors caes

  • Invalid credentials at keycloak level can correspond to:
    • Username or password invalid
    • account lockout
    • password expired
2.5) Ldap Errors handling within keycloak for Windows

Keycloak defines a class to define a Microsoft AD mapper to handle error codes:

When this mapper is enabled, Windows ldap errors messages are intercepted by this corresponding keycloak with the appropriate processing for error handling

AD error code



The AD-specific error code is the one after « data » and before « vece » or « v893 » in the actual error string returned to the binding process

525 user not found 52e invalid credentials
530 not permitted to logon at this time
531 not permitted to logon at this workstation
532 password expired
533
534 account disabled
The user has not been granted the requested logon type at this machine
701 account expired
773 user must reset password
775 user account locked

Keycloak source code to handle MS-AD errors

https://github.com/keycloak/keycloak/blob/master/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/msadlds/MSADLDSUserAccountControlStorageMapper.java

protected boolean processAuthErrorCode(String errorCode, UserModel user) {
        logger.debugf("MSAD LDS Error code is '%s' after failed LDAP login of user '%s'", errorCode, user.getUsername());

        if (ldapProvider.getEditMode() == UserStorageProvider.EditMode.WRITABLE) {
            if (errorCode.equals("532") || errorCode.equals("773")) {
                // User needs to change his MSAD password. Allow him to login, but add UPDATE_PASSWORD required action
                if (!user.getRequiredActions().contains(UserModel.RequiredAction.UPDATE_PASSWORD.name())) {
                    user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
                }
                return true;
            } else if (errorCode.equals("533")) {
                // User is disabled in MSAD LDS. Set him to disabled in KC as well
                if (user.isEnabled()) {
                    user.setEnabled(false);
                }
                return true;
            } else if (errorCode.equals("775")) {
                logger.warnf("Locked user '%s' attempt to login", user.getUsername());
            }
        }

        return false;
}

Interesting to be noticed that for windows, this corresponding piece of code is able to handle Password reset. The password reset is handled through a specific UseraccessControl, which is UPDATE_PASSWORD.

2.6) Ldap Errors handling within keycloak but windows

As mentioned previously, Keycloak does not implement error handling for other Ldap providers but LDAP MS-AD.

If there was a need to be able to have a specific LDAP error keycloak handing, the user should develop a SPI in the same as what been done with windows (MSADLDSUserAccountControlStorageMapper)

2.7) Password Expiry Date / Updating Password

A point to be careful with is password Expiration, as there is no mechanism, which can set user required action at keycloak level to UpdatePassword.

Another possible way to handle the password expiration date, if specific SPI handling LDAP errors is not developed would be to have an external batch running daily comparing currentDate with passwordExpiryDate and setting the user required action to UpdatePassword if necessary.

3) User LDAP Account Lockout / Keycloak message

After a number of unsuccessful bind attempts Ldap account is locked.
It is possible to define parameters such as

  • Number of possible attempts before locking the account (3 attempts for example)
  • Duration of the lockout (1 day for example)

At keycloak level, is only reported the error message invalid user credentials.

Having the same message reported “ invalid user credentials” for user lockout or invalid credentials is something very common, as it doesn’t provide any to hint to potential attackers. Like this they can’t even guess that the account is locked and for how long.

4) Migration and Provisionning of users to a LDAP DataBase

One of the situation often seen, is that the customer wants to migrate transparently existing users to an LDAP, where the users can be in RDMS , old LDAP. Often the password storage scheme used whithin the old system can be very weak (MD5, SHA1 …)

Thanks to keycloak, it is possible to:

  • migrate transparently the user with their old password
  • force user to reset their password upon first authentication
  • new password (created) will be stored with a stronger password scheme (SSHA2 …)

To achieve such a result, keycloak should be configured to force password update as required upon user creation. The new LDAP should also be configured with strong password storage scheme (SSHA2 for example).

Understanding Password Policy  with Keycloak and LDAP
janua
Les derniers articles par janua (tout voir)