Menu

PasswordExpiredControl is not detecting expired password

2020-06-24
2020-09-07
  • Alvaro Felipe Garcia Mendez

    As i saw in a post from a few years ago https://sourceforge.net/p/ldap-sdk/discussion/1001257/thread/9d60b696/, i've used then same code to do the expiration check

    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.
                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;
                DraftBeheraLDAPPasswordPolicy10ResponseControl pwpResponse = DraftBeheraLDAPPasswordPolicy10ResponseControl
                        .get(bindResult);
                if (pwpResponse != null) {
                    DraftBeheraLDAPPasswordPolicy10ErrorType errorType = pwpResponse.getErrorType();
                    if (errorType != null) {
                        // There was a password policy error.
                        System.out.print("There was a password policy error");
                    }
                }
                return passwordExpired;
            }
    
        }
    

    Now, as you can see i've used the PasswordExpiredControl and, also, the DraftBeheraLDAPPasswordPolicy10ResponseControl class without succes. The response for both classes is null, then i read this

    then you should work with your vendor to determine what mechanism (if any) that server offers for this capability.

    so as far as i know OpenLDAP has this capabilities, so what else can be failing?

    PD: 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 it returns this

    ldap_initialize( ldaps://localhost:636/??base )
        Enter LDAP Password:
        ldap_bind: Invalid credentials (49); Password expired
    
     

    Last edit: Alvaro Felipe Garcia Mendez 2020-06-24
  • Neil Wilson

    Neil Wilson - 2020-06-24

    I don't know whether OpenLDAP supports the password expired response control as described in draft-vchu-ldap-pwd-policy-00, but I wouldn't be surprised if it does not. If it does support that control, then the server should return it without the client needing to do anything special in the request.

    I do think that it's much more likely that it supports the password policy control described in draft-behera-ldap-password-policy-10, but the password policy response control will only be returned if the bind request includes the corresponding request control. The bind request used in the example above does not include that control, so the server wouldn't know to include the response control in the bind result. If you want to use that control, then you should change your bind request from

    new SimpleBindRequest(dn, password)

    to

    new SimpleBindRequest(dn, password, new DraftBeheraLDAPPasswordPolicy10RequestControl())

    If you include the request control and the server still doesn't return the corresponding response control, then that's probably an issue with the server rather than the client, and this probably isn't the best place to get OpenLDAP-specific help.

     
    ❤️
    1
    • Alvaro Felipe Garcia Mendez

      Dude, you're a lifesaviour :D
      That control in the SimpleBindRequest do the magic with this i can validate perfectly, now is returning the errorType.name() as PASSWORD_EXPIRED.
      Now the only doubt left is, does the PasswordExpiredControl need something similar to DraftBeheraLDAPPasswordPolicy10RequestControl?

       
      • Neil Wilson

        Neil Wilson - 2020-06-24

        As I mentioned above, you shouldn't have to do anything special in the request to get the password expired response control. If you're not seeing it, then it's probably either because the server doesn't support it or maybe because it's not configured to return it. I'm not an OpenLDAP expert, so I can't say whether it supports it and if so whether there is any associated configuration.

         
        • Alvaro Felipe Garcia Mendez

          Well, it's probably that, anyway thank you so much for your help!

           
  • Neil Wilson

    Neil Wilson - 2020-06-24

    By the way, the version of ldapsearch that the LDAP SDK provides (tools/ldapsearch) has support for both of those controls, so you could test with it before changing your code For example:

    tools/ldapsearch --hostname myhost --port 636 --useSSL --bindDN dn --promptForBindPassword --usePasswordPolicyControl --baseDN "" --scope base "(objectClass=*)"

    If the server includes any controls in the bind response, then they should be written to standard output before the tool attempts the search.

     
    👍
    1
  • Alvaro Felipe Garcia Mendez

    Hello again, do you know if an AD in Windows server 2016 can handle the password expired with the DraftBeheraLDAPPasswordPolicy10RequestControl?

     

    Last edit: Alvaro Felipe Garcia Mendez 2020-09-07
  • Neil Wilson

    Neil Wilson - 2020-09-07

    I'm not an AD expert, but it does not appear that its root DSE advertises support for the control, so I would guess that it does not.

     
  • Neil Wilson

    Neil Wilson - 2020-09-07

    By the way, it looks like OpenLDAP version 2.4.51 (released in mid-August) added support for the password expired and password expiring controls.

     
  • Alvaro Felipe Garcia Mendez

    Well, with OpenLDAP it works neat! but since our customer is using Windows AD we can't make work properly. In fact it ignores many Policies, like Password history, Minimum and Maximum password age but make the password changes and logins succesfully. Anyway, thanks for your time :)

     

    Last edit: Alvaro Felipe Garcia Mendez 2020-09-07

Log in to post a comment.