简体   繁体   English

在 Python 中使用 LDAP 检测 Active Directory 用户帐户是否被锁定

[英]Detect if an Active Directory user account is locked using LDAP in Python

I'm validating user logins using python's ldap module.我正在使用 python 的 ldap 模块验证用户登录。 When the login fails, I get a ldap.INVALID_CREDENTIALS login, but this can be either because of a wrong password or because the account is locked.当登录失败时,我得到一个 ldap.INVALID_CREDENTIALS 登录,但这可能是因为密码错误或帐户被锁定。 The account get's locked after the 3rd try.帐户在第 3 次尝试后被锁定。

I would like to detect that the account is locked and report that to the frustrated user, instead of the same "invalid login" message.我想检测到该帐户已被锁定并将其报告给沮丧的用户,而不是相同的“无效登录”消息。

Searching for a solution I found:搜索我找到的解决方案:

  • The userAccountControl LOCKED flag is not used by AD; AD 不使用 userAccountControl LOCKED 标志;
  • The lockoutTime attribute should be used instead应该改用 lockoutTime 属性

The LDAP query I should be using to find locked users is:我应该用来查找锁定用户的 LDAP 查询是:

(&(objectClass=user)(lockoutTime>=1))

Or for a specific user:或者对于特定用户:

(&(objectClass=user)(sAMAccountName=jabberwocky)(lockoutTime>=1))

But this is not working, the query returns no results every time.但这不起作用,查询每次都没有返回结果。

A value of zero in lockoutTime means it's not locked out. lockoutTime中的零值意味着它没有被锁定。 So, you should try this.所以,你应该试试这个。

(&(objectClass=user)(!lockoutTime=0)) 

Actually, the above query is still not 100% correct.实际上,上述查询仍然不是 100% 正确的。 If you read the fine print from MSDN, Microsoft is suggesting you to add the Lockout-Time attribute to the Lockout-Duration attribute and then compare it with the current time.如果您从 MSDN 阅读细则,Microsoft 建议您将Lockout-Time属性添加到Lockout-Duration属性,然后将其与当前时间进行比较。 That's because there is such a thing called lockout duration.那是因为有一个叫做锁定时间的东西。 Once the lockout duration passes, the user is unlocked automatically.一旦锁定时间结束,用户将自动解锁。 Zero in Lockout-Duration means the account is locked forever until the administrator unlock it. Lockout-Duration中的零表示帐户将永远锁定,直到管理员将其解锁。

See this MSDN article请参阅这篇MSDN 文章

This attribute value is only reset when the account is logged onto successfully.此属性值仅在帐户登录成功时重置。 This means that this value may be non zero, yet the account is not locked out.这意味着该值可能不为零,但帐户未被锁定。 To accurately determine if the account is locked out, you must add the Lockout-Duration to this time and compare the result to the current time, accounting for local time zones and daylight savings time.准确判断账户是否被锁定,必须在该时间上加上Lockout-Duration,与当前时间进行比较,考虑当地时区和夏令时。

lockoutTime is a <not set> attribute so the easiest way is to use: lockoutTime是一个<not set>属性,所以最简单的方法是使用:

(&(objectClass=user)(lockoutDuration=*))) 

for the non-empty entries.对于非空条目。

Update:更新:

However, this value is also set when the password expires, password needs to change etc.但是,当密码过期、需要更改密码等时,也会设置此值。

So it needs to be filtered by:所以需要过滤:

UserPrincipal userPrincipal = new UserPrincipal(context);
bool isLocked = userPrincipal.IsAccountLockedOut();

to get the cases where the user is locked out because they violated the password policy eg incorrectly entered the password 5 times.获取用户因违反密码策略而被锁定的情况,例如错误输入密码 5 次。

I found also this list of property flags: How to use the UserAccountControl flags我还找到了这个属性标志列表: How to use the UserAccountControl flags

SCRIPT  0x0001  1
ACCOUNTDISABLE  0x0002  2
HOMEDIR_REQUIRED    0x0008  8
LOCKOUT 0x0010  16
PASSWD_NOTREQD  0x0020  32
PASSWD_CANT_CHANGE 0x0040   64
ENCRYPTED_TEXT_PWD_ALLOWED  0x0080  128
TEMP_DUPLICATE_ACCOUNT  0x0100  256
NORMAL_ACCOUNT  0x0200  512
INTERDOMAIN_TRUST_ACCOUNT   0x0800  2048
WORKSTATION_TRUST_ACCOUNT   0x1000  4096
SERVER_TRUST_ACCOUNT    0x2000  8192
DONT_EXPIRE_PASSWORD    0x10000 65536
MNS_LOGON_ACCOUNT   0x20000 131072
SMARTCARD_REQUIRED  0x40000 262144
TRUSTED_FOR_DELEGATION  0x80000 524288
NOT_DELEGATED   0x100000    1048576
USE_DES_KEY_ONLY    0x200000    2097152
DONT_REQ_PREAUTH    0x400000    4194304
PASSWORD_EXPIRED    0x800000    8388608
TRUSTED_TO_AUTH_FOR_DELEGATION  0x1000000   16777216
PARTIAL_SECRETS_ACCOUNT 0x04000000      67108864

You must make a binary-AND of property userAccountControl with 0x002 .您必须使用0x002对属性userAccountControl进行二进制与运算。 In order to get all locked (ie disabled) accounts you can use为了获得所有锁定(即禁用)的帐户,您可以使用

(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))

For operator 1.2.840.113556.1.4.803 see LDAP Matching Rules对于操作员1.2.840.113556.1.4.803请参阅LDAP 匹配规则

In addition, I found that lockoutTime is not guaranteed for all users in AD (at least in our configuration), but will be created upon reaching the number of failed lockout attempts.此外,我发现 lockoutTime 并不能保证 AD 中的所有用户(至少在我们的配置中),但会在达到锁定尝试失败次数时创建。 So in checking for locked accounts, checking for None or an equivalent will be required as well.因此,在检查锁定帐户时,还需要检查 None 或等效项。

use this query to get the best results,使用此查询以获得最佳结果,

Get-ADUser -LDAPFilter "(&(objectCategory=Person)(objectClass=User)(lockoutTime>=1))" -Properties LockedOut Get-ADUser -LDAPFilter "(&(objectCategory=Person)(objectClass=User)(lockoutTime>=1))" -Properties LockedOut

(&(objectClass=user)(&(lockoutTime=*)(!(lockoutTime=0)))) (&(objectClass=user)(&(lockoutTime=*)(!(lockoutTime=0))))

Will return objects which are users and have a present attribute named lockoutTime which isn't equal to 0.将返回作为用户的对象,并且具有名为 lockoutTime 的 present 属性,该属性不等于 0。

Do it like this:像这样做:

def islocked(self, user, basedn, conn):

    search_filter = "(&(objectCategory=Person)(objectClass=User)(lockoutTime>=1))"
    search_attribute = ["sAMAccountName"]

    try:
        conn.search(basedn,
                        search_filter,
                        attributes=search_attribute)
        results = conn.entries
    except ldap3.core.exceptions.LDAPException as e:
        print(e)
    lockedaccounts = [x['sAMAccountName'] for x in results]
    lockedaccounts = [str(x) for x in lockedaccounts]
    lockedaccounts = [x for x in lockedaccounts]
    if user in lockedaccounts:
        return True
    else:
        return False

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM