Solved

Change Active Directory User Password method SetPassword and ASP.Net

Posted on 2004-09-20
18
1,925 Views
Last Modified: 2007-12-19
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
Comment
Question by:nauman_ahmed
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
18 Comments
 
LVL 25

Author Comment

by:nauman_ahmed
ID: 12104507
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
 
LVL 16

Expert Comment

by:RobertRFreeman
ID: 12106108
Can you access Active Directory at all from the web server?
0
 
LVL 20

Accepted Solution

by:
ihenry earned 500 total points
ID: 12110526
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
Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

 
LVL 25

Author Comment

by:nauman_ahmed
ID: 12112031
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
 
LVL 20

Expert Comment

by:ihenry
ID: 12112369
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
 
LVL 20

Expert Comment

by:ihenry
ID: 12114660
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
 
LVL 25

Author Comment

by:nauman_ahmed
ID: 12115545
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
 
LVL 20

Expert Comment

by:ihenry
ID: 12120572
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
 
LVL 20

Expert Comment

by:ihenry
ID: 12125342

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
 
LVL 20

Expert Comment

by:ihenry
ID: 12125645
>> 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
 
LVL 25

Author Comment

by:nauman_ahmed
ID: 12126162
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
 
LVL 25

Author Comment

by:nauman_ahmed
ID: 12126181
Also is it possible to delete user from the ActiveDirectory? If so which method should be used?

Thanks, Nauman.
0
 
LVL 20

Expert Comment

by:ihenry
ID: 12126867

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
 
LVL 20

Expert Comment

by:ihenry
ID: 12170207

hi Nauman
any luck so far?
0
 
LVL 25

Author Comment

by:nauman_ahmed
ID: 12170327
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
 
LVL 20

Expert Comment

by:ihenry
ID: 12170494

no problem Nauman, take your time :o)
0
 

Expert Comment

by:erikking
ID: 14953708
 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
 
LVL 25

Author Comment

by:nauman_ahmed
ID: 14957975
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

Featured Post

Learn by Doing. Anytime. Anywhere.

Do you like to learn by doing?
Our labs and exercises give you the chance to do just that: Learn by performing actions on real environments.

Hands-on, scenario-based labs give you experience on real environments provided by us so you don't have to worry about breaking anything.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article describes relatively difficult and non-obvious issues that are likely to arise when creating COM class in Visual Studio and deploying it by professional MSI-authoring tools. It is assumed that the reader is already familiar with the cla…
In my previous two articles we discussed Binary Serialization (http://www.experts-exchange.com/A_4362.html) and XML Serialization (http://www.experts-exchange.com/A_4425.html). In this article we will try to know more about SOAP (Simple Object Acces…
If you're a developer or IT admin, you’re probably tasked with managing multiple websites, servers, applications, and levels of security on a daily basis. While this can be extremely time consuming, it can also be frustrating when systems aren't wor…
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…

695 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question