Search code examples
c#asp.net-membershipmembershipmembership-provider

ASP.NET Membership ChangePassword control - Need to check for previous password


I have a new table that hold old passwords, I need to check if there is a match.

If there is a match I need the ChangePassword contol to NOT change the password. I need to tell the user that this password was used and pic a new one.

I can't seem to be able to interrupt the control from changing the password. Maybe I am using the wrong event.

Here is a piece of my code, or how I wish it would work. I appreciate all your help.

protected void ChangePassword1_ChangedPassword(object sender, EventArgs e)
    {
        MembershipUser user = Membership.GetUser();
        string usrName = "";
        if (user != null)
        {
            string connStr = ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString;
            SqlConnection mySqlConnection = new SqlConnection(connStr);
            SqlCommand mySqlCommand = mySqlConnection.CreateCommand();
            mySqlCommand.CommandText = "Select UserName from OldPasswords where UserName = 'test'";
            mySqlConnection.Open();
            SqlDataReader mySqlDataReader = mySqlCommand.ExecuteReader(CommandBehavior.Default);
            while (mySqlDataReader.Read())
            {
                usrName = mySqlDataReader["UserName"].ToString();
                if (usrName == user.ToString())
                {

                    Label1.Text = "Match";
                }
                else
                {
                    Label1.Text = "NO Match!";
                }
            }

Solution

  • You are overriding the wrong method, Steve. You want to override the cancellable ChangingPassword.

    Try this:

    protected void ChangePassword1_ChangingPassword(object sender, LoginCancelEventArgs e)
    {
        // do your lookup here, 
        bool passwordHasBeenPreviouslyUsed = true;
    
        if (passwordHasBeenPreviouslyUsed)
        {
            e.Cancel = true;
            // notify of error
            return;
        }
    
    }
    

    And, as per previous Q/A sessions, You should NEVER EVER EVER store a user's password1. Go to the membership table and get the salt and use that to hash the incoming password to compare to the already salt-hashed values you have stored in your lookup table.

    Good luck.

    (1) - how tenable would your position be when the CEO finds out that his password has been stored in an exploitable format? There is a level of trust given to the black mages that are us and that trust carries it's own risks. Be aware of them. ;-)

    EDIT:

    A working example:

    ChangePassword.aspx

    <%@ Page Language="C#" %>
    <%@ Import Namespace="System.Diagnostics"%>
    
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
    
        }
    
        protected void ChangePassword1_ChangingPassword(object sender, LoginCancelEventArgs e)
        {
            // works for me!
            Debugger.Break();
        }
    </script>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:ChangePassword ID="ChangePassword1" runat="server" OnChangingPassword="ChangePassword1_ChangingPassword">
            </asp:ChangePassword>
        </div>
        </form>
    </body>
    </html>
    

    Update: You may also be interested in simply defining a handler in a higher scope that will watch all password activity:

    consider this

    public void SetupPasswordActionHook()
    {
    
        //Occurs when a user is created, a password is changed, or a password is reset.
        Membership.ValidatingPassword += Membership_ValidatingPassword;
    }
    
    void Membership_ValidatingPassword(object sender, ValidatePasswordEventArgs e)
    {
    
        // Gets a value that indicates whether the System.Web.Security.MembershipProvider.ValidatingPassword event is being raised during a 
        // call to the System.Web.Security.MembershipProvider.CreateUser() method.
    
        // true if the System.Web.Security.MembershipProvider.ValidatingPassword event is being raised during a call to the 
        // System.Web.Security.MembershipProvider.CreateUser() method; otherwise, false.
        bool isNewUser = e.IsNewUser;
    
        // Gets the password for the current create-user, change-password, or reset-password action.
    
        // The password for the current create-user, change-password, or reset-password action.
        string password = e.Password;
    
        // Gets the name of the membership user for the current create-user, change-password, or reset-password action.
    
        // The name of the membership user for the current create-user, change-password, or reset-password action.
        string username = e.UserName;
    
        // Gets or sets a value that indicates whether the current create-user, change-password, or reset-password action will be canceled.
    
        // true if the current create-user, change-password, or reset-password action will be canceled; otherwise, false. The default is false.
        e.Cancel = true;
    
        // Gets or sets an exception that describes the reason for the password-validation failure.
    
        // An System.Exception that describes the reason for the password-validation failure.
        e.FailureInformation = new Exception("This is why I failed your password");
    
    }