As reported in this thread on the dev mailing list when a user changes his/her password the LDAP/MSAD password policies are not used. We notice this because in MSAD we have the password history enabled but we see that users from Keycloak can simply change their password to one of their old passwords without a problem. The MSAD password complexity policy is adhered to by the way but I understand this is a default setting in MSAD used no matter how you change the password.
The reason is that the password change is currently done using the default admin user as bind DN and with a LDAP modification operation using a 'replace attribute'. For the password policies to take effect the password change must be done using the user itself as bind DN and the LDAP modification operation must consist of a remove and an add attribute.
To fix this seems a little tricky as Marek says on the mailing list:
This makes things a bit tricky. Because:
1) Our current model SPI and federation SPI for update credential
doesn't differ between the case when user is updating his credential or
when admin is resetting the credential of user.
2) Also in LDAP both operations are executed under "admin" connection
(user own connection is used just to verify his password).
3) Finally there is no old password available in the
Feel free to create JIRA, but hard to promise when we will be able to
look into it (I am on holiday next week and then we have feature freeze
and won't be able to add new stuff like this).
So if you really want it, you may need to send PR by yourself. The
implementation may require more changes. Some pointers how I would do it
(we may need ACK from other team members to confirm as we are close to
"feature freeze" phase right now until we start on keycloak 2.x
1) Change UserCredentialModel and put new fields "oldValue" with the old
password. Also maybe the boolean field "isAdminCall", which will be true
if admin is restarting the password (in this case the LDAP operation can
be same like already and use "replace" operation) or if user himself is
restarting the password. Maybe the "isAdminCall" field is not necessary
as with admin call, the "oldValue" simply won't be available (when user
himself is restarting the password in account management, user is
required to set password and AccountService knows the old password value)
Other possibility is to introduce the context map ( Map<String, String>
contextData ) on UserCredentialModel, which is more flexible. At the
same time the "device" field can be removed from UserCredentialModel IMO
as it doesn't seem to be used from anywhere right now.
2) Change the LDAPIdentityStore implementation to differ between the two
cases you described
I have tried trying to get this to work in the Keycloak code myself but so far no luck unfortunately. If I get it working properly I can maybe create a pull request of it.