Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 641
  • Last Modified:

LDAP, Web Apps, and App Pools

I have an application that is supposed to set an AD account password.  My domain admin gave me an account that has admin access to the domain to do this.  Here's the problem:

When I try to use the application, when it tries to actually set the account password, it throws an exception indicating that it doesn't have permission to do this.  However, I know the account has admin domain privileges (I've logged in manually to this account and verified this).  

I then tried to create a separate app pool and tried to run the web site under this app pool.  I configured the app pool to use the domain admin account I was given.  When I did this, I couldn't even browse to the site - it keeps saying, "Service Unavailable'.  

When I change the app pool credentials back to the default, the web site comes up but then it doesn't work as it keeps saying I don't have permissions to change the account password.  

What am I not understanding here?  Why will this not work?
0
robertpan
Asked:
robertpan
  • 7
  • 7
1 Solution
 
Robert SchuttSoftware EngineerCommented:
How do you query the AD? There is a number of different ways to do it and there's different solutions to supply the credentials for accessing the AD, which is what you need to do (I suspect).
0
 
robertpanAuthor Commented:
This is what I am doing with regard to LDAP:

        public void ChangeUserPassword(string szUser, string szOU, string szPassword, out string szErr)
        {
            string sz = "";
            string szSID = szUser;
            string szLDAPUser = "LDAP://" + vszLDAPServer + "/CN=" + szSID + "," + szOU;

            DirectoryEntry uEntry = new DirectoryEntry(szLDAPUser, vszAdmin, vszPwd);
            uEntry.Invoke("SetPassword", new object[] { szPassword });
            uEntry.Properties["LockOutTime"].Value = 0; //unlock account
            uEntry.CommitChanges();
            uEntry.Close();

            szErr = sz;
        }

I know that that credentials used in the call (stored in vszAdmin and vszPwd) work in that I can log in manually with those credentials and change a user's password.  My admins have confirmed that those credentials do have domain admin priviledges.  

I also know that when I test it, the password I use to test meets the password strength requirements.  

I also know that when I change the call to use 'changepassword' it all works.  However, 'changepassword' will not accomplish what I need to actually do.
0
 
Robert SchuttSoftware EngineerCommented:
I see a number of pages when I search for 'directoryentry invoke setpassword' that seem to indicate that there are some possible problems that you can't solve 'as is' because of a bug.

One solution I came across would be to set the password like this:

uEntry.Properties["unicodePwd"].Value = System.Text.Encoding.Unicode.GetBytes(String.Format(@"""{0}""", szPassword));

Open in new window


(and remove the call to Invoke). But I'm not entirely sure if that will work in your case.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
robertpanAuthor Commented:
That did not work either - but it did generate a different exception at least:

The server is unwilling to process the request. (Exception from HRESULT: 0x80072035)


This is with the website running under the default app pool.
0
 
Robert SchuttSoftware EngineerCommented:
I've been trying to read up on this, finding a lot of problems but some are related to other LDAP servers like iPlanet.

It seems most reactions to an 'unwilling' server (amongst the jokes about servers having feelings like that) is that you need to use SSL to do some actions like set password which is (even in the encoded form) essentially sending a cleartext password over the network.

So you could try:

DirectoryEntry uEntry = new DirectoryEntry(szLDAPUser, vszAdmin, vszPwd, AuthenticationTypes.SecureSocketsLayer);

Open in new window


But you may need to have the server especially set up to have a secure LDAP listener (I read about port 636 instead of 389).
0
 
robertpanAuthor Commented:
Making that change results in a yet different exception:
The server is not operational.  

I guess this means I do need to set up a secure LDAP listener.  I'll see what my admins can do about this (I personally have no idea how to do this).  

One thing I did note is that my original posted code works as-is from my local machine only.  It is the *only* place the code works.  I am *not* running IIS.  I use Visual Studio to host my site when I test it.  I have no idea how VS does this so I have no idea why it would work on my local machine yet no where else.
0
 
Robert SchuttSoftware EngineerCommented:
The thing I read on other sites about connecting to a secure server is to use port 636 so you would need to change 'vszLDAPServer' or put it in the string for the queried user object:

string szLDAPUser = "LDAP://" + vszLDAPServer + ":636/CN=" + szSID + "," + szOU;

Open in new window


The fact that it works locally could mean that there is another solution. Could there be a difference between the two situations regarding .NET version? As far as I'm aware the current user should not have an influence on the call once you log in to the AD with a specifed account.
0
 
robertpanAuthor Commented:
This is why I'm so confused as to what is actually going on here.  The fact that it works from my local machine with a VS hosted page means I know the code itself works and the credentials are valid.  

But it won't work anywhere else.  So I don't know what IIS is doing to my request.  Do the credentials of the app pool take precedence over the supplied credentials in the actual LDAP call?  But even if so - why can I not create an app pool with those credentials?  When I do that, the web site becomes un-browsible.  When I use the default app pool the site works but the call fails.
0
 
Robert SchuttSoftware EngineerCommented:
> Do the credentials of the app pool take precedence over the supplied credentials in the actual LDAP call?

No, it should definitely be the other way around, as you expect. The currently logged on user (or user that the process is running under when not interactive like from the app pool) is only used to access the AD if no user is specified in the call.

> why can I not create an app pool with those credentials?

Yeah, you mentioned that. I don't think you should want that. The user is specifically created for AD access and doesn't have access to the files or lacks other permissions/policy credentials (on purpose).

* * *

I did find some slightly different code you could try:

DirectoryEntry uEntry = new DirectoryEntry(szLDAPUser, vszAdmin, vszPwd, AuthenticationTypes.Secure);

Open in new window


Secure means just logging in I think, not specifically via SSL, so if you had put in :636, take that out again.
0
 
robertpanAuthor Commented:
Nope.  

When I use this code:
            DirectoryEntry uEntry = new DirectoryEntry(szLDAPUser, vszAdmin, vszPwd, AuthenticationTypes.Secure);
            uEntry.Properties["unicodePwd"].Value = System.Text.Encoding.Unicode.GetBytes(String.Format(@"""{0}""", szPassword));

I get: The server is unwilling to process the request. (Exception from HRESULT: 0x80072035)


When I use this code:
            DirectoryEntry uEntry = new DirectoryEntry(szLDAPUser, vszAdmin, vszPwd, AuthenticationTypes.Secure);
            uEntry.Invoke("SetPassword", new object[] { szPassword });

I get Access denied.  

The site is back to running  under the default app pool.  The default app pool is running under default credentials.
0
 
Robert SchuttSoftware EngineerCommented:
I've been searching for that error but I'm afraid there's a number of possible reasons. Haven't gotten anywhere with digging into that because mostly it can't apply here because it works in a certain situation, from your own machine, just not from the server. Other people have found that they needed to set certain fields (mandatory from GPO), or create the user first with relaxed security, stuff like that. In your case the user already exists so that can't be the case. One thing that does stand out is someone who after several tests found out that in the end it _was_ the strict password policy that didn't accept his new password but again I can't really see how it would then work from your local machine, because that is enforced on the server.

I tried installing OpenLdap on my machine at home to see if there was any way I could reproduce it but keep getting other errors with that, before even getting back a user object...
0
 
robertpanAuthor Commented:
For anyone interested, I did more searching and found some code that was subtly different that worked.  

string strPort = "389";
string strPath = String.Concat("LDAP://", strServer, ":", strPort, strUser);
AuthTypes = AuthenticationTypes.Signing | AuthenticationTypes.Sealing | AuthenticationTypes.Secure;
objUser = new DirectoryEntry(strPath, vszAdmin, vszPwd, AuthTypes);
objUser.RefreshCache();

intPort = Int32.Parse(strPort);

objUser.Invoke("SetOption", new object[] { ADS_OPTION_PASSWORD_PORTNUMBER, intPort });
objUser.Invoke("SetOption", new object[] {ADS_OPTION_PASSWORD_METHOD, ADS_PASSWORD_ENCODE_CLEAR});
objUser.Invoke("SetPassword", new object[] { szPassword });

This code is not hugely different than my original code - but this works.
0
 
Robert SchuttSoftware EngineerCommented:
Fair enough, no objection. Thanks for sharing. Might save someone else some time some day.
0
 
robertpanAuthor Commented:
It solved the problem.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 7
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now