cancel
Showing results for 
Search instead for 
Did you mean: 

Handling Authentication LDAP Exceptions

Highlighted
UgmaAdmin
New Member
0 Kudos

Handling Authentication LDAP Exceptions

I'm new to LDAP and UboundID.

 

I've learned enough to get an LDAPConnection going and then bind a user.

 

What I'm curious about is the best way to get more information about exceptions that occur when there's a problem with the users credentials.

 

Here's an example diagnostic message I get:

 

80090308: LdapErr: DSID-0C0903D9, comment: AcceptSecurityContext error, data 532, v2580

 

I'm aware of at least the following scenarios (error codes):

525 - user not found
52e - invalid credentials
530 - not permitted to logon at this time
531 - not permitted to logon from this computer
532 - password expired
533 - account disabled
701 - account expired
773 - user must reset password
775 - account locked

 

 

 

Is there a way that people are already going about this, or should I just extract the data code from the diagnostic message and use a switch statement to notify the user?

5 REPLIES
UnboundID NeilW
UnboundID
0 Kudos

Re: Handling Authentication LDAP Exceptions

It looks like you're working with Active Directory. As far as I know, Active Directory doesn't provide any way to get more information than it already exposes through those codes. You can see https://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx for a more complete list of possible error codes (although this is a general list, so it has a lot of codes that don't apply to your specific case).

UgmaAdmin
New Member
0 Kudos

Re: Handling Authentication LDAP Exceptions

Thanks for the quick reply.

 

I took a look at the link you provided, but I can't find the error codes I mentioned above in there.

UgmaAdmin
New Member
0 Kudos

Re: Handling Authentication LDAP Exceptions

After a little digging, I've found that the error codes I mentioned are in hexadecimal format.

 

To find them in the Microsoft Errors, you just need to convert the error to decimal

 

Here's some useful information about the errors I mentioned. 

 

Common Active Directory LDAP bind errors: 

80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 525, v893 
HEX: 0x525 - user not found 
DEC: 1317 - ERROR_NO_SUCH_USER
 (The specified account does not exist.) 
NOTE: Returns when username is invalid. 

80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 52e, v893 
HEX: 0x52e - invalid credentials 
DEC: 1326 - ERROR_LOGON_FAILURE
 (Logon failure: unknown user name or bad password.) 
NOTE: Returns when username is valid but password/credential is invalid. Will prevent most other errors from being displayed as noted. 

80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 530, v893 
HEX: 0x530 - not permitted to logon at this time 
DEC: 1328 - ERROR_INVALID_LOGON_HOURS 
(Logon failure: account logon time restriction violation.) 
NOTE: Returns only when presented with valid username and password/credential. 

80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 531, v893 
HEX: 0x531 - not permitted to logon from this workstation 
DEC: 1329 - ERROR_INVALID_WORKSTATION
 (Logon failure: user not allowed to log on to this computer.) 
LDAP[userWorkstations: <multivalued list of workstation names>] 
NOTE: Returns only when presented with valid username and password/credential. 

80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 532, v893 
HEX: 0x532 - password expired 
DEC: 1330 - ERROR_PASSWORD_EXPIRED
 (Logon failure: the specified account password has expired.) 
LDAP[userAccountControl: <bitmask=0x00800000>] - PASSWORDEXPIRED 
NOTE: Returns only when presented with valid username and password/credential. 

80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 533, v893 
HEX: 0x533 - account disabled 
DEC: 1331 - ERROR_ACCOUNT_DISABLED 
(Logon failure: account currently disabled.) 
LDAP[userAccountControl: <bitmask=0x00000002>] - ACCOUNTDISABLE 
NOTE: Returns only when presented with valid username and password/credential. 

