3

I am using the following C# code in the code behind of a webform deployed in an ASP.NET 4 (4.0.30319) application pool on Server1 and Server2.

PrincipalContext pc = new PrincipalContext(ContextType.Domain, "testnet.testad.org:636", "dc=testnet,dc=testad,dc=org");
bool validated = pc.ValidateCredentials(username, password, ContextOptions.Negotiate);

Server1 is running: windows server 2003 SP2
IIS 6.0
ASP.NET version 4.0.30319

It takes between 30-60 seconds to authenticate depending on the options.
(Note: using regular ldap it authenticates immediately with no delay)

Server 2 is running: windows server 2008 SP2
IIS 7.0
ASP.NET version 4.0.30319

Running the exact same code as Server1, Server2 authenticates almost instantaneously.
(I have also tried the code against another IIS 7.0 server with the same results)

Has anyone ran into this issue before?
Is there an alternative way to authenticate on an IIS 6.0 server vs IIS 7.0 server?
Is there something I need to configure, add, remove etc.,?

Thanks for any help on this.

..............................................................................................................................................

[Update]

I turned on wireshark while making an ldaps authentication request.
I have created a file containing all requests over 636.
It can be viewed here: Server1 636 traffic

The biggest gaps are found between:

No. 1949 at 1.115583 sec - No. 06788 at 14.501754 sec
and
No. 6803 at 14.64297 sec - No. 11742 at 27.921379 sec

All other traffic on that port occurs within the same second.

NOTE: There is roughly the same amount of traffic on Server2 but it all occurs between 2-3 seconds.
It can be viewed here: Server2 636 traffic

I ran netstat -ano” command and found the following connections for ldaps when I login:

Proto Local Address Foreign Address State PID
TCP 10.1.72.74:1761 10.1.72.54:636 ESTABLISHED 3688
TCP 10.1.72.74:1800 10.1.72.54:636 ESTABLISHED 3688
TCP 10.1.72.74:1825 10.1.72.54:636 ESTABLISHED 3688

