在 AD 2008 R2 中通过 System.DirectoryServices.Protocols 设置用户密码
我正在从 .net 应用程序 (asp.net VB .net 4.0) 连接到 DMZ 中的 Microsoft Active Directory 服务器。我需要在名为“SingleCustomerAccount”的组织单元中创建一个新的“inetorgperson”。
我必须使用 System.DirectoryServices.Protocols 命名空间来完成所有工作,因为 ADSI 类(System.DirectoryServices 命名空间)无法跨 DMZ 正常工作。
无论如何,连接到 Windows Server 2003 R2 上的 Active Directory 工作正常;但是,为了升级,我们正在 Windows Server 2008 R2(林和域的本机模式下的 2008r2)上针对 Active Directory 运行测试。
我现有的创建用户的代码不起作用。
System.DirectoryServices.Protocols.DirectoryOperationException: The server cannot handle directory requests. at System.DirectoryServices.Protocols.LdapConnection.ConstructResponse(Int32 messageId, LdapOperation operation, ResultAll resultType, TimeSpan requestTimeOut, Boolean exceptionOnTimeOut) at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout) at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request) at Salford.LDAP.LDAPUser.SaveNewToDirectory(String UsersFirstPassword) in C:\Projects\SCA\App_Code\SCA\LDAPUser.vb:line 1059 at SCA.Web.Service.CitizenService.CreateNewAccount(String Username, String Title, String FirstName, String Surname, String Street, String City, String County, String Postcode, String EmailAddress, String HomeTel, String MobileTel, String UPRN, String SpinID, Int16 AccountLevel) in C:\Projects\SCA\App_Code\CitizenService.vb:line 255
我发现当我删除添加密码属性的代码时,会创建用户,但只是没有密码。所以有问题的代码是我添加密码的地方。但 2003 年至 2008 年间发生了什么变化导致它无法发挥作用呢?
这是我的代码。
Using ldapConn As New LdapConnection(New LdapDirectoryIdentifier(LDAPServerAddress), credential)
ldapConn.SessionOptions.ProtocolVersion = 3
ldapConn.SessionOptions.Signing = Not _UseSecureConnection
ldapConn.SessionOptions.Sealing = Not _UseSecureConnection
ldapConn.SessionOptions.SecureSocketLayer = _UseSecureConnection
If _UseSecureConnection Then
ldapConn.SessionOptions.VerifyServerCertificate = New VerifyServerCertificateCallback(AddressOf ServerCallback)
End If
ldapConn.AuthType = AuthType.Negotiate
ldapConn.Bind()
Dim DistinguishedName As String = String.Format("CN={0},OU={1},{2}", Me.AccountName, Me.OrgUnit, Me.DCSuffix)
' Save this distinguished name to the local object; so that the group memberships addition works in a minute.
Me._DistinguishedName = DistinguishedName
Dim addRequest As New AddRequest(DistinguishedName, Me.LDAPUserObjectType)
'' Add an AccountName attribute
addRequest.Attributes.Add(New DirectoryAttribute(GetLDAPSchemaMapping(LDAPUserProperties.AccountName), AccountName))
'' Look in any derived classes, if they want any attributes adding as part of this save operation.
'' Hint: Derived classes will override the "GetDirectoryAttributesForAddNewRequest" function and return a list of anything they want adding
'' to the AD at the time of creation.
If Not GetDirectoryAttributesForAddNewRequest() Is Nothing Then
For Each kvp As KeyValuePair(Of String, String) In GetDirectoryAttributesForAddNewRequest()
addRequest.Attributes.Add(New DirectoryAttribute(kvp.Key, kvp.Value))
Next
End If
'' Hash up the password into a Unicode byte array and send this as the requried initial password.
addRequest.Attributes.Add(New DirectoryAttribute("unicodePwd", GetPasswordData(UsersFirstPassword)))
' Execute the request on the directory server.
Dim addResponse As DirectoryResponse = ldapConn.SendRequest(addRequest)
' Need to return the GUID, need to search against the ldap server:
Dim request As New SearchRequest(String.Format("OU={0},{1}", Me.OrgUnit, Me.DCSuffix), "(&(objectCategory=" & Me.LDAPUserObjectType & ")(sAMAccountName=" & Me.AccountName & "))", System.DirectoryServices.Protocols.SearchScope.Subtree)
Dim searchResponse As SearchResponse = DirectCast(ldapConn.SendRequest(request), SearchResponse)
returnedGuid = DirectCast(searchResponse.Entries(0).Attributes("objectGuid").Item(0), Byte())
' Set up the search request object so we can do searches now based on this new user:
Dim rq As SearchRequest = BuildLdapSearchRequest("sAMAccountName", Me.AccountName)
' ** Send the query to the LDAP server, and save the response into the private _SearchResponse object **
_SearchResponse = DirectCast(ldapConn.SendRequest(rq), SearchResponse)
End Using
对于此调用,_useSecureConnection 为 false - 绑定工作正常。 就像我说过的,当我注释掉这一行时,它起作用了:
addRequest.Attributes.Add(New DirectoryAttribute("unicodePwd", GetPasswordData(UsersFirstPassword)))
为了完整性起见,GetPasswordData 方法如下。
''' <summary>
''' Returns a unicode-encoded byte array based on the incoming password string.
''' </summary>
''' <param name="password">The password to turn into a byte array</param>
Public Function GetPasswordData(ByVal password As String) As Byte()
Dim formattedPassword As String
formattedPassword = String.Format("""{0}""", password)
Return Encoding.Unicode.GetBytes(formattedPassword)
End Function
我很欣赏任何见解...
问候 BG264
I am connecting to a Microsoft Active Directory server in a DMZ from my .net application (asp.net VB .net 4.0). I need to create a new "inetorgperson" in an orgunit called "SingleCustomerAccount".
I have had to use the System.DirectoryServices.Protocols namespace for all the work, because the ADSI classes (System.DirectoryServices namespace) wouldn't work across the DMZ properly.
Anyway it's been working fine connecting to Active Directory on Windows Server 2003 R2; however we're running tests against Active Directory on Windows Server 2008 R2 (2008r2 in native mode for forest and domain) in order to upgrade.
My existing code to create a user does not work.
System.DirectoryServices.Protocols.DirectoryOperationException: The server cannot handle directory requests. at System.DirectoryServices.Protocols.LdapConnection.ConstructResponse(Int32 messageId, LdapOperation operation, ResultAll resultType, TimeSpan requestTimeOut, Boolean exceptionOnTimeOut) at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout) at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request) at Salford.LDAP.LDAPUser.SaveNewToDirectory(String UsersFirstPassword) in C:\Projects\SCA\App_Code\SCA\LDAPUser.vb:line 1059 at SCA.Web.Service.CitizenService.CreateNewAccount(String Username, String Title, String FirstName, String Surname, String Street, String City, String County, String Postcode, String EmailAddress, String HomeTel, String MobileTel, String UPRN, String SpinID, Int16 AccountLevel) in C:\Projects\SCA\App_Code\CitizenService.vb:line 255
I have found that when I remove the bit of code that adds the password attribute, the user is created, but just without a password. So the code at fault is where I am adding the password. But what has changed between 2003 and 2008 which would have stopped it from working?
Here is my code.
Using ldapConn As New LdapConnection(New LdapDirectoryIdentifier(LDAPServerAddress), credential)
ldapConn.SessionOptions.ProtocolVersion = 3
ldapConn.SessionOptions.Signing = Not _UseSecureConnection
ldapConn.SessionOptions.Sealing = Not _UseSecureConnection
ldapConn.SessionOptions.SecureSocketLayer = _UseSecureConnection
If _UseSecureConnection Then
ldapConn.SessionOptions.VerifyServerCertificate = New VerifyServerCertificateCallback(AddressOf ServerCallback)
End If
ldapConn.AuthType = AuthType.Negotiate
ldapConn.Bind()
Dim DistinguishedName As String = String.Format("CN={0},OU={1},{2}", Me.AccountName, Me.OrgUnit, Me.DCSuffix)
' Save this distinguished name to the local object; so that the group memberships addition works in a minute.
Me._DistinguishedName = DistinguishedName
Dim addRequest As New AddRequest(DistinguishedName, Me.LDAPUserObjectType)
'' Add an AccountName attribute
addRequest.Attributes.Add(New DirectoryAttribute(GetLDAPSchemaMapping(LDAPUserProperties.AccountName), AccountName))
'' Look in any derived classes, if they want any attributes adding as part of this save operation.
'' Hint: Derived classes will override the "GetDirectoryAttributesForAddNewRequest" function and return a list of anything they want adding
'' to the AD at the time of creation.
If Not GetDirectoryAttributesForAddNewRequest() Is Nothing Then
For Each kvp As KeyValuePair(Of String, String) In GetDirectoryAttributesForAddNewRequest()
addRequest.Attributes.Add(New DirectoryAttribute(kvp.Key, kvp.Value))
Next
End If
'' Hash up the password into a Unicode byte array and send this as the requried initial password.
addRequest.Attributes.Add(New DirectoryAttribute("unicodePwd", GetPasswordData(UsersFirstPassword)))
' Execute the request on the directory server.
Dim addResponse As DirectoryResponse = ldapConn.SendRequest(addRequest)
' Need to return the GUID, need to search against the ldap server:
Dim request As New SearchRequest(String.Format("OU={0},{1}", Me.OrgUnit, Me.DCSuffix), "(&(objectCategory=" & Me.LDAPUserObjectType & ")(sAMAccountName=" & Me.AccountName & "))", System.DirectoryServices.Protocols.SearchScope.Subtree)
Dim searchResponse As SearchResponse = DirectCast(ldapConn.SendRequest(request), SearchResponse)
returnedGuid = DirectCast(searchResponse.Entries(0).Attributes("objectGuid").Item(0), Byte())
' Set up the search request object so we can do searches now based on this new user:
Dim rq As SearchRequest = BuildLdapSearchRequest("sAMAccountName", Me.AccountName)
' ** Send the query to the LDAP server, and save the response into the private _SearchResponse object **
_SearchResponse = DirectCast(ldapConn.SendRequest(rq), SearchResponse)
End Using
_useSecureConnection is false for this call - the bind works fine.
Like I have said, when I comment out this line, it works:
addRequest.Attributes.Add(New DirectoryAttribute("unicodePwd", GetPasswordData(UsersFirstPassword)))
The GetPasswordData method is below for completeness.
''' <summary>
''' Returns a unicode-encoded byte array based on the incoming password string.
''' </summary>
''' <param name="password">The password to turn into a byte array</param>
Public Function GetPasswordData(ByVal password As String) As Byte()
Dim formattedPassword As String
formattedPassword = String.Format("""{0}""", password)
Return Encoding.Unicode.GetBytes(formattedPassword)
End Function
I appreciate any insights...
Regards
bgs264
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
两台服务器的密码策略是否可能不同?或者还有其他一些政策差异?
一种检查方法可能是使用 ldp.exe 工具,看看是否可以使用完全相同的密码执行相同的操作。 这里是一个描述更改使用该工具的密码。
Is it possible that the password policies are different for the two servers? Or that there's some other policy difference?
One way to check might be to use the
ldp.exe
tool and see if you can do the same operations with the exact same password with it. Here's a link that describes changing the password using that tool.通过使用 LDAPS 而不是 LDAP 的组合解决了这个问题;放宽密码政策;完全重建应用程序;清除浏览器缓存并重新启动所有服务器。
This was fixed by a combination of using LDAPS instead of LDAP; relaxing the password policy; doing a full rebuild of the application; clearing the browser cache and rebooting all the servers.