Active Directory - проверить, не истек ли срок действия пароля? - PullRequest
3 голосов
/ 30 августа 2011

Есть ли способ в 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 ]

5 голосов
/ 30 августа 2011

Если вы используете .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!

2 голосов
/ 30 августа 2011

Для .NET 2.0 вы можете использовать LDAP . Волшебная часть - userAccountControl:1.2.840.113556.1.4.803:=65536. Первая часть - это свойство, которое вы хотите найти, вторая - «побитовое И», а третья - побитовый флаг для проверки, в данном случае 17-й бит. Подробнее о побитовом И и ИЛИ в Active Directory можно узнать в Как запросить Active Directory с помощью побитового фильтра .

В приведенном ниже коде обновите переменную SearchRoot с помощью контроллера домена (DC) и FQDN .

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
1 голос
/ 31 августа 2011
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
}
1 голос
/ 30 августа 2011

Вы можете использовать следующий код из здесь , который я перевел с C # и немного изменил в соответствии с вашим вопросом (добавил геттер):

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).

...