开发者

Setting user's password via System.DirectoryServices.Protocols in AD 2008 R2

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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