Active Directory - 检查密码是否永不过期?

时间:2011-08-30 16:59:16

标签: asp.net vb.net active-directory .net-2.0

在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属性的列表?

4 个答案:

答案 0 :(得分:5)

如果您使用的是.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中的用户和群组一起玩!

答案 1 :(得分:2)

对于.NET 2.0,您可以使用一些LDAP。神奇的部分是userAccountControl:1.2.840.113556.1.4.803:=65536。第一部分是要搜索的属性,第二部分是“按位AND”,第三部分是要检查的按位标志,在本例中是第17位。您可以在 How to query Active Directory by using a bitwise filter 中的Active Directory中按位AND和OR查看更多内容。

在下面的代码中,使用domain controller(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

答案 2 :(得分:1)

您可以使用最初来自here的以下代码,我已根据您的问题翻译了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的引用。我已经在没有Active Directory的Windows Server 2008上使用.NET Framework 4(它也应该在2.0下工作)进行了测试。但是请自行检查并随意扩展它以获取/设置其他属性或连接到其他计算机(SomeDomain/OtherComputerName而不是Environment.MachineName)。

答案 3 :(得分:1)

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
}
相关问题