Определите, заблокирована ли учетная запись пользователя Active Directory с помощью LDAP в Python

Я проверяю входы пользователей в систему с помощью модуля ldap Python. Когда вход не удается, я получаю имя входа ldap.INVALID_CREDENTIALS, но это может быть либо из-за неправильного пароля, либо из-за того, что учетная запись заблокирована. Аккаунт блокируется после 3-й попытки.

Я хотел бы обнаружить, что учетная запись заблокирована, и сообщить об этом расстроенному пользователю вместо того же сообщения «неверный вход в систему».

В поисках решения я нашел:

  • Флаг userAccountControl LOCKED не используется AD;
  • Вместо этого следует использовать атрибут lockoutTime.

Запрос LDAP, который я должен использовать для поиска заблокированных пользователей:

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

Или для конкретного пользователя:

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

Но это не работает, запрос каждый раз не возвращает результатов.


person Daniel Reis    schedule 03.08.2012    source источник


Ответы (7)


Нулевое значение в lockoutTime означает, что он не заблокирован. Итак, вы должны попробовать это.

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

На самом деле, приведенный выше запрос все еще не на 100% правильный. Если вы прочитали мелкий шрифт в MSDN, Microsoft предлагает вам добавить атрибут Lockout-Time к атрибуту Lockout-Duration, а затем сравнить его с текущим временем. Это потому, что есть такая вещь, как продолжительность блокировки. По истечении времени блокировки пользователь автоматически разблокируется. Ноль в Lockout-Duration означает, что учетная запись заблокирована навсегда, пока ее не разблокирует администратор.

См. эту статью MSDN.

Значение этого атрибута сбрасывается только после успешного входа в учетную запись. Это означает, что это значение может быть ненулевым, но учетная запись не заблокирована. Чтобы точно определить, заблокирована ли учетная запись, необходимо добавить к этому времени значение Lockout-Duration и сравнить результат с текущим временем с учетом местных часовых поясов и летнего времени.

person Harvey Kwok    schedule 07.08.2012
comment
Я получаю ldap.FILTER_ERROR: {'desc': 'Bad search filter'} при использовании (!lockoutTime=0) или даже (lockoutTime>0). Кажется, только (!lockoutTime>=1) избегает этого. - person Daniel Reis; 31.01.2013

lockoutTime — это атрибут <not set>, поэтому проще всего использовать:

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

для непустых записей.

Обновление:

Однако это значение также устанавливается, когда срок действия пароля истекает, пароль необходимо изменить и т. д.

Итак, фильтровать нужно:

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

чтобы получить случаи, когда пользователь заблокирован, потому что он нарушил политику паролей, например, неправильно ввел пароль 5 раз.

person rbrayb    schedule 04.06.2013

Кроме того, я обнаружил, что lockoutTime не гарантируется для всех пользователей в AD (по крайней мере, в нашей конфигурации), а будет создаваться по достижении количества неудачных попыток блокировки. Таким образом, при проверке заблокированных учетных записей также потребуется проверка None или эквивалент.

person Al Baker    schedule 24.08.2012
comment
Я обнаружил, что это тоже так. Атрибут lockoutTime не будет установлен, если пользователь никогда не блокировал свою учетную запись. Если в любое время они заблокировали свою учетную запись и с тех пор вошли в систему, но их учетная запись больше не заблокирована, тогда атрибут будет установлен на 0. - person ChadSikorra; 25.02.2015

Я также нашел этот список флагов свойств: Как использовать флаги UserAccountControl

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

Вы должны выполнить бинарное И свойства userAccountControl с 0x002. Чтобы получить все заблокированные (т.е. отключенные) учетные записи, вы можете использовать

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

Для оператора 1.2.840.113556.1.4.803 см. правила сопоставления LDAP.

person Wernfried Domscheit    schedule 16.03.2016
comment
Я проверил бит блокировки и обнаружил, что он не работает. - person yanqian; 23.04.2019
comment
@yanqian вы пробовали бит ACCOUNTDISABLE (2)? - person Wernfried Domscheit; 23.04.2019

используйте этот запрос, чтобы получить наилучшие результаты,

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

person Rizwan Ranjha    schedule 03.12.2014

Делай это так:

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
person J-Bone    schedule 27.08.2020

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

Возвращает объекты, которые являются пользователями и имеют текущий атрибут с именем lockoutTime, который не равен 0.

person Jonas    schedule 21.11.2016