I adapted the proposed example code in https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/controls/PasswordExpiredControl.html to my needs.
public Boolean checkExpiration(String user, String pass) throws LDAPException {
SSLSocketFactory socketFactory = null;
try {
socketFactory = createFactory();
} catch (Exception e) {
// CreateFactory Exception
e.printStackTrace();
}
// Create a secure connection to the Active Directory server.
final LDAPConnection connection = new LDAPConnection(socketFactory, myHost, (Integer.parseInt(portLdap)),
bindDN, passDN);
// Send a simple bind request to the directory server.
BindRequest bindRequest = new SimpleBindRequest("uid=example1,ou=Corporate Users,dc=example,dc=com", pass);
BindResult bindResult;
boolean passwordExpired;
try {
bindResult = connection.bind(bindRequest);
// If we got here, the bind was successful and we know the password was
// not expired. However, we shouldn't ignore the result because the
// password might be about to expire. To determine whether that is the
// case, we should see if the bind result included a password expiring
// control. I'm not interested on this.
passwordExpired = false;
return passwordExpired;
} catch (LDAPException le) {
// If we got here, then the bind failed. The failure may or may not have
// been due to an expired password. To determine that, we should see if
// the bind result included a password expired control.
bindResult = new BindResult(le.toLDAPResult());
ResultCode resultCode = le.getResultCode();
String errorMessageFromServer = le.getDiagnosticMessage();
PasswordExpiredControl expiredControl = PasswordExpiredControl.get(le);
passwordExpired = expiredControl != null;
return passwordExpired;
} finally {
connection.close();
}
}
Now, i've checked if the user has a password expired in the openldap host with this command
# ldapwhoami -H ldaps://localhost:636 -W -D "uid=example1,ou=Corporate Users,dc=example,dc=com" -e ppolicy -v
and the response is
ldap_initialize( ldaps://localhost:636/??base )
Enter LDAP Password:
ldap_bind: Invalid credentials (49); Password expired
So the question is what's happening? Why is not detecting the password as expired?
PD: I debugged the expiringControl value and it returns a null
and the le(LDAPException) value is LDAPException(resultCode=49 (invalid credentials), errorMessage='invalid credentials', ldapSDKVersion=5.1.0, revision=89705d759f7c1ab3bccb2870f8c2e7d529ed231b)
Finally i've ended posting the question in the UnboundID Forum (https://sourceforge.net/p/ldap-sdk/discussion/1001257/thread/e95d52b047/#210f) and they answered really quick.
So here's the solution. I've added new elements due to my OpenLDAP don't support PasswordExpiredControl, so i've added DraftBeheraLDAPPasswordPolicy10ResponseControl
and changing the bind to from
new SimpleBindRequest(dn, password)
to new SimpleBindRequest(dn, password, new DraftBeheraLDAPPasswordPolicy10RequestControl())
.
The final script is as follows.
public Boolean checkExpiration(String user, String pass) throws LDAPException {
String cn = getCNFromUser(user);
SSLSocketFactory socketFactory = null;
try {
socketFactory = createFactory();
} catch (Exception e) {
// CreateFactory Exception
e.printStackTrace();
}
// Create a secure connection to the Active Directory server.
final LDAPConnection connection = new LDAPConnection(socketFactory, myHost, (Integer.parseInt(portLdap)),
bindDN, passDN);
// Send a simple bind request to the directory server.
BindRequest bindRequest = new SimpleBindRequest("cn=" + cn + ",dc=test,dc=com", pass,
new DraftBeheraLDAPPasswordPolicy10RequestControl());
BindResult bindResult;
boolean passwordExpired;
try {
bindResult = connection.bind(bindRequest);
// If we got here, the bind was successful and we know the password was
// not expired. However, we shouldn't ignore the result because the
// password might be about to expire. To determine whether that is the
// case, we should see if the bind result included a password expiring
// control.
passwordExpired = false;
return passwordExpired;
} catch (LDAPException le) {
// If we got here, then the bind failed. The failure may or may not have
// been due to an expired password. To determine that, we should see if
// the bind result included a password expired control.
bindResult = new BindResult(le.toLDAPResult());
PasswordExpiredControl expiredControl = PasswordExpiredControl.get(le);
// Checking if the expiredControl is not null, then it has an expired password
passwordExpired = expiredControl != null;
if (passwordExpired) {
return passwordExpired;
}
// Obtaining control for password policy, this in case there's no support for
// PasswordExpiredControl in LDAP server
DraftBeheraLDAPPasswordPolicy10ResponseControl pwpResponse = DraftBeheraLDAPPasswordPolicy10ResponseControl
.get(bindResult);
if (pwpResponse != null) {
// Getting error type
DraftBeheraLDAPPasswordPolicy10ErrorType errorType = pwpResponse.getErrorType();
if (errorType != null) {
// There was a password policy error.
passwordExpired = errorType.name().matches("PASSWORD_EXPIRED");
if (!passwordExpired) {
System.out.print("There was other error: " + errorType.name());
}
}
}
return passwordExpired;
}
}