Changing the autogenerated password format in the SqlMembershipProvider

Since working with ASP.Net 2.0, I’ve been using the included Membership API almost exclusively. There was one piece of it I was never crazy about: the autogenerated passwords created by the SqlMembershipProvider (and, presumably, other providers).

Let me rephrase that. I didn’t have a problem with the auto-generated passwords, which included many symbol characters. For me, it was simple enough to copy/paste the autogenerated password (which would look something like this: @&#eyue@^%#), log in, then change the password to something more memorable.

Unfortunately, I am not a good representative sample of the typical web user, and eventually I heard my clients complain about the “overly complex” autogenerated passwords. Despite the explanations of an easy workaround (copy and paste) and the added benefit of the complex passwords (more security), clients still complain.

I came up with a quick way to hack the SqlMembershipProvider to generate less complex passwords, and it was as simple as creating a new provider class that inherits from SqlMembershipProvider, then overriding the GeneratePassword method.

In the code sample below, the autogenerated password will create a fixed number of randomly generated symbols (based on the MinRequiredNonAlphanumericCharacters property), then add a series of randomly generated upper case letters to ensure a password of at least MinRequiredPasswordLength characters long (with a forced minimum of eight characters).

Using only upper case letters is just one example. You could just as easily use random digits (zero through 9), or random lower case letters. There is an argument for using random lower case letters instead of upper case letters, as people are apt to interpret an upper case “O” as a zero “0″, a problem that generally doesn’t exist with lower case letters.

Some day I may hash this out to be a more robust provider with more options on choosing the password formats, but for the immediate problem, it’s more than adequate.

namespace CustomProviders
{
    public class ExtendedSqlMembershipProvider : System.Web.Security.SqlMembershipProvider
    {
        public ExtendedSqlMembershipProvider() : base()
        {
        }
        public override string GeneratePassword()
        {
            Random rand = new Random();
            StringBuilder newpassword = new StringBuilder();
            int length = (this.MinRequiredPasswordLength < 8 ? 8 : this.MinRequiredPasswordLength);
            int symbollength = this.MinRequiredNonAlphanumericCharacters;
            int charlength = length - symbollength;

            for (int index = 1; index <= symbollength; index++)
            {
                newpassword.Append((char)rand.Next(33, 47));
            }

            for (int index = 1; index <= charlength; index++)
            {
                newpassword.Append((char)rand.Next(65, 90));
            }

            return newpassword.ToString();
        }
    }
}

Apparently, this doesn’t work in all situations.

According to Lutz Roeder’s Reflector, the CreateUserWizard control calls this:

if (this.AutoGeneratePassword)
{
    int num1 = Math.Max(10, Membership.MinRequiredPasswordLength);
    this._password = Membership.GeneratePassword(num1, Membership.MinRequiredNonAlphanumericCharacters);
}

The Membership class (a static class) has its own password hashing algorithm that ignores the hashing of the provider.

Of course, for consistency, the PasswordRecovery control calls the provider’s ResetPassword() method, which in turn calls the provider’s GeneratePassword() method. This matches my testing where the custom provider outlined above will generate passwords in the alternate format when being reset (using the PasswordRecovery control), but initial passwords are in the original format (thanks to the CreateUserWizard control).

In my opinion, this is a faulty implementation — a provider system which is ignored in one respect and recognized in another. It should not be this way.

3 comments to Changing the autogenerated password format in the SqlMembershipProvider

  • Don Wilcox

    I had a similar problem to yours. So I used your idea of replacing the membership provider to fix the reset password. Then to solve the problem in the CreateUserWizard, I just turned off AutoGeneratePassword, added an invisible TextBox named Password to the control, and in the CreatingUser event, I stuff the password control with a password generated using hte same algorithm:

    TextBox pswdTxt =
    (TextBox)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl(“Password”);
    pswdTxt.Text = MyGeneratePassword();

    Thanks for the tip, I could only find my half of it.

    Don

  • bg

    We actually have a real problem with the password format, which is that if they include angular brackets they arer sometimes not transported correctly in HTML encoded emails and if copy-pasted into a textbox they are rejected by the server as potential code injection.

    I am not sure yet if I want to go all the way of creating a new provider or if I just wrap it in a GeneratePassword class of my own which filters out the angular brackets…

  • bilyboy

    I know. I have the same thing here. Client complained about the default behavior even it’s just a matter of copy and paste the auto-gen password. How hard would that get?? It’s just a dumb argument…

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>