Saturday, April 28, 2012

How to enable Admins to update user's password in ASP.NET

This article assumes that there is an existing database with the necessary database objects (tables, stored procs, etc.) that enable programmatic access to Membership information from .NET code via the classes in the System.Web.Security namespace. To generate the neccessary SQL Server Db objects, run the "aspnet_regsql" tool located in C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regsql.exe for .NET 4.0 apps, or C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_regsql.exe for 2.0, 3.0, and 3.5 apps. A good explanation on how to use aspnet_regsql can be found in this Scott Guthrie's blog.

A more common scenario for updating user credentials is to enable users to update passwords themselves. However, this blog discusses a case when there is a need for site's adminstrator to intervene and update a user account with a particular password.

In this blog's example, the registered users are displayed in a GridView named gvMemberUserAccounts. The currently selected User's info is displayed in a DetailsView control.


The password is updated when the "Change Password" button is clicked with the handler method below:

//****************************************************************
protected void btnChangePassword_Click(object sender, EventArgs e)
{
            string strMessage = "";
            this.lblPasswordUpdateMessage.Text = "";
            this.lblPasswordUpdateMessage.Visible = false;

            try
            {
                MembershipUser membershipUser = Membership.GetUser(this.gvMemberUserAccounts.SelectedDataKey.Value, false);

                if (membershipUser != null)
                {
                    string strRandomGeneratedPassword = membershipUser.ResetPassword();

                    if (membershipUser.ChangePassword(strRandomGeneratedPassword, this.txtPassword.Text.Trim()))
                    {

                        //Notify the user about the password change:
                        //SendEmailToUser(
this.txtPassword.Text.Trim(), this.membershipUser.Email);


                        strMessage = "Password Updated! Email sent to " + membershipUser.Email;
                    }
                    else
                    {
                        strMessage = "Password not changed!";
                    }
                }               
            }
            catch (Exception ex)
            {
                strMessage = ex.Message;
            }

            this.lblPasswordUpdateMessage.Text = strMessage;
            this.lblPasswordUpdateMessage.Visible = true;
        }


The currently selected user is retrieved from the GridView:

MembershipUser membershipUser = Membership.GetUser(this.gvMemberUserAccounts.SelectedDataKey.Value, false);

The problem is that the membershipUser.ChangePassword() method requires an existing password / new password values to be passed, and the site's admin at this point has no knowledge of the current password. To remedy this, user's password is temporarily reset:

string strRandomGeneratedPassword = membershipUser.ResetPassword();

and the method ChangePassword() is called with this reset password and the password value provided in the TextBox:

if (membershipUser.ChangePassword(strRandomGeneratedPassword, this.txtPassword.Text.Trim()))
{

    //Notify the user about the password change:
    //SendEmailToUser(this.txtPassword.Text.Trim(), this.membershipUser.Email);


    strMessage = "Password Updated! Email sent to " + membershipUser.Email;
}
else
{
    strMessage = "Password not changed!";
}


For the above method to succeed, the relevant web.config <membeship><providers> <add> node's attributes are shown in bold:

<system.web>
    ...

    <authentication mode="Forms">
      <forms loginUrl="~/Login.aspx" timeout="2880" />
    </authentication>


    <membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="20">
      <providers>
        <clear/>
        <add name="SqlAdminProvider"

                 connectionStringName="connStr"
                 enablePasswordRetrieval="false" 
                 enablePasswordReset="true"
                 requiresQuestionAndAnswer="false"

                 applicationName="/"
                 passwordFormat="Hashed"
                 maxInvalidPasswordAttempts="3"
                 minRequiredPasswordLength="7"
                 minRequiredNonalphanumericCharacters="0"
                 passwordAttemptWindow="10"
                 type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>     
       </providers>

    </membership>
    ...

</system.web>

No comments:

Post a Comment