sources/ldap: add support for Active Directory `userAccountControl` attribute
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
21a9aa229a
commit
c251b87f8c
|
@ -10,6 +10,7 @@ from pytz import UTC
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.sources.ldap.sync.base import LDAP_UNIQUENESS, BaseLDAPSynchronizer
|
from authentik.sources.ldap.sync.base import LDAP_UNIQUENESS, BaseLDAPSynchronizer
|
||||||
|
from authentik.sources.ldap.sync.vendor.ad import UserAccountControl
|
||||||
|
|
||||||
|
|
||||||
class UserLDAPSynchronizer(BaseLDAPSynchronizer):
|
class UserLDAPSynchronizer(BaseLDAPSynchronizer):
|
||||||
|
@ -75,4 +76,8 @@ class UserLDAPSynchronizer(BaseLDAPSynchronizer):
|
||||||
)
|
)
|
||||||
ak_user.set_unusable_password()
|
ak_user.set_unusable_password()
|
||||||
ak_user.save()
|
ak_user.save()
|
||||||
|
if "userAccountControl" in attributes:
|
||||||
|
uac = UserAccountControl(attributes.get("userAccountControl"))
|
||||||
|
ak_user.is_active = not uac.ACCOUNTDISABLE
|
||||||
|
ak_user.save()
|
||||||
return user_count
|
return user_count
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
"""Active Directory specific"""
|
||||||
|
from enum import IntFlag
|
||||||
|
|
||||||
|
|
||||||
|
class UserAccountControl(IntFlag):
|
||||||
|
"""UserAccountControl attribute for Active directory users"""
|
||||||
|
|
||||||
|
# https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity
|
||||||
|
# /useraccountcontrol-manipulate-account-properties
|
||||||
|
|
||||||
|
SCRIPT = 1
|
||||||
|
ACCOUNTDISABLE = 2
|
||||||
|
HOMEDIR_REQUIRED = 8
|
||||||
|
LOCKOUT = 16
|
||||||
|
PASSWD_NOTREQD = 32
|
||||||
|
PASSWD_CANT_CHANGE = 64
|
||||||
|
ENCRYPTED_TEXT_PWD_ALLOWED = 128
|
||||||
|
TEMP_DUPLICATE_ACCOUNT = 256
|
||||||
|
NORMAL_ACCOUNT = 512
|
||||||
|
INTERDOMAIN_TRUST_ACCOUNT = 2048
|
||||||
|
WORKSTATION_TRUST_ACCOUNT = 4096
|
||||||
|
SERVER_TRUST_ACCOUNT = 8192
|
||||||
|
DONT_EXPIRE_PASSWORD = 65536
|
||||||
|
MNS_LOGON_ACCOUNT = 131072
|
||||||
|
SMARTCARD_REQUIRED = 262144
|
||||||
|
TRUSTED_FOR_DELEGATION = 524288
|
||||||
|
NOT_DELEGATED = 1048576
|
||||||
|
USE_DES_KEY_ONLY = 2097152
|
||||||
|
DONT_REQ_PREAUTH = 4194304
|
||||||
|
PASSWORD_EXPIRED = 8388608
|
||||||
|
TRUSTED_TO_AUTH_FOR_DELEGATION = 16777216
|
||||||
|
PARTIAL_SECRETS_ACCOUNT = 67108864
|
|
@ -54,6 +54,7 @@ def mock_ad_connection(password: str) -> Connection:
|
||||||
"objectSid": "user0",
|
"objectSid": "user0",
|
||||||
"objectClass": "person",
|
"objectClass": "person",
|
||||||
"distinguishedName": "cn=user0,ou=users,dc=goauthentik,dc=io",
|
"distinguishedName": "cn=user0,ou=users,dc=goauthentik,dc=io",
|
||||||
|
"userAccountControl": 66050,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
# User without SID
|
# User without SID
|
||||||
|
|
|
@ -72,7 +72,8 @@ class LDAPSyncTests(TestCase):
|
||||||
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
with patch("authentik.sources.ldap.models.LDAPSource.connection", connection):
|
||||||
user_sync = UserLDAPSynchronizer(self.source)
|
user_sync = UserLDAPSynchronizer(self.source)
|
||||||
user_sync.sync()
|
user_sync.sync()
|
||||||
self.assertTrue(User.objects.filter(username="user0_sn").exists())
|
user = User.objects.filter(username="user0_sn").first()
|
||||||
|
self.assertFalse(user.is_active)
|
||||||
self.assertFalse(User.objects.filter(username="user1_sn").exists())
|
self.assertFalse(User.objects.filter(username="user1_sn").exists())
|
||||||
|
|
||||||
def test_sync_users_openldap(self):
|
def test_sync_users_openldap(self):
|
||||||
|
|
Reference in New Issue