簡體   English   中英

Active Directory - 檢查密碼是否永不過期?

[英]Active Directory - check if password never expires?

在 Visual Basic 中有沒有辦法檢查用戶的密碼是否在 Active Directory 中設置為永不過期?

我找到了一種方法來找到它的最后更改日期,但我找不到其他可用的選項。

Dim de As DirectoryServices.DirectoryEntry = GetUser(uDetails.username)
Dim objUser = GetObject(de.Path)
If objUser.PasswordLastChanged < DateTime.Now.AddMonths(-3) Then
...

在哪里可以找到所有可用objUser屬性的列表?

如果您使用 .NET 3.5 及更高版本,則應查看System.DirectoryServices.AccountManagement (S.DS.AM) 命名空間。 在這里閱讀所有相關信息:

基本上,您可以定義域上下文並輕松找到 AD 中的用戶和/或組:

// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");

if(user != null)
{
   // one of the properties exposed is "PasswordNeverExpires" (bool)
   if(user.PasswordNeverExpires)
   { 
      // do something here....      
      ...   
   }
}

新的 S.DS.AM 使在 AD 中與用戶和組一起玩變得非常容易!

對於.NET 2.0,您可以使用一些LDAP 神奇的部分是userAccountControl:1.2.840.113556.1.4.803:=65536 第一部分是您要搜索的屬性,第二部分表示“按位與”,第三部分是要檢查的按位標志,在本例中為第 17 位。 您可以在如何使用按位過濾器查詢 Active Directory了解有關Active Directory 中按位 AND 和 OR 的更多信息。

在下面的代碼中,使用域控制器(DC) 和FQDN更新SearchRoot變量。

Imports System.DirectoryServices

Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        ''//Bind to the root of our domain
        ''//    YOU_DOMAIN_CONTROLLER should be one of your DCs
        ''//    EXAMPLE and COM are the parts of your FQDN
        Dim SearchRoot As DirectoryEntry = New DirectoryEntry("LDAP://YOUR_DOMAIN_CONTROLLER/dc=EXAMPLE,dc=COM")

        ''//Create a searcher bound to the root
        Dim Searcher As DirectorySearcher = New DirectorySearcher(SearchRoot)

        ''//Set our filer. The last part is dumb but that is the way that LDAP was built.
        ''//It basically does a bitwise AND looking for the 17th bit to be set on that property "userAccountControl" which is the "password never expires" bit
        ''//See this if you care to learn more http://support.microsoft.com/kb/269181
        Searcher.Filter = "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))"
        ''//Find all of the results

        Dim Results = Searcher.FindAll()
        Dim DE As DirectoryEntry

        ''//Loop through each result
        For Each R As SearchResult In Results

            ''//Get the result as a DirectoryEntry object
            DE = R.GetDirectoryEntry()

            ''//Output the object name
            Console.WriteLine(DE.Name)
        Next
    End Sub

End Class

您可以使用以下最初來自此處的代碼,這些代碼是我從 C# 翻譯過來的,並根據您的問題進行了一些修改(添加了一個 getter):

Dim pwdNeverExpires = getPasswordNeverExpires("Tim")
setPasswordNeverExpires("Tim", True)

' See http://msdn.microsoft.com/en-us/library/aa772300(VS.85).aspx
<Flags()> _
Private Enum ADS_USER_FLAG_ENUM
    ADS_UF_SCRIPT = 1
    ' 0x1
    ADS_UF_ACCOUNTDISABLE = 2
    ' 0x2
    ADS_UF_HOMEDIR_REQUIRED = 8
    ' 0x8
    ADS_UF_LOCKOUT = 16
    ' 0x10
    ADS_UF_PASSWD_NOTREQD = 32
    ' 0x20
    ADS_UF_PASSWD_CANT_CHANGE = 64
    ' 0x40
    ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128
    ' 0x80
    ADS_UF_TEMP_DUPLICATE_ACCOUNT = 256
    ' 0x100
    ADS_UF_NORMAL_ACCOUNT = 512
    ' 0x200
    ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 2048
    ' 0x800
    ADS_UF_WORKSTATION_TRUST_ACCOUNT = 4096
    ' 0x1000
    ADS_UF_SERVER_TRUST_ACCOUNT = 8192
    ' 0x2000
    ADS_UF_DONT_EXPIRE_PASSWD = 65536
    ' 0x10000
    ADS_UF_MNS_LOGON_ACCOUNT = 131072
    ' 0x20000
    ADS_UF_SMARTCARD_REQUIRED = 262144
    ' 0x40000
    ADS_UF_TRUSTED_FOR_DELEGATION = 524288
    ' 0x80000
    ADS_UF_NOT_DELEGATED = 1048576
    ' 0x100000
    ADS_UF_USE_DES_KEY_ONLY = 2097152
    ' 0x200000
    ADS_UF_DONT_REQUIRE_PREAUTH = 4194304
    ' 0x400000
    ADS_UF_PASSWORD_EXPIRED = 8388608
    ' 0x800000
    ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 16777216
    ' 0x1000000
