Active Directory (LDAP) - Check account locked out / Password expired

后端 未结 4 1312
轮回少年
轮回少年 2020-12-02 21:04

Currently I authenticate users against some AD using the following code:

DirectoryEntry entry = new DirectoryEntry(_path, username, pwd);

try
{
    // Bind          


        
4条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-02 21:40

    I know this answer is a few years late, but we just ran into the same situation as the original poster. Unfortunately, in our environment, we can't use LogonUser -- we needed a pure LDAP solution. It turns out there is a way to get the extended error code from a bind operation. It's a bit ugly, but it works:

    catch(DirectoryServicesCOMException exc)
    {
        if((uint)exc.ExtendedError == 0x80090308)
        {
            LDAPErrors errCode = 0;
    
            try
            {
                // Unfortunately, the only place to get the LDAP bind error code is in the "data" field of the 
                // extended error message, which is in this format:
                // 80090308: LdapErr: DSID-0C09030B, comment: AcceptSecurityContext error, data 52e, v893
                if(!string.IsNullOrEmpty(exc.ExtendedErrorMessage))
                {
                    Match match = Regex.Match(exc.ExtendedErrorMessage, @" data (?[0-9A-Fa-f]+),");
                    if(match.Success)
                    {
                        string errCodeHex = match.Groups["errCode"].Value;
                        errCode = (LDAPErrors)Convert.ToInt32(errCodeHex, fromBase: 16);
                    }
                }
            }
            catch { }
    
            switch(errCode)
            {
                case LDAPErrors.ERROR_PASSWORD_EXPIRED:
                case LDAPErrors.ERROR_PASSWORD_MUST_CHANGE:
                    throw new Exception("Your password has expired and must be changed.");
    
                // Add any other special error handling here (account disabled, locked out, etc...).
            }
        }
    
        // If the extended error handling doesn't work out, just throw the original exception.
        throw;
    }
    

    And you'll need definitions for the error codes (there are a lot more of these at http://www.lifeasbob.com/code/errorcodes.aspx):

    private enum LDAPErrors
    {
        ERROR_INVALID_PASSWORD = 0x56,
        ERROR_PASSWORD_RESTRICTION = 0x52D,
        ERROR_LOGON_FAILURE = 0x52e,
        ERROR_ACCOUNT_RESTRICTION = 0x52f,
        ERROR_INVALID_LOGON_HOURS = 0x530,
        ERROR_INVALID_WORKSTATION = 0x531,
        ERROR_PASSWORD_EXPIRED = 0x532,
        ERROR_ACCOUNT_DISABLED = 0x533,
        ERROR_ACCOUNT_EXPIRED = 0x701,
        ERROR_PASSWORD_MUST_CHANGE = 0x773,
        ERROR_ACCOUNT_LOCKED_OUT = 0x775,
        ERROR_ENTRY_EXISTS = 0x2071,
    }
    

    I couldn't find this information anywhere else -- everyone just says you should use LogonUser. If there's a better solution, I'd love to hear it. If not, I hope this helps other people who can't call LogonUser.

提交回复
热议问题