80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 701, v893 
HEX: 0x701 - account expired 
DEC: 1793 - ERROR_ACCOUNT_EXPIRED 
(The user's account has expired.) 
LDAP[accountExpires: <value of -1, 0, or extemely large value indicates account will not expire>] - ACCOUNTEXPIRED 
NOTE: Returns only when presented with valid username and password/credential. 

80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 773, v893 
HEX: 0x773 - user must reset password 
DEC: 1907 - ERROR_PASSWORD_MUST_CHANGE 
(The user's password must be changed before logging on the first time.) 
LDAP[pwdLastSet: <value of 0 indicates admin-required password change>] - MUST_CHANGE_PASSWD 
NOTE: Returns only when presented with valid username and password/credential. 

80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 775, v893 
HEX: 0x775 - account locked out 
DEC
1909 - ERROR_ACCOUNT_LOCKED_OUT (The referenced account is currently locked out and may not be logged on to.) 
LDAP[userAccountControl: <bitmask=0x00000010>] - LOCKOUT 
NOTE: Returns even if invalid password is presented 

 

Source: https://www-01.ibm.com/support/docview.wss?uid=swg21290631

UgmaAdmin
New Member
0 Kudos

Re: Handling Authentication LDAP Exceptions

@NeilW, Where do I suggest that something like an ActiveDirectoryErrorCode class be included in the BindResult? If the codes are all known via Microsoft, is there a good reason to require the code to be extracted from a String? Surely binding to an AD, and the errors that come with it, is a common enough operation to deserve a straight-forward API.

 

What about something like this? 

 

package tech.ugma.vendorissues.connection.ldap;

import java.util.Scanner;

@SuppressWarnings("WeakerAccess")
public class ActiveDirectoryErrorCode {

    private final String name;
    private final int decimalValue;
    private final String hexadecimalString;
    private final String description;


    /**
     * Only use if the error code is not already defined herein; before using this constructor try
     * <pre>{@code
     * String dataCode = ActiveDirectoryErrorCode.extractDataCode(ldapDiagnosticMessage);
     *
     * if (dataCode != null) {
     *     ActiveDirectoryErrorCode predefined = ActiveDirectoryErrorCode.findIfAlreadyDefined(dataCode);
     *
     *     if (predefined == null) {
     *         return new ActiveDirectoryErrorCode(dataCode);
     *     } else {
     *         return predefined;
     *     }
     * } else {
     *     return null;
     * }}</pre>
     *
     */
    ActiveDirectoryErrorCode(final String dataCode) {
        String hexadecimalString = "0x" + dataCode;
        int decimalValue = Integer.decode("0x" + dataCode);
        String name = "";
        String description = "We haven't defined this error code here in the source code, but it surely is defined" +
                " on Microsoft's website. Lookup its decimal value, here: https://msdn.microsoft.com/en-us/library/ms681381(v=vs.85).aspx";

        this.name = name;
        this.decimalValue = decimalValue;
        this.hexadecimalString = hexadecimalString;
        this.description = description;
    }

    /**
     * Look up an error code using the data from UnboundID's diagnostic message.
     * <p>
     * Example of a diagnostic message: <pre>80090308: LdapErr: DSID-0C0903D9, comment: AcceptSecurityContext error, data 532, v2580</pre>
     * The dataCode that you should pass in, here, is <pre>532</pre>
     *
     * @param dataCode should be extracted from UnboundID's BindResult's diagnostic message. It's the hexadecimal representation
     *                 of a Microsoft Error Code.
     * @return if one is already defined, this returns it; null otherwise.
     */
    public static ActiveDirectoryErrorCode findIfAlreadyDefined(String dataCode) {
        int decimalValue = Integer.decode("0x" + dataCode);
        for (ActiveDirectoryErrorCode e :
                values()) {
            if (e.decimalValue == decimalValue) {
                return e;
            }
        }
        return null;
    }

    /**
     * Example of a diagnostic message: <pre>80090308: LdapErr: DSID-0C0903D9, comment: AcceptSecurityContext error, data 532, v2580</pre>
     * The dataCode that would be extracted, here, is <pre>532</pre>
     *
     */
    public static String extractDataCode(String ldapDiagnosticMessage) {

        if (ldapDiagnosticMessage == null) {
            return null;
        }

        Scanner extractor = new Scanner(ldapDiagnosticMessage);

        String data = extractor.findInLine("(?=data)[^,]*");
        String dataCode = data.substring(data.indexOf(" ") + 1);

        return dataCode;
    }

    /**
     * Creates a new active directory error code with the specified name and integer value.
     *
     * @param name              The name for this error code.
     * @param decimalValue      The decimal value for this error code.
     * @param hexadecimalString The hexadecimal string representation for this error code.
     */
    private ActiveDirectoryErrorCode(final String name, final int decimalValue, String hexadecimalString) {
        this(name, decimalValue, hexadecimalString, "");
    }

    /**
     * Creates a new active directory error code with the specified name, decimal value, hexadecimal value and description.
     *
     * @param name              The name for this error code.
     * @param decimalValue      The decimal value for this error code.
     * @param hexadecimalString The hexadecimal string representation for this error code.
     * @param description       A short description of the error code.
     */
    private ActiveDirectoryErrorCode(final String name, final int decimalValue, String hexadecimalString, String description) {
        this.name = name;
        this.decimalValue = decimalValue;
        this.hexadecimalString = hexadecimalString;
        this.description = description;
    }

    /**
     * See <a href="https://msdn.microsoft.com/en-us/library/ms681385(v=vs.85).aspx#error_no_such_user">Microsoft Error Code 1317</a>
     * <p>
     * NOTE: Returned when username is invalid.
     */
    public static final ActiveDirectoryErrorCode NO_SUCH_USER
            = new ActiveDirectoryErrorCode("ERROR_NO_SUCH_USER",
            1317,
            "0x525",
            "The specified account does not exist.");
    /**
     * See <a href="https://msdn.microsoft.com/en-us/library/ms681385(v=vs.85).aspx#error_logon_failure">Microsoft Error Code 1326</a>
     * <p>
     * NOTE: Returns when username is valid but password/credential is invalid. Will prevent most other errors from being displayed as noted.
     */
    public static final ActiveDirectoryErrorCode LOGON_FAILURE
            = new ActiveDirectoryErrorCode("ERROR_LOGON_FAILURE",
            1326,
            "0x52e",
            "The user name or password is incorrect.");


    /**
     * See <a href="https://msdn.microsoft.com/en-us/library/ms681385(v=vs.85).aspx#error_invalid_logon_hours">Microsoft Error Code 1328</a>
     * <p>
     * NOTE: Returns only when presented with valid username and password/credential.
     */
    public static final ActiveDirectoryErrorCode INVALID_LOGON_HOURS
            = new ActiveDirectoryErrorCode("ERROR_INVALID_LOGON_HOURS",
            1328,
            "0x530",
            "Your account has time restrictions that keep you from signing in right now.");


    /**
     * See <a href="https://msdn.microsoft.com/en-us/library/ms681385(v=vs.85).aspx#error_invalid_workstation">Microsoft Error Code 1329</a>
     * <p>
     * NOTE: Returns only when presented with valid username and password/credential.
     */
    public static final ActiveDirectoryErrorCode INVALID_WORKSTATION
            = new ActiveDirectoryErrorCode("ERROR_INVALID_WORKSTATION",
            1329,
            "0x531",
            "This user isn't allowed to sign in to this computer.");


    /**
     * See <a href="https://msdn.microsoft.com/en-us/library/ms681385(v=vs.85).aspx#ERROR_PASSWORD_EXPIRED">Microsoft Error Code 1330</a>
     * <p>
     * NOTE: Returns only when presented with valid username and password/credential.
     */
    public static final ActiveDirectoryErrorCode PASSWORD_EXPIRED
            = new ActiveDirectoryErrorCode("ERROR_PASSWORD_EXPIRED",
            1330,
            "0x532",
            "The password for this account has expired.");


    /**
     * See <a href="https://msdn.microsoft.com/en-us/library/ms681385(v=vs.85).aspx#ERROR_ACCOUNT_DISABLED">Microsoft Error Code 1331</a>
     * <p>
     * NOTE: Returns only when presented with valid username and password/credential.
     */
    public static final ActiveDirectoryErrorCode ACCOUNT_DISABLED
            = new ActiveDirectoryErrorCode("ERROR_ACCOUNT_DISABLED",
            1331,
            "0x533",
            "This user can't sign in because this account is currently disabled.");

    /**
     * See <a href="https://msdn.microsoft.com/en-us/library/ms681386(v=vs.85).aspx#ERROR_ACCOUNT_EXPIRED">Microsoft Error Code 1793</a>
     * <p>
     * NOTE: Returns only when presented with valid username and password/credential.
     */
    public static final ActiveDirectoryErrorCode ACCOUNT_EXPIRED
            = new ActiveDirectoryErrorCode("ERROR_ACCOUNT_EXPIRED",
            1793,
            "0x701",
            "The user's account has expired.");

    /**
     * See <a href="https://msdn.microsoft.com/en-us/library/ms681386(v=vs.85).aspx#ERROR_PASSWORD_MUST_CHANGE">Microsoft Error Code 1907</a>
     * <p>
     * NOTE: Returns only when presented with valid username and password/credential.
     */
    public static final ActiveDirectoryErrorCode PASSWORD_MUST_CHANGE
            = new ActiveDirectoryErrorCode("ERROR_PASSWORD_MUST_CHANGE",
            1907,
            "0x773",
            "The user's password must be changed before signing in.");


    /**
     * See <a href="https://msdn.microsoft.com/en-us/library/ms681386(v=vs.85).aspx#ERROR_ACCOUNT_LOCKED_OUT">Microsoft Error Code 1909</a>
     * <p>
     * NOTE: Returns even if invalid password is presented.
     */
    public static final ActiveDirectoryErrorCode ACCOUNT_LOCKED_OUT
            = new ActiveDirectoryErrorCode("ERROR_ACCOUNT_LOCKED_OUT",
            1909,
            "0x775",
            "The referenced account is currently locked out and may not be logged on to.");


    /**
     * Retrieves an array of all error codes defined herein.  This will
     * not include dynamically-generated values.
     *
     * @return An array of all error codes defined in herein.
     */
    public static ActiveDirectoryErrorCode[] values() {
        return new ActiveDirectoryErrorCode[]
                {
                        NO_SUCH_USER,
                        LOGON_FAILURE,
                        INVALID_LOGON_HOURS,
                        INVALID_WORKSTATION,
                        PASSWORD_EXPIRED,
                        ACCOUNT_DISABLED,
                        ACCOUNT_EXPIRED,
                        PASSWORD_MUST_CHANGE,
                        ACCOUNT_LOCKED_OUT
                };
    }

    public String getName() {
        return name;
    }

    public int getDecimalValue() {
        return decimalValue;
    }

    public String getHexadecimalString() {
        return hexadecimalString;
    }

    public String getDescription() {
        return description;
    }

    @Override
    public String toString() {
        return "ActiveDirectoryErrorCode{" +
                "name='" + name + '\'' +
                ", description='" + description + '\'' +
                ", decimalValue=" + decimalValue +
                ", hexadecimalString='" + hexadecimalString + '\'' +
                '}';
    }
}
UnboundID NeilW
UnboundID
0 Kudos

Re: Handling Authentication LDAP Exceptions

You could open an issue in the GitHub project at https://github.com/pingidentity/ldapsdk/issues, although it might be a while before anything like this would be implemented, since I've got a pretty big backlog of work to do right now. Also, it wouldn't be specific to bind operations, since I believe that those kinds of error codes can also apply to other operations, and it could take a while to compile a list of applicable error codes.