views:

244

answers:

2

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

A: 

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.

ho1
Thanks for responding. The password is valid, because it is a stong password and using the "Active Directory Users" snap-in the password can be set as expected.I tried following the tutorial you gave the link to. The process works but where it instructs to change the "userpassword" attribute I think this is not applicable - it doesnt change the password - it just adds an attribute with what you specify. You can then print it back which doesnt seem right: 1> postalCode: BL4 1RR; 1> userPassword: ben; 1> givenName: Ben; It also doesnt change the password for the account. Regards,Ben
bgs264
Hmm, I think the issue may be that the tutorial relates to "Active Directory Lightweight Directory Services" when this is just "normal" Active Directory. But thanks for the idea.
bgs264
@bgs264: If you could set the exact same password with any password to that domain then that's probably proof enough that my guess was wrong and I don't think you need to worry about ldp (I haven't used it in a long time and can't remember how it works anyway).
ho1
A: 

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.

bgs264