AD Change Password WebPart
Update 30/1/2009
See the latest post about this at zevenseas AD ChangePassword WebPart released where you can find the link download this ;)
It was always a nice to have for our extranet environment to have a webpart available within SharePoint to let users change their password instead of using an isolated .NET web application (no.. not a SharePoint WebApplication ;)). As it turned out in the last couple of days it became a must-have since the webapplication didn't seem to work properly anymore. Please note that everything did run smoothly for 2yrs. Although a couple of weeks ago we migrated the environment from 2003 to 2007, ever since users received errors like "The server is not operational" when they tried to change their password.
So I once again turned on my best friend Google and try to find any free/opensource ChangePassword webparts. Unfortunately I couldn't find one so I wrote one myself (more fun anyway eh? ;)) Luckily enough I could re-use some of the code that I used to build the webapplication.
So how does my webpart look like in code?
using ActiveDs; using Microsoft.SharePoint; using Microsoft.SharePoint.WebControls; using System; using System.DirectoryServices; using System.Web.UI.WebControls; namespace ChangePassword { public class ChangePasswordWebpart : System.Web.UI.WebControls.WebParts.WebPart { private TextBox oldpassword; private TextBox newpassword; private TextBox checknewpassword; private LinkButton btn; private Label output; protected override void CreateChildControls() { this.oldpassword = new TextBox(); this.oldpassword.TextMode = TextBoxMode.Password; this.Controls.Add(oldpassword); this.newpassword = new TextBox(); this.newpassword.TextMode = TextBoxMode.Password; this.Controls.Add(newpassword); this.checknewpassword = new TextBox(); this.checknewpassword.TextMode = TextBoxMode.Password; this.Controls.Add(checknewpassword); this.btn = new LinkButton(); this.btn.Click += new EventHandler(btn_Click); this.btn.Text = "Change Password"; this.Controls.Add(btn); this.output = new Label(); this.Controls.Add(output); base.CreateChildControls(); } void btn_Click(object sender, EventArgs e) { if (newpassword.Text.ToString() == checknewpassword.Text.ToString()) { SPWeb webContext = SPControl.GetContextWeb(Context); string strLoginName = webContext.CurrentUser.LoginName; int iPosition = strLoginName.IndexOf("\\") + 1; strLoginName = strLoginName.Substring(iPosition); DirectoryEntry entry = new DirectoryEntry("LDAP://domain.com", strLoginName, oldpassword.Text.ToString(), AuthenticationTypes.Secure); DirectorySearcher search = new DirectorySearcher(entry); search.Filter = "(SAMAccountName=" + strLoginName + ")"; search.SearchScope = SearchScope.Subtree; search.CacheResults = false; SearchResultCollection results = search.FindAll(); if (results.Count > 0) { foreach (SearchResult result in results) { try { entry = result.GetDirectoryEntry(); } catch (Exception error) { output.Text += "<BR>" + error.Message.ToString(); } } try { entry.Invoke("ChangePassword", new object[] { oldpassword.Text.ToString(), newpassword.Text.ToString() }); entry.CommitChanges(); output.Text += "<BR> Password is changed"; } catch (Exception) { output.Text += "<b> Password couldn't be changed due to restrictions<b>"; } } else { output.Text += "<BR> User not found or bad password"; } } else { output.Text += "<BR>Passwords don't match"; } } protected override void Render(System.Web.UI.HtmlTextWriter writer) { string strLoginName = string.Empty; try { SPWeb webContext = SPControl.GetContextWeb(Context); strLoginName = webContext.CurrentUser.LoginName; } catch (Exception) { output.Text += "<BR> Please sign in first using the 'Sign In' button above"; } if (strLoginName != string.Empty) { writer.Write("<table border=0>"); writer.Write("<tr>"); writer.Write("<td class='ms-vb'>"); writer.Write("Current password:"); writer.Write("</td>"); writer.Write("<td class='ms-vb'>"); oldpassword.RenderControl(writer); writer.Write("</td>"); writer.Write("<td class='ms-vb'>"); writer.Write("</td>"); writer.Write("</tr>"); writer.Write("<tr valign='top'>"); writer.Write("<td class='ms-vb'>"); writer.Write("New password:"); writer.Write("</td>"); writer.Write("<td class='ms-vb'>"); newpassword.RenderControl(writer); writer.Write("</td>"); writer.Write("<td class='ms-vb'>"); writer.Write("</td>"); writer.Write("</tr>"); writer.Write("<tr valign='top'>"); writer.Write("<td class='ms-vb'>"); writer.Write("Confirm new password:"); writer.Write("</td>"); writer.Write("<td class='ms-vb'>"); checknewpassword.RenderControl(writer); writer.Write("</td>"); writer.Write("<td class='ms-vb'>"); writer.Write("</tr>"); writer.Write("<tr valign='top'>"); writer.Write("</td>"); writer.Write("<td class='ms-vb'>"); writer.Write("</td>"); writer.Write("<td class='ms-vb'>"); btn.RenderControl(writer); writer.Write("</td>"); writer.Write("<td class='ms-vb'>"); writer.Write("</td>"); writer.Write("</tr>"); writer.Write("</table>"); output.RenderControl(writer); } else { output.RenderControl(writer); } } } }
You have to reference the "System.DirectoryServices" and the COM "Active DS Type Library", also when you package everything together, make sure that the Interop.ActiveDs.dll is included otherwise it doesn't work.
And at runtime it looks like this:
Hope this helps someone who is looking for the same as I was ;)
58 comments:
Robin
Your webpart is very very helpful. But I have a situation very similar and I am looking for a solution, hopefuly you can help me with that.
I have some AD users which are using their account just to check their emails through our OWA. After 90 days their password will expire automatically (Company's password policy). How can I have them change their password after 90 days. What happens is that after about 90 days they forget that their password is about expiring and after it expires they call me and ask me to reset the password.
Please help me in this if you can.
Thanks
Robin,
I had a similar need for a change password capability, but I decided to implement it as a MOSS Application page (an aspx page in _layouts, as described in one of Ted Pattison's blog posts) and I added a Custom Action to everyone's Welcome (personal actions) menu.
Ehsan,
For one of my clients, I wrote a windows service that, 80 days after their last password change, emails users a reminder to change their password.
Hi Michael,
I did the same as you did so I guess great minds think alike? ;)
@Eshan,
sorry for noticing your comment this late, but I posted a piece of code about a year ago that does exactly what you want. Check it out at http://glorix.blogspot.com/2007/04/password-reminder-updated.html
Robin
I implemented your web part. But whenever user try to change it. He is getting following error
------------
An unexpected error has occurred. Web Parts Maintenance Page: If you have permission, you can use this page to temporarily disable Web Parts or remove personal settings. For more information, contact your site administrator.
---------
Can you suggest what wrong I did? I also test the user proviliges, they have contribute accress.
Please help me out asap?
Does it work if you try to change it?
Page is loaded with out any problem, Actually enduser want to change his password, so after entering of old and new password, whne user click on "Change Password" link, he will
------------
An unexpected error has occurred. Web Parts Maintenance Page: If you have permission, you can use this page to temporarily disable Web Parts or remove personal settings. For more information, contact your site administrator.
---------
Let me know what do I need to check?
I am experiencing the same issue as Ash. I am getting the same error whenever anyone tries to change their password. I have looked over the logs and the error is not showing up. I even tried this on the administrator account to make sure this was not an access issue. No luck so far.
Just checking in to see if you had any suggestions.
Thanks!
I have the same problem and no idea how to fix it. HELP!!!
Well I guess there is something wrong with your LDAP query to the server. Probably the webpart runs into an error which I haven't covered in my try/catch blocks.
Can you make sure your LDAP path is properly set?
Or could you post your modification of the webpart?
What about this Interop.ActiveDs.dll I mean how to inlude this in the package?? maybe this is the solution to the problem.
Well you can add .dll's when you package up your webpart using tools like wspbuilder or stsdev.
Another approach is to place the Interop.ActiveDs.dll into the BIN folder of the webapplication on your webserver (together with the .dll of your webpart)
I have the issue down to my LDAP settings. I have my LDAP setup correctly on this server for Forms Authentication. This however is not working for this webpart. I don't understand why it works for Forms Authentication, but not this.
@John,
so you are using Forms Authentication instead of Windows Authentication? If so, the webpart won't work because it's created to change the Active Directory (=Windows Auth) accounts and not FBA based accounts ;)
No, I was commenting that I had one of out sites setup with Forms Authentication. I am not trying to use the webpart on the site with Forms. I was just explaining that the LDAP query worked for the site with Forms. I am using the same query for the webpart with no luck.
maybe a silly question but what's the setting of the trust level in the web.config? Did you try (or is it already) on Full trust?
I think this is the error that most of the people got:
Request for the permission of type 'System.DirectoryServices.DirectoryServicesPermission, System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' failed
Free commercially proven password change web part - stylish, localizable, supports multiple domains and forests, includes standard web (non-SharePoint user interface and even supports Microsoft ADAM users. Check it out if you have time.
More free tools on the way!
http://www.adselfservicesuite.com/
Patrick
entry.Invoke("ChangePassword", new object[] { oldpassword.Text.ToString(), newpassword.Text.ToString() });
The most first run, I was able to reset the user password, but the second time the above line throw an exception.
I have been doing some research but couldn't find any clue.
Any help will be appreciated
Hi Randy,
this could be due to the policy that is set on your domain. One of the settings is 'only change password per 24hrs'.. if this policy is active than that's why get the error messages.
Hi Robin, your webpart is very helpful, but not work normally for me. When a user type incorrectly your passwors, an error message displays on sharepoint site ("...An unexpected error has occurred..."). Another resources work normally and my environment is a sharepoint services.
Thanks!
Hi Robin,
Is it possible that you have this web part package somewhere for download? No experience with using the code.
Yes a webpart package would be very nice. Excellent work, thanks!
Well after going through a huge learning curve today I would like to offer some insight..
If you are reciving the following error
An unexpected error has occurred. Web Parts Maintenance Page: If you have permission, you can use this page to temporarily disable Web Parts or remove personal settings. For more information, contact your site administrator.
Make sure your LDAP:// string has the correct domain information. For example if your Domain Controler is abc.local the your LDAP string should look like this LDAP://DC=abc,DC=local.
I would like to ask this. I noticed that after reseting the password I am able to still log into the WSS site using my old password and my new password, however OWA will only see the new password which is a good thing..
Anyone have any sugestions.
Doug
How do you import, insert this code in to your sharepoint portal ?
Hey Robin,
When I try to add the web part to a page I'm getting the error:
"Unable to add selected web part(s)
Change my password: Cannot import this web part. "
have you run into the same problem? I would really appreciate if you could help me with this.
THANKS !
by the way why is the Interop.ActiveDs.dll file required? I don't see any reference to it in the code, except for the very first using statement, actually if you don't add this reference and you remove that line it will compile fine.
I was using the SharePoint SmartPart template to deploy the web part:
http://www.codeplex.com/smarttemplates
and for some reason it wouldn't work, I kept getting the error:
"Unable to add selected web part(s)
Change my password: Cannot import this web part. "
So I decided to do it manually following this great article:
http://www.codeguru.com/csharp/.net/net_asp/webforms/article.php/c12293__1/
And it worked like a charm.
Great work man.
Thanks for sharing.
I am new to creating webparts but somewhat familiar with coding. I have compiled the webpart to my website using the provided code with success. The webpart shows up when I view all webparts and my new webpart name is displayed. When I try to view or add the webpart, SP displays an error message, can not import webpart. Could someone help me understand why and possibly how to fix this issue?
Hello Robin
I am have implemented ADAM AUthentication on my localserver and installed ADAM. I am using directory entry as
DirectoryEntry entry = new DirectoryEntry("LDAP://localhost:389/CN=Users,OU=ADAMTest,O=ADAM,C=US", strLoginName, oldpassword.Text.ToString(), AuthenticationTypes.None);
and rest of the code as you mentioned. I am testing webpart directly on MOSS server
Now whenever I change the code I am getting following error, please let me know whats wrong I am doing? Please advise, it knocking my head too much, I tried so many things but nothing clicked
*----
User Password Change Error: at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) at System.DirectoryServices.DirectoryEntry.Bind() at System.DirectoryServices.DirectoryEntry.get_AdsObject() at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne) at System.DirectoryServices.DirectorySearcher.FindAll() at ADAMPasswordChange.ADAMPassword.btn_Click(Object sender, EventArgs e) Logon failure: unknown user name or bad password.
Logon failure: unknown user name or bad password.
*----
Hey Ani,
I had a similar problem and I solved it removing the last parameter (AuthenticationTypes.None) of the DirectoryEntry constructor.
Let us know if it helped.
Regards.
Hello Ulise
I made the changes, but still getting same error. Here is my code
*-----
DirectoryEntry entry = new DirectoryEntry("LDAP://localhost:389/CN=Users,OU=ADAMTest,O=ADAM,C=US", strLoginName, oldpassword.Text.ToString());
output.Text += " - Directory Entry 2";
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + strLoginName + ")";
search.SearchScope = SearchScope.Subtree;
search.CacheResults = false;
SearchResultCollection results = search.FindAll();
output.Text += strLoginName + "\n" + strUserName + "\n" + strMyuser + "\n" + oldpassword.Text.ToString() + "\n" + newpassword.Text.ToString() + "\n";
if (results.Count > 0)
{
foreach (SearchResult result in results)
{
try
{
entry = result.GetDirectoryEntry();
}
catch (Exception error) { output.Text += error.Message.ToString(); }
}
try
{
entry.Invoke("ChangePassword", new object[] { oldpassword.Text.ToString(), newpassword.Text.ToString() });
entry.CommitChanges();
output.Text += "Password is changed";
}
catch (Exception)
{
output.Text += "Password couldn't be changed due to restrictions";
}
}
}
catch (Exception error)
{
output.Text += "User Password Change Error:\n" + error.StackTrace.ToString() + "\n" + error.Message.ToString();
output.Text += error.Message.ToString();
}
*------
Please advise.
Hello Ulises
One more thing I forgot to mention that I am using this for FBA. It seems this web part is not for FBA. Please suggest me an alternate option/logic, if it is not for FBA.
Well.. it specifically says "AD Change Password webpart" so any FBA (like ADAM) is not really supported in this webpart.
Ani,
it might be a dumb question, but have you checked that your ldap path is correct?
Since I didn't find a suitable location to put this type of webpart I grabbed Robin's code and slightly modified it to create a stand alone page which I later added it to our sharepoint site (with the same layout of course), and it works fine.
Let me know if you want to look at it and I can send you the whole project in a zip file.
Hello Ulises
Can you please let me know how to check path is correct?
Secondly FYI, when you install ADAM, you will also get some VB script. I tested the setpassword.vbs, it works perfectly on server using same path.
Anyway I may be wrong, let me know how to check path?
Hello Ulises/Robin
Please review following VBS, I tested on commaond prompt as
LDAP://localhost:389" CN=inetuser1,O=ADAM, OU=ADAMTest,C=US newPassword123
and it is working without any problem
*-----Setpass.vbs
''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Option Explicit
Public Const ForReading = 1
Public Const ForWriting = 2
Public Const ForAppending = 8
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' Sub LogMessage() - writes a message to the screen and logfile
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub LogMessage(fsOut, Msg)
WScript.Echo(msg)
fsOut.WriteLine(msg)
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'' main()
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim oArgs
Dim oOpenDsObject
Dim oUser
Dim szProvider
Dim szNewPass
Dim szUserName
Dim szAdmin
Dim szAdminPass
'Dim szLogFile
Dim fs
Dim fsOut
Dim lngError
'On Error Resume Next
'Stop
Set oArgs = WScript.Arguments
If (oArgs.Count <> 3) Then
WScript.Echo "usage: SetPassword <-Provider-And-Server-> <-UserSuffix-> <-NewPass->"
Wscript.Echo "For example, SetPassword LDAP://localhost:389 CN=adamuser,OU=adamou,c=us NewPassword"
Else
szProvider = oArgs(0)
szUserName = oArgs(0) & "/" & oArgs(1)
szNewPass = oArgs(2)
End If
Wscript.Echo oArgs(0) & "/" & oArgs(1) & "/" & oArgs(2)
Set oUser = GetObject(szUserName)
'set special dsheuristics bit in order to be able to set password without requiring SSL
Dim searchobj, objdse, config
'Get the configuration naming context
set objdse = GetObject(oArgs(0) & "/RootDSE")
config = objdse.get("ConfigurationNamingContext")
set objdse = nothing
Set searchobj = GetObject(szProvider & "/CN=Directory Service,CN=Windows NT,CN=Services," & config )
searchobj.Put "dsheuristics", "0000000001001"
searchobj.SetInfo
' Now set the password
oUser.Put "userpassword", szNewPass
oUser.SetInfo
wscript.Echo "Setting the Password was successful"
*---------
I run above mentioned script as on command prompt in following syntex
setpass LDAP://localhost:389" CN=inetuser1,O=ADAM, OU=ADAMTest,C=US newPassword123
"Setting" a password is very different from "changing" a password. The key difference is that "setting" a password is done by using the domain admin privilege. And changing a password is changing your own password (just like you do in Windows (Ctrl+Alt+Del > Change Password). So please note that there are key differences between invoking the 'change' and the 'set'.
I have implemented the web part and installed on a web server (that is also a domain controller) with the Password couldn't be changed due to restrictions error. Can I proceed?
Pasquale
Hi Pasquale,
yes you can proceed, just take note of all the password complexity requirements of your domain controller.
Robin
Hi Robin,
the only password requirement is the minimum length set to 3 characters. But I specify password of 8-9 characters with some digits.
Pasquale
What about password history? Or the option that you can only change your password one time a day?
This is awesome, great post! I was told that this couldn't be done, so your solution is very helpful
I just finished up essentially the same thing - although not based on this code...
http://armsinfragilehands.blogspot.com/2008/11/password-reset-web-part.html
very great blog! I searched the answer for months with no luck! your blog definitely helps me a lot!
By the way I also got a tool called sharepoint password change http://www.sharepointboost.com/passwordchange.html
which is great! I mean with this tool you can send notification email to users when their passwords expired! Who you do this?
Thanks for you blog again!
Right now I just wandering with your solution could I send some notifications when some passwords are expired? Because right now I am using a web part tool called sharepoint password change which offer such feature.
Thanks again of your blog.
Robin, great idea and will save lots of hassles.
I'm not a coder nor techie person, so could you please explain where to put the code for change password webpart? I created a web part zone and then pasted the code between the tag bits, but nothing happened. Now, I'm sure I am missing some big steps in there about linking to a database etc and creating a 'blank' webpart.
Hello there
I got the source code for AD Change Password WebPart from codeplex and also downloaded and installed WSPBuilder to deploy the webpart onto sharepoint. i can build and deploy the webpart successfully but I cant see this webpart nowhere on sharepoint. So I want to put this webpart somewhere on SharePoint site to let users change their AD password, I have looked for the webpart into Site Collection etc but not there. Could you please tell me am I missing something?
any help really appreciated
Kind Regards,
Saleem
hi
this is realy gr8
i use this and it is working fine in my case.
but currently i m facing some problem like.
Users creating problem:
user detail in AD
first name: share
last name: point
user login name: share
so user login name is "share" and full name is "share point"
it is not changing password of this type of user.
if my login name and full name is similar then no problem..
any idea.
Hello,
does this work with SharePoint 2010?
Thank you!
Best wishes,
Marko
Dera Rabin,
I am facing a problem while changing the user password, it showing the error message (Password couldn't be changed due to restrictions), Kindly say me whats the problem
Dera Rabin,
I am facing a problem while changing the user password, it showing the error message (Password couldn't be changed due to restrictions), Kindly say me whats the problem
I m very new to MOSS 2007.
We have 30 users in active directory. I want to implement password policy for this moss users.
But i dont know how to link active directory to moss site..
can anyone help me with BASICS...
i have one question how to change password in sharepoint
Hi thanks for this, we also found a way but we had to pay for it, but it gave a few more options.. but wasnt free..
www.qipoint.com .. dunno if that will work for u but worked for us and so far has great support
Hi Robin
Thank you so much for this post. I am a complete newbie to sharepoint and thus was wondering that if in this webpart a link to a password reset portal URL be included? Thus if an user has an impending password expiry, they get a prompt and a link to the URL to reset their password. Can this be done? Will their be major changes in the code?
Regards
Wonderful. Made a few changes to the code for myself, specifically the LDAP, and it works like a charm. My test accounts are registering the new passwords, and the visual errors are showing up correctly.
Thanks for your hard work. You have saved my colleagues and I a number of hours.
Thanks for sharing Active directory password reset tool tips. for more info i rfer cion systems Active directory password reset tool in USA.
Post a Comment