diff --git a/doc/designs/index.rst b/doc/designs/index.rst index 547f027ce..91a8a6357 100644 --- a/doc/designs/index.rst +++ b/doc/designs/index.rst @@ -14,6 +14,7 @@ FreeIPA design documentation krb-ticket-policy.md extdom-plugin-protocol.md expiring-password-notification.md + ldap_grace_period.md ldap_pam_passthrough.md libpwquality.md membermanager.md diff --git a/doc/designs/ldap_grace_period.md b/doc/designs/ldap_grace_period.md new file mode 100644 index 000000000..4b9db3424 --- /dev/null +++ b/doc/designs/ldap_grace_period.md @@ -0,0 +1,96 @@ +# LDAP Grace Period + +## Overview + +IPA previously allowed LDAP authentications past expiration to prevent a chicken-and-egg problem. Because all administratively-set passwords are expired a user must be given an opportunity to authenticate in order to reset their password. This allowed for unlimited authentications. + +## Use Cases + +Many IPA users have asked for a mechanism to deny LDAP authentications once expired. + +## How to Use + +A new option is added to password policies, --gracelimit. This specifies the number of allowed BINDs past expiration. + +To set the global policy: + +ipa pwpolicy-mod --gracelimit 3 + +This will allow 3 additional logins past expiration. + +Setting to -1 disables the grace limit check. + +Setting to 0 will do a grace limit check but will always fail because no further logins are allowed. The distinction between 0 and -1 is that with 0 a password policy control is returned. + +## Design + +An expired draft around LDAP password policies describes two methods for limiting account access past expiration, https://tools.ietf.org/id/draft-behera-ldap-password-policy-10.html + +The RFE provides two options (which can be use simultaneously). + +1. Limit the number of authentications past expiration +2. Limit by time past the expiration + +This implements the first part only. 389-ds already implements this so we can reuse existing schema, using their alternative attribute names passwordGraceLimit (system) and passwordGraceUserTime (user). + +A 389-ds plugin will be registered as a bind preop function which will compare the policy grace period with the user's grace period + +The password policy plugin will have a new attribute added, passwordGraceLimit, to store the policy maximum. + +The basic flow is: + +- Register preop BIND plugin +- On BIND, get the DN +- Get the password policy for that DN +- If the policy grace limit == -1 then exit +- Compare the policy grace limit to the user's passwordGraceUserTime +- If the user's grace limit exceeds policy, fail +- If the grace limit == 0, fail +- Set a password policy control with the number of remaining logins +- Set the time in the policy to -1 to indicate no value + +On successful password reset (by anyone) reset the user's passwordGraceUserTime to 0. + +The default value on install/upgrade will be -1 to retail existing behavior. + +The per-user attempts will not be replicated. + +## Implementation + +N/A + +## Feature Management + +### UI + +The new option is not visible in the UI yet. + +### CLI + +Overview of the CLI commands. Example: + +| Command | Options | +| --- | ----- | +| pwpolicy-mod | --gracelimit=<-1 to MAXINT> | + +### Configuration + +The plugin will be registered on new installations. + +## Upgrade + +The plugin will be registered on upgrades. + +## Test plan + +1. Set a grace limit on a custom policy, ldapsearch a few times, verify that the limit is set to what is expected +2. Keep going until authentication fails +3. Reset password, verify that authentication can happen +4. With two servers verify that an authentication one one server doesn't trigger a replication event to the other. + +## Troubleshooting and debugging + +$ ldapsearch -LLL -x -D 'uid=tuser,cn=users,cn=accounts,dc=example,dc=test' -w password -e ppolicy -b uid=tuser,cn=users,cn=accounts,dc=example,dc=test dn +# PasswordExpired control +ldap_bind: Success (0) (Password expired, 3 grace logins remain) +dn: uid=tuser,cn=users,cn=accounts,dc=example,dc=test