Baxter
  • 5,633
  • 24
  • 69
  • 105
  • So using port 389 the auth call happens instantaneously - the certificates that are issued from both servers when connecting over 636, are those the same? The only other time I've noticed _that_ drastic of a slow-down is when referral binds are not being suppressed properly when authorizing. Could you Wireshark the auth attempt on Server1 to see where the lull in traffic is? – X3074861X Mar 25 '13 at 14:42
  • @X3074861X Yes, using port 389 the auth call happens instantaneously. I am unsure about the certificates, but I don't have any special certificates on my dev laptop and it authenticates just fine over 636 while debugging. I ran Wireshark and made an auth attempt on Server1. I updated my question above with the results and the location of the full log file with all traffic over 636. – Baxter Mar 25 '13 at 17:19
  • I went through those Wireshark logs, and as you've probably noticed as well, the biggest snag in traffic is seen during the TLS Handshake sequences. On Server1 in Event Viewer, under the system logs, are you seeing any Warnings or Errors from Schannel? You may need to define the SSL connection in addition to the Negotiate : `bool validated = pc.ValidateCredentials(username, password, ContextOptions.Negotiate | ContextOptions.SecureSocketLayer);` – X3074861X Mar 25 '13 at 22:22
  • I took a look at the Event Viewer system logs and found a Schannel error from this morning: "A fatal error occurred when attempting to access the SSL client credential private key. The error code returned from the cryptographic module is 0x80090016." – Baxter Mar 26 '13 at 01:29
  • Date: 3/25/2013 Time: 10:11:06 AM Source: Schannel "A fatal error occurred when attempting to access the SSL client credential private key. The error code returned from the cryptographic module is 0x80090016." I have not been able to duplicate this error no matter how many times I run the slow ldaps login code. – Baxter Mar 26 '13 at 01:49
  • When I add ContextOptions.SecureSocketLayer to ValidateCredentials it rejects the username and password. – Baxter Mar 26 '13 at 03:07
  • So we've ruled out this isn't due to the creation of a sound SSL connection - the Schannel exception is too infrequent. I'm curious why adding the SecureSocket context options would cause the logins to fail though - that is strange. I found a post that may help though, not sure if you've seen it [here](http://stackoverflow.com/questions/2538064/active-directory-services-principalcontext-what-is-the-dn-of-a-container-o) The user who commented on the answer was having the same issue. If that doesn't work, I have some DirectoryServices.Protocols code that may help diagnose the issue. – X3074861X Mar 28 '13 at 15:26

3 Answers3

2

Have a look at my answer at ServerFault...

The service may not be able to access:

C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys

Your mention:

Date: 3/25/2013 Time: 10:11:06 AM Source: Schannel "A fatal error occurred when attempting to access the SSL client credential private key.

makes it probable.

Community
  • 1
  • 1
Daro
  • 1,990
  • 2
  • 16
  • 22
  • I ran process monitor and filtered results by path contains "Crypto\RSA\MachineKeys". When I ran the login page I found a lot of Access Denied entries to the path you specified. I have made the log entries available here: [Process Monitor Logs](http://www.fullstackbusinessdesign.com/forums/ldaps/process-monitor-log.CSV) What account do you mean by "service account" to give access to it? – Baxter Apr 03 '13 at 13:25
  • Additionally, in the logs the operation is "CreateFile" but the folders and machine keys the operation is being applied to already exist? The result for the folders is "Name Collision" and the result for the machine keys is "Access Denied". – Baxter Apr 03 '13 at 14:18
  • "NT AUTHORITY\NETWORK SERVICE" is getting the access denied, so give it READ / Execute permissions – Daro Apr 03 '13 at 16:16
  • I added read & execute / read permissions for "Network Service" to the key that was displaying all the access denied errors in procmon. This immediately resolved the problem. The ldaps login over 636 now works immediately and the key shows all success messages in procmon. Thank you very much for your assistance. – Baxter Apr 04 '13 at 00:26
1

Check the registry key entries to see what SSL / TLS version is supported; an issue which can result in handshake issues... (see Scenario 5 in the link given below)

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols

For some relevant scenarios and their resolutions have a read of troubleshooting ssl related issues server certificate

Paul Zahra
  • 9,522
  • 8
  • 54
  • 76
  • I checked the registry entries you mention and found the following protocols: PCT 1.0, SSL 2.0, SSL 3.0, TLS 1.0. Do I need to do anything with these? I am not having problems with https traffic over 443. As described above I am having problems with ldaps traffic over 636. However, I followed the guide provided and found: 1. The certificate does have a corresponding private key. 2. I installed and ran SSL Diagnostics with no errors. 3. I ran netstat -ano” added result to the question above. 4. I ran network monitor and saw the same gaps in time. Everything looks ok except for the time gaps? – Baxter Mar 28 '13 at 14:49
  • hmm... another #note... If the ClientCertificates property on the LdapConnection object and QueryClientCertificate property on the LdapSessionOptions object are both set, the certificate specified in the ClientCertificates property is ignored... i.e. your ssl certs seem fine, what is the ldap server spewing out? – Paul Zahra Mar 28 '13 at 15:03
  • This looks like a good place to troubleshoot / narrow down your issue... I would follow it.. http://support.microsoft.com/kb/290483... in particular Method 3: Use Microsoft Internet Explorer and Method 4: Use the WebClient sample in the Microsoft Platform SDK, seems a little too simple but may provide useful info. – Paul Zahra Mar 28 '13 at 15:06
1

PrincipalContext's ValidateCredentials method is basically a wrapper for the LDAP Bind operation. The two key articles to read for this are IADsOpenDSObject::OpenDSObject and LDAP ADsPath.

You're using SSL, so you need to specify that if you want it to be as efficient as possible. The documentation on the ContextOptions argument of the ValidateCredentials method actually sounds like it doesn't support this:

A combination of one or more ContextOptions enumeration values the options used to bind to the server. This parameter can only specify Simple bind with or without SSL, or Negotiate bind.

Assuming that I'm misinterpreting the documentation and the ValidateCredentials method really does support specifying Negotiate | SecureSocketLayer, you need to look at how you're sending the username. In the OpenDSObject article, it gives this advice on the username's format:

You may pass in lpszUserName as one of the following strings:

  1. The name of a user account, such as "jeffsmith". To use a user name by itself, you must set only the ADS_SECURE_AUTHENTICATION flag in the lnReserved parameter.

  2. The user path from a previous version of Windows NT, such as "Fabrikam\jeffsmith".

  3. Distinguished Name, such as "CN=Jeff Smith,OU=Sales,DC=Fabrikam,DC=Com". To use a DN, the lnReserved parameter must be zero or it must include the ADS_USE_SSL flag

  4. User Principal Name (UPN), such as "jeffsmith@Fabrikam.com". To use a UPN, you must assign the appropriate UPN value for the userPrincipalName attribute of the target user object.

You're setting the SSL flag, so you have to use 2, 3, or 4.

P.S. In your example code, you are specifying the domain's DNS name in the constructor. If you're specifying a server in your real code, you need to add the ServerBind flag.

Community
  • 1
  • 1
Sean Hall
  • 7,629
  • 2
  • 29
  • 44
  • The code I am using is working on three other servers, server2008, server2003, and windows 7. I believe the issue is with the server itself not the authentication code I am using. – Baxter Apr 03 '13 at 13:28
  • @Baxter There are times that setting the right flags makes a difference, for example [this question](http://stackoverflow.com/q/13406955/628981) – Sean Hall Apr 03 '13 at 14:09