Delegate Password Reset Permissions
Resetting another user’s password requires both the password-reset privilege and permission to write that entry’s userPassword attribute. This recipe grants only that write permission below ou=People,dc=example,dc=com.
Use a disposable server containing the sample users from Access Directory Entries Over REST. Run these commands before changing the sample password of user.0. --trustAll accepts the demonstration server’s self-signed certificate.
Create the Delegate and Grant Access
Create a delegate outside the target People subtree, so its own entry is not in the delegated reset scope:
bin/ldapmodify --hostname localhost --port 1389 --useStartTLS --trustAll \
--bindDN 'cn=Directory Manager' --bindPassword password <<'LDIF'
dn: ou=Administrators,dc=example,dc=com
changetype: add
objectClass: organizationalUnit
ou: Administrators
dn: uid=password-admin,ou=Administrators,dc=example,dc=com
changetype: add
objectClass: inetOrgPerson
cn: Password Administrator
sn: Administrator
uid: password-admin
userPassword: AdminPassword123!
ds-privilege-name: password-reset
dn: ou=People,dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr="userPassword")(version 3.0; acl "Delegate password resets in People"; allow (write) userdn="ldap:///uid=password-admin,ou=Administrators,dc=example,dc=com";)
LDIF
The ACI is inherited by entries below People. It does not grant writes to other attributes, permission to add or delete entries, or password resets outside that subtree. Existing ACIs still apply; this example assumes the default access-control configuration.
Verify the Scope
Reset a sample user’s password:
bin/ldappasswordmodify --hostname localhost --port 1389 --useStartTLS --trustAll \
--bindDN 'uid=password-admin,ou=Administrators,dc=example,dc=com' \
--bindPassword 'AdminPassword123!' \
--authzID 'dn:uid=user.0,ou=People,dc=example,dc=com' \
--newPassword 'NewPassword123!'
The password-modify operation should succeed. Verify the new password by binding as the user:
bin/ldapsearch --hostname localhost --port 1389 --useStartTLS --trustAll \
--bindDN 'uid=user.0,ou=People,dc=example,dc=com' \
--bindPassword 'NewPassword123!' \
--baseDN 'uid=user.0,ou=People,dc=example,dc=com' --searchScope base \
'(objectClass=*)' uid
Check that the delegate cannot change another attribute:
bin/ldapmodify --hostname localhost --port 1389 --useStartTLS --trustAll \
--bindDN 'uid=password-admin,ou=Administrators,dc=example,dc=com' \
--bindPassword 'AdminPassword123!' <<'LDIF'
dn: uid=user.0,ou=People,dc=example,dc=com
changetype: modify
replace: description
description: This change must be rejected
LDIF
Expect LDAP result 50, Insufficient Access Rights. A successful change indicates that another ACI grants broader access.
If the loopback HTTPS handler from the REST recipe is enabled, the same delegate can request a generated password through REST:
curl --fail-with-body --cacert server-cert.pem --user 'password-admin:AdminPassword123!' \
--request POST 'https://localhost:8443/api/users/user.0?_action=resetPassword'
The response contains generatedPassword; it replaces the password set above. See Resetting Passwords for the API details.