End Enum

Protected Overridable Function getPasswordNeverExpires(ByVal userName As String) As Boolean
    Const userNameString As String = "userName"
    Const userFlagsString As String = "userFlags"

    Dim machineName As String = Environment.MachineName

    Dim userInThisComputerDirectoryEntry As DirectoryEntry = getUserInThisComputerDirectoryEntry(machineName, userName)
    If userInThisComputerDirectoryEntry Is Nothing Then
        Throw New ArgumentException("not found in " & machineName, userNameString)
    End If

    Dim userFlagsProperties As PropertyValueCollection = userInThisComputerDirectoryEntry.Properties(userFlagsString)
    Dim userFlags As ADS_USER_FLAG_ENUM = CType(userFlagsProperties.Value, ADS_USER_FLAG_ENUM)

    Return userFlags = (userFlags Or ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD)
End Function

Protected Overridable Sub setPasswordNeverExpires(ByVal userName As String, ByVal passwordNeverExpires As Boolean)
    Const userNameString As String = "userName"
    Const userFlagsString As String = "userFlags"

    Dim machineName As String = Environment.MachineName

    Dim userInThisComputerDirectoryEntry As DirectoryEntry = getUserInThisComputerDirectoryEntry(machineName, userName)
    If userInThisComputerDirectoryEntry Is Nothing Then
        Throw New ArgumentException("not found in " & machineName, userNameString)
    End If

    Dim userFlagsProperties As PropertyValueCollection = userInThisComputerDirectoryEntry.Properties(userFlagsString)

    Dim userFlags As ADS_USER_FLAG_ENUM = CType(userFlagsProperties.Value, ADS_USER_FLAG_ENUM)
    Dim newUserFlags As ADS_USER_FLAG_ENUM = userFlags

    If passwordNeverExpires Then
        newUserFlags = newUserFlags Or ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD
    Else
        newUserFlags = newUserFlags And (Not ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD)
    End If

    userFlagsProperties.Value = newUserFlags

    userInThisComputerDirectoryEntry.CommitChanges()
End Sub

Protected Overridable Function getUserInThisComputerDirectoryEntry(ByVal machineName As String, ByVal userName As String) As DirectoryEntry
    Dim computerDirectoryEntry As DirectoryEntry = getComputerDirectoryEntry(machineName)

    Const userSchemaClassName As String = "user"
    Return computerDirectoryEntry.Children.Find(userName, userSchemaClassName)
End Function

Protected Overridable Function getComputerDirectoryEntry(ByVal machineName As String) As DirectoryEntry
    'Initiate DirectoryEntry Class To Connect Through WINNT Protocol
    ' see: http://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.path.aspx
    Const pathUsingWinNTComputerMask As String = "WinNT://{0},computer"
    Dim path As String = String.Format(pathUsingWinNTComputerMask, machineName)
    Dim thisComputerDirectoryEntry As New DirectoryEntry(path)
    Return thisComputerDirectoryEntry
End Function

您必須添加對System.DirectoryServices的引用。 我已經在 Windows Server 2008 和 .NET Framework 4(它也應該在 2.0 下工作)上測試了它,沒有Active Directory 但是自己檢查一下並隨意擴展它以獲取/設置其他屬性或連接到其他機器( SomeDomain/OtherComputerName而不是Environment.MachineName )。

public bool isPasswordExpired(String p_UserName, String p_DomainName)
{
    bool m_Check=false;

    int m_Val1 = (int)de1.Properties["userAccountControl"].Value;
    int m_Val2 = (int) 0x10000;

    if (Convert.ToBoolean(m_Val1 & m_Val2))
    {
        m_Check = true;
    } //end

    return m_Check
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM