• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2085
  • Last Modified:

Change Active Directory User Password method SetPassword and ASP.Net

Hi,

I cannot make the following code work in asp.net. It works fine in Console application.

string strLDAP = "LDAP://192.168.0.2CN=jdoe,OU=sample_ou,DC=MYDOMAIN,DC=local";
               DirectoryEntry entry  = new DirectoryEntry(strLDAP,"administrator","abcde",AuthenticationTypes.ServerBind);
               object native = entry.NativeGuid;
               entry.Invoke("SetPassword",new object[] {"testing"});
               Response.Write("Authenticated.<br>");
               Response.Write(entry.Properties["name"].Value);

This always give me the exception: System.Runtime.InteropServices.COMException: One or more input parameters are invalid
at entry.Invoke("SetPassword",new object[] {"testing"});

I have already tried using the AuthenticationType as a secure socket layer but that gave me "The server is not operational." . This thing is really annoying and wants me to shift my application to Windows as it works fine there. Any suggestions regarding changing the user password in active directory using ASP.net will be very helpful.

Thanks, Nauman.
0
nauman_ahmed
Asked:
nauman_ahmed
1 Solution
 
nauman_ahmedAuthor Commented:
I have already searched a lot on the net and tried almost everything. I will be really very thankful if a working solution is posted.

Thanks, Nauman.
0
 
RobertRFreemanCommented:
Can you access Active Directory at all from the web server?
0
 
ihenryCommented:
Hi nauman,
I use the following function to reset user password. The userName parameters need to be a "Domain Admins" or "Account operators (Domain Account operators)" or any user which has proper rights to change password.

private String adminAccountName = @"Domain\Admins";
private String adminPassword = @"adminpwd";
public void ChangePassword(String ldapPath, String userName, String newPassword)
{
      DirectoryEntry de = new DirectoryEntry(ldapPath, adminAccountName, adminPassword, AuthenticationTypes.Secure);
      DirectorySearcher ds = new DirectorySearcher(de);

      String qry = String.Format("(&(objectCategory=person)(sAMAccountName={0}))", userName);
      ds.Filter = qry;
      ds.Sort.PropertyName = "cn";
      try
      {
            SearchResult sr = ds.FindOne();
            DirectoryEntry user = sr.GetDirectoryEntry();
            user.Invoke("SetPassword", new object[] {"" + newPassword + ""} );
            user.CommitChanges();
      }
      catch (Exception)
      {
            throw;
      }
      finally
      {
            if (de != null) de.Dispose();
            if (ds != null) ds.Dispose();
      }
}
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
nauman_ahmedAuthor Commented:
Thanks for the replies. I have noticed one thing in the LDAP connection string that if I use the WinNt: prefix, SetPassword  work fine however if I use the connection string having the LDAP: prefix it gives me an exception where I invoke the SetPassword command.

JHenry: How you are defining the connection string for active directory? Can you post it here? Also currently I am trying to manange the active directory from another server. Will this make any difference?
 
Thanks, Nauman.
0
 
ihenryCommented:
The your ldap path looks incorrect (if it's not typo error), it should be
string strLDAP = "LDAP://192.168.0.2/CN=jdoe,OU=sample_ou,DC=MYDOMAIN,DC=local";

This is the connection string format for ldap provider
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/ldap_adspath.asp

I found WinNT provider is giving weird behaviour for some reasons especially when the code is running in ASP.NET environment. You should use ldap provider when accessing active directory.

Have you tried my code?
0
 
ihenryCommented:
Nauman, to get SetPassword to work your codes need to do the following
1. bind to a user account which has proper access right ("Reset Password" extended control access right) to set the password.
2. use secure binding (SSL or kerberos) instead of simple binding.
3. make sure the supply new password match DC password policy complexity.
0
 
nauman_ahmedAuthor Commented:
Jhenry,

I am trying to use the method that you have used to reset the password but I am getting System.UnauthorizedAccessException: Access is denied. Impersonation is true for my application and I am logging in using the admin account. Any suggestions?

Thanks, Nauman.
0
 
ihenryCommented:
Can you give me more information of the parameters being passed to the function, the provider type, the binding user account type, and asp.net authentication type. Do you have password policy enabled in the DC and do you have SSL setup or kerberos enabled in the active directory?
0
 
ihenryCommented:

Nauman,

When invoking SetPassword, LDAP provider initially tries to establish 128-bit SSL connection. If the connection is unsuccessful, second attempt is to try to use Kerberos. And if Kerberos is unsuccessful, it then calls the AD specific network management API, NetUserChangePassword function.

Since with SetPassword you can change a user password without need to know the original password, the caller must have Reset Password extended control access right which usually given out to Domain Admins or Account Operators (Domain Account Operators). If you want something for your app users to change their own password, using SetPassword is not a good way to go. Because you need to grant such level of permission to all users and use ChangePassword would be a better choice.

IADsUser::SetPassword
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/iadsuser_setpassword.asp

NetUserChangePassword
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netuserchangepassword.asp

User-Change-Password extended right
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adschema/adschema/r_user_change_password.asp

IADsUser::ChangePassword
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/iadsuser_changepassword.asp
0
 
ihenryCommented:
>> System.UnauthorizedAccessException: Access is denied.
>> Impersonation is true for my application...
>> I am logging in using the admin account..

Another reason might be caused... if you use my method and adminAccountName var not equal to Admin account then rely on asp.net context user (impersonate to true, logging with admin account, "Integrated Authentication" is selected in IIS and AD relies on different machine), SetPassword won't work. This is due to the double-hop issue. The good practice is always passing hard credentials to your DirectoryServices code through the class constructor, or by using the username and password properties with a user account that has sufficient access rights to do a particular task.
0
 
nauman_ahmedAuthor Commented:
Thanks JHenry and your help is really great :) Can you tell me if Kerberos authetication is enabled by default on Windows 2003 Server and if SSL communication can work by just installing the SSL certificate on the server or there are some additional steps involve in this kind of communication.

Thanks, Nauman.
0
 
nauman_ahmedAuthor Commented:
Also is it possible to delete user from the ActiveDirectory? If so which method should be used?

Thanks, Nauman.
0
 
ihenryCommented:

Try to setup a network sniffer to sniff of the traffic to know what protocol is being used. Normally, SSL/LDAP is port 636 and the Kerberos set password port is 464 (If I'm not mistaken). SSL here means, an SSL connection must be established from client to Server. Here some articles from microsoft regarding this matter.

http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/security/tkerbdel.mspx
http://www.microsoft.com/technet/Security/prodtech/win2000/secwin2k/a0701.mspx


To delete a user from AD is pretty simple
DirectoryEntry de = new DirectoryEntry();
de.Path = ldapPath; // the user distinguishedName that to be deleted
de.User = Username; // user account which has sufficient rights to delete object in AD
de.Password = password;
entry.RefreshCache();
de.Parent.Children.Remove( de );
de.Parent.CommitChanges();


HTH
0
 
ihenryCommented:

hi Nauman
any luck so far?
0
 
nauman_ahmedAuthor Commented:
hi ihenry,

Sorry I was bit late in replying. There is a deadline coming in two days and that stopped me working on the AD thing. I will continue working on it after 30th. So hopefully will post the response next week.

Thanks for all of your help :), Nauman.
0
 
ihenryCommented:

no problem Nauman, take your time :o)
0
 
erikkingCommented:
 user.Invoke("SetPassword", new object[] {"" + newPassword + ""} );

This command does not work in Active Directory which run on Window 2003.
With an Exception error message that "The filename, directory name, or volume label syntax is incorrect."

So...Please help me..!!
0
 
nauman_ahmedAuthor Commented:
I have the following code that work fine in Windows 2003:

DirectoryEntry obDirEntry = new DirectoryEntry("WinNT://"+ConfigurationSettings.AppSettings["AD_SERVER_ADDR"]
                                          ,ConfigurationSettings.AppSettings["AD_ADMINISTRATOR_ID"]
                                          ,CryptoLibrary.DecryptData(ConfigurationSettings.AppSettings["AD_ADMINISTRATOR_PASSWORD"]));
DirectoryEntries entries = obDirEntry.Children;
DirectoryEntry obUser = entries.Find(UserID, "User");
obUser.Invoke("SetPassword", strUserPassword);
obUser.CommitChanges();

HTH, Nauman.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

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