Password Policy errors not being thrown with LDAP Spring Security

861 Views Asked by At

I have am fairly new to Spring Security with LDAP and I am trying to authenticate with a user who has a password expired on the LDAP server(FreeIPA).

I cannot seem to trigger any password expired exception etc. The Password Policy Response Controls always return null....

Here is my code, perhaps I am doing something incorrectly. How do I handle password policy errors? They don't fire at all currently.

<bean id="freeIpaContextSource" class="org.springframework.security.ldap.ppolicy.PasswordPolicyAwareContextSource">
    <constructor-arg value="${logon.freeipa.zone.ldap.connection.url}"/>
    <property name="base" value="${logon.freeipa.zone.user.dn.base}"/>
</bean>

<bean id="freeIpaLdapTemplate" class="org.springframework.security.ldap.SpringSecurityLdapTemplate">
    <constructor-arg name="contextSource" ref="freeIpaContextSource"/>
</bean>

I have a custom LdapAuthenticator below which uses a ldaptemplate to authenticate users.

@Override
public DirContextOperations authenticate(Authentication authentication) {
    checkForIllegalStateDuringAuthentication(authentication);
    logger.info(String.format("*** Beginning to authenticate against LDAP zone %s ***", authorizationZone.getName()));
    zoneAuthenticationService.saveRequestDataInSession((UsernamePasswordAuthenticationToken) authentication, authorizationZone.getName());
    CollectingAuthenticationErrorCallback errorCallback = new CollectingAuthenticationErrorCallback();
    boolean isAuthenticated = false;
    String userName = authentication.getName();
    String password = authentication.getCredentials().toString();
    String filterLookup = buildLDAPFilterLookupString(userName);
    if (StringUtils.isNotBlank(password)) {
        logger.info(String.format("*** Attempting authentication for user %s ***", userName));
        try {
            isAuthenticated = ldapTemplate.authenticate(StringUtils.EMPTY, filterLookup, password, errorCallback);

        } catch (Exception exception) {
            errorCallback.execute(exception);
        }
    }
    if (!isAuthenticated) {
        if (errorCallback.getError() == null) {
            errorCallback.execute(new AuthenticationException(null));
        }
        //Any LDAP exception caught are stored inside the errorCallBack for use later to display an appropriate error.
        logger.error(String.format("*** Authentication for user %s has failed. Exception has occurred while system performed LDAP authentication. ***", userName), errorCallback.getError());
        throw new LdapAuthenticationException(errorCallback.getError().getMessage(), errorCallback.getError());
    }
    logger.info(String.format("*** Authentication for user %s has succeeded ***", userName));
    return new DirContextAdapter(buildAuthenticatedDN(userName));
}

No matter what I do I cannot get any password policy errors to return. From my understanding you need to set a request control with PasswordPolicyControl when attempting to authenticate, but I never receive any response controls from the server. I have tried implementing something like below, but no luck on anything.

LdapContext context = (LdapContext)ldapTemplate.getContextSource().getContext(buildAuthenticatedDN(userName).toString(), password);
Control[] rctls = new Control[]{new PasswordPolicyControl(false)};
context.reconnect(rctls);
PasswordPolicyResponseControl ctrl = PasswordPolicyControlExtractor.extractControl(context);
//ctrl is always null
 if (ctrl.isExpired()) {
                throw new 
PasswordPolicyException(ctrl.getErrorStatus());
            }

What am I doing wrong? I am struggling greatly with this and any help would very much be appreciated.

1

There are 1 best solutions below

1
On

If your client really sends the correct response control you might hit this issue (open since 7 years):

#1539 [RFE] Add code to check password expiration on ldap bind

IIRC FreeIPA enforces password expiry only during Kerberos pre-authc (kinit).