0

我根据我的需要调整了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 值,它返回 anull并且 le(LDAPException) 值为LDAPException(resultCode=49 (invalid credentials), errorMessage='invalid credentials', ldapSDKVersion=5.1.0, revision=89705d759f7c1ab3bccb2870f8c2e7d529ed231b)

4

1 回答 1

0

最后,我已经结束在 UnboundID 论坛(https://sourceforge.net/p/ldap-sdk/discussion/1001257/thread/e95d52b047/#210f)上发布问题,他们回答得很快。

所以这是解决方案。由于我的 OpenLDAP 不支持 PasswordExpiredControl,我添加了新元素,因此我添加DraftBeheraLDAPPasswordPolicy10ResponseControl了绑定并将其更改为 from new SimpleBindRequest(dn, password)to 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;
        }

    }
于 2020-06-24T23:19:35.343 回答