我正在编写一些代码来使用LDAP连接查询Active Directory。我只对用户感兴趣,而且我正在测试AD的虚拟实例。
它运作良好 - 我指定要返回的特定属性并使用这些属性返回结果。
最后一项挑战是过滤掉已停用的用户。在网络上我发现这需要DirectorySearcher
Filter
属性中的以下条款:
(!(userAccountControl:1.2.840.113556.1.4.803:=2))
然而,这并没有奏效。某些残疾用户总是被退回。为了调查我写了一个小控制台应用程序来揭示所有用户属性:
请注意,我们会返回2个用户,但只有一个用户拥有'帐户控件'属性? (请注意,标签'帐户控件'正在报告userAccountControl
属性。)第二个用户,无论是启用还是禁用,都不会返回userAccountControl
属性,因此我无法对其进行过滤基于此。
有人可以解释一下吗?
*更新*
添加一些执行查询的代码:
using (DirectoryEntry de = new DirectoryEntry(ConnectionString))
{
//de.Path = Path;
de.Username = Username;
de.Password = Password;
DirectorySearcher directorySearcher = new DirectorySearcher(de);
directorySearcher.PageSize = 1001;// To Pull up more than 100 records.
// Note that the userAccountControl clause excludes disabled users
directorySearcher.Filter = string.Format("(&(objectClass=user){0}{1})", DisabledUserFilter(), query);
Console.WriteLine("------------");
Console.WriteLine(directorySearcher.Filter);
Attributes.ForEach(a => directorySearcher.PropertiesToLoad.Add(a.Key));
directorySearcher.SearchScope = SearchScope.Subtree;
try
{
var result = directorySearcher.FindAll();
...
答案 0 :(得分:2)
听起来您发现其他对象类型没有" userAccountControl" -attribute(例如Contacts)。试试这个saerch过滤器:
(&(userAccountControl=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
这个测试是否完全设置了属性,并且还设置了未设置的禁用位。
提示:您还应该包含" objectCategory = user"的过滤器。在搜索用户帐户时,因为计算机帐户也有对象类" user"和" userAccountControl" -attribute。
答案 1 :(得分:0)
您使用哪些课程来获取AD条目的详细信息?
以下是我们用来检测AD条目状态的一些代码(对不起VB.NET):
Private Sub verifyUser(ByVal username As String, ByVal password As String)
'1. Check if username exists in AD
Dim userPath As String = String.Empty
If Not findUser(username, userPath) Then
'not found
Exit Sub
End If
'2. Get AD Entry
Using adsUser As New DirectoryEntry(userPath, ADsUserName, ADsPassword)
'3. Is account Locked
If isLockedHack(adsUser) Then
'account is locked
Exit Sub
End If
'4. Is account Disabled
If isDisabled(adsUser) Then
'account is disabled
Exit Sub
End If
'5. Has account expired
If hasAccountExpired(adsUser) Then
'account expired
Exit Sub
End If
'6. Check whether user has to change password at next login
If hasToChangePassAtNextLoginHack(adsUser) Then
'change pass next login
Exit Sub
End If
'7. Has password expired
If hasPasswordExpired(adsUser) Then
'password expired
Exit Sub
End If
'8. Check whether password entered is okay
If isPassCorrect(userPath, username, password) Then
'account is fine
Else
'account is fine but password is incorrect
End If
End Using
End Sub
Private strMaxPwdAge As String = "maxPwdAge"
Private strPwdLastSet As String = "pwdLastSet"
Private strLockoutTime As String = "lockoutTime"
Private strAccountDisabled As String = "AccountDisabled"
Private Function hasToChangePassAtNextLoginHack(ByVal adsUser As DirectoryEntry) As Boolean
If adsUser.Properties.Contains(strPwdLastSet) Then
Dim objPwdLastSet As Object = adsUser.Properties(strPwdLastSet)(0)
If objPwdLastSet.LowPart = 0 Then
Return True
End If
End If
Return False
End Function
Private Function hasPasswordExpired(ByVal adsUser As DirectoryEntry) As Boolean
Dim pwdLastSet As Object
pwdLastSet = adsUser.Properties(strPwdLastSet).Value
Dim pwdDate As DateTime = GetDateFromLargeInteger(pwdLastSet)
Dim today As DateTime = Date.Now
If pwdDate.AddDays(CInt(getMaxPwdAge())).CompareTo(today) < 0 Then
Return True
Else
Return False
End If
Return False
End Function
Private Function isLockedHack(ByVal adsUser As DirectoryEntry) As Boolean
Dim pcoll As PropertyCollection = adsUser.Properties
If adsUser.Properties.Contains(strLockoutTime) Then
Dim oli2 As Object = adsUser.Properties(strLockoutTime)(0)
Dim timeVal As Long = (oli2.HighPart * &H100000000) + oli2.LowPart
If timeVal > 0 Then
Return True
End If
End If
Return False
End Function
Private Function isPassCorrect(ByVal userPath As String, ByVal user As String, _
ByVal pass As String) As Boolean
Try
Using adsUser As New DirectoryEntry(userPath, user, pass)
Dim natObj As Object = adsUser.NativeObject
adsUser.Dispose()
End Using
Catch ex As Exception
Return False
End Try
Return True
End Function
Private Function isLocked(ByVal adsUser As DirectoryEntry) As Boolean
Dim binIL As Boolean
binIL = adsUser.InvokeGet("IsAccountLocked")
If binIL Then
Return True
End If
Return False
End Function
Private Function isDisabled(ByVal adsUser As DirectoryEntry) As Boolean
If adsUser.InvokeGet(strAccountDisabled) Then
Return True
End If
Return False
End Function
Private Function hasAccountExpired(ByVal adsUser As DirectoryEntry) As Boolean
Dim myDate As DateTime = adsUser.InvokeGet("AccountExpirationDate")
Dim defExpiredDate As New DateTime(1601, 1, 1)
Dim passNeverExpiresDate As New DateTime(1970, 1, 1)
Dim today As DateTime = Date.Now
If (myDate.CompareTo(defExpiredDate) <> 0) And (myDate.CompareTo(passNeverExpiresDate) <> 0) Then
If myDate.CompareTo(today) < 0 Then
Return True
Else
Return False
End If
End If
Return False
End Function
Private Function findUser(ByVal username As String, ByRef path As String) As Boolean
path = ContainerFound(ContainerType.user, username)
If path = "" Then
Return False
End If
Return True
End Function
Private Function getMaxPwdAge() As String
Using domainRoot As New DirectoryEntry(strLDAP & strADsPath, ADsUserName, ADsPassword)
Dim maxPwdAge As LargeInteger
Dim ticksDividerValue = -864000000000
Dim numDays As Long
If domainRoot.Properties.Contains(strMaxPwdAge) Then
maxPwdAge = domainRoot.Properties(strMaxPwdAge)(0)
numDays = ((maxPwdAge.HighPart * 2 ^ 32) + maxPwdAge.LowPart) / ticksDividerValue
Else
numDays = 0
End If
Return numDays.ToString()
End Using
End Function
Private Function ContainerFound(ByVal Type As Byte, ByVal Item As String) As String
'Finds the path of an object within the active directory
Using objADObject As New DirectoryEntry
objADObject.Path = strLDAP & strADsPath
objADObject.Username = ADsUserName
objADObject.Password = ADsPassword
objADObject.AuthenticationType = AuthenticationTypes.Secure
Using objADSearcher As New DirectorySearcher(objADObject)
Dim Results As SearchResult
Select Case Type
Case ContainerType.organisationalUnit
objADSearcher.Filter = ("ou=" & Item)
Case ContainerType.group, ContainerType.user
objADSearcher.Filter = ("cn=" & Item)
End Select
Try
Results = objADSearcher.FindOne
Catch ex As Exception
'CannotConnectDomain
Return ""
End Try
If IsNothing(Results) = True Then
Return ""
Else
: Return Results.Path
End If
End Using
End Using
End Function
Public Function GetDateFromLargeInteger(ByVal largeInteger As Object) As Date
Try
Return Date.FromFileTime(GetInt64FromLargeInteger(largeInteger))
Catch e As ArgumentOutOfRangeException
Throw New ArgumentException(strNotValidVal, e)
End Try
End Function
Public Function GetInt64FromLargeInteger(ByVal largeInteger As Object) As Long
Const highShift As Long = &H100000000
Dim lowPart As Integer
Dim highPart As Integer
Dim longVal As Long
Dim largeIntType As Type
largeIntType = largeInteger.GetType()
Try
highPart = CType(largeIntType.InvokeMember("HighPart", BindingFlags.GetProperty Or BindingFlags.Public, Nothing, largeInteger, Nothing), Integer)
lowPart = CType(largeIntType.InvokeMember("LowPart", BindingFlags.GetProperty Or BindingFlags.Public, Nothing, largeInteger, Nothing), Integer)
longVal = (highPart * highShift) + lowPart
Return longVal
Catch e As MissingMethodException
Throw New ArgumentException(strInvalidCom, e)
End Try
End Function
希望它能让您简要了解我们的AD检查是如何完成的。如果有帮助,请告诉我。