com.unboundid.ldap.sdk.controls.PasswordExpiredControl 未检测到过期密码 (Java)
com.unboundid.ldap.sdk.controls.PasswordExpiredControl is not detecting expired password (Java)
我根据自己的需要改编了 https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/controls/PasswordExpiredControl.html 中建议的示例代码。
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();
}
}
现在,我已经使用此命令检查用户在 openldap 主机中的密码是否已过期
# ldapwhoami -H ldaps://localhost:636 -W -D "uid=example1,ou=Corporate Users,dc=example,dc=com" -e ppolicy -v
响应是
ldap_initialize( ldaps://localhost:636/??base )
Enter LDAP Password:
ldap_bind: Invalid credentials (49); Password expired
所以问题是 发生了什么事?为什么没有检测到密码已过期?
PD:我调试了 expiringControl 值,它 returns 一个 null
并且 le(LDAPException) 值为 LDAPException(resultCode=49 (invalid credentials), errorMessage='invalid credentials', ldapSDKVersion=5.1.0, revision=89705d759f7c1ab3bccb2870f8c2e7d529ed231b)
我终于结束了在 UnboundID 论坛 (https://sourceforge.net/p/ldap-sdk/discussion/1001257/thread/e95d52b047/#210f) 中发布问题,他们的回答非常快。
这就是解决方案。由于我的 OpenLDAP 不支持 PasswordExpiredControl,我添加了新元素,因此我添加了 DraftBeheraLDAPPasswordPolicy10ResponseControl
并将绑定更改为 from
new SimpleBindRequest(dn, password)
到 new SimpleBindRequest(dn, password, new DraftBeheraLDAPPasswordPolicy10RequestControl())
。
最终脚本如下
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;
}
}
我根据自己的需要改编了 https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/controls/PasswordExpiredControl.html 中建议的示例代码。
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();
}
}
现在,我已经使用此命令检查用户在 openldap 主机中的密码是否已过期
# ldapwhoami -H ldaps://localhost:636 -W -D "uid=example1,ou=Corporate Users,dc=example,dc=com" -e ppolicy -v
响应是
ldap_initialize( ldaps://localhost:636/??base )
Enter LDAP Password:
ldap_bind: Invalid credentials (49); Password expired
所以问题是 发生了什么事?为什么没有检测到密码已过期?
PD:我调试了 expiringControl 值,它 returns 一个 null
并且 le(LDAPException) 值为 LDAPException(resultCode=49 (invalid credentials), errorMessage='invalid credentials', ldapSDKVersion=5.1.0, revision=89705d759f7c1ab3bccb2870f8c2e7d529ed231b)
我终于结束了在 UnboundID 论坛 (https://sourceforge.net/p/ldap-sdk/discussion/1001257/thread/e95d52b047/#210f) 中发布问题,他们的回答非常快。
这就是解决方案。由于我的 OpenLDAP 不支持 PasswordExpiredControl,我添加了新元素,因此我添加了 DraftBeheraLDAPPasswordPolicy10ResponseControl
并将绑定更改为 from
new SimpleBindRequest(dn, password)
到 new SimpleBindRequest(dn, password, new DraftBeheraLDAPPasswordPolicy10RequestControl())
。
最终脚本如下
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;
}
}