Thursday, July 28, 2011

AD password Change

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 += "
"
+ 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"; } } else { output.Text += "
User not found or bad password"
; } } else { output.Text += "
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 += "
Please sign in first using the 'Sign In' button above"
; } if (strLoginName != string.Empty) { writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write(""); writer.Write("
"); writer.Write("Current password:"); writer.Write(""); oldpassword.RenderControl(writer); writer.Write(""); writer.Write("
"); writer.Write("New password:"); writer.Write(""); newpassword.RenderControl(writer); writer.Write(""); writer.Write("
"); writer.Write("Confirm new password:"); writer.Write(""); checknewpassword.RenderControl(writer); writer.Write(""); writer.Write("
"); writer.Write(""); btn.RenderControl(writer); writer.Write(""); writer.Write("
"
); 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:

No comments: