7

I am working to implement a custom Membership Provider for my .net application. I have set up the configuration for a minimum number of characters and non-alphanumeric characters, but it seems to let passwords through anyway, even when they break the rules.

OnValidatingPassword is a virtual method. The example from Microsoft does not override the method.

This question grapples with the same problem, but the author gave up on getting the answer to his question and simply overrode the function. This answer states that one does not have to override the function to have it work.

Does the base function not do anything? When I override OnValidatePassword, and simply call the base class, my function gets hit, but it never rejects my too-simple passwords.

Code sample (with a custom CreateUser function)

protected override void OnValidatingPassword(ValidatePasswordEventArgs e)
        {                        
             base.OnValidatingPassword(e);
        }
        //
        // MembershipProvider.CreateUser
        //
        public MembershipUser CreateUser(string username, string password, string globalIdentifier, string firstName, string lastName, 
            string birthDate, object providerUserKey, out MembershipCreateStatus status)
        {
            ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, password, true);
            OnValidatingPassword(args);

            if (args.Cancel)
            {
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }
Community
  • 1
  • 1
pc1oad1etter
  • 8,549
  • 10
  • 49
  • 64

1 Answers1

6

The documentation for MembershipProvider.OnValidatingPassword only states that that it raises the ValidatingPassword event if a handler is registered, not that it actually validates the password.

Looking at the method in Reflector confirms this:

protected virtual void OnValidatingPassword(ValidatePasswordEventArgs e)
{
    if (this._EventHandler != null)
    {
        this._EventHandler(this, e);
    }
}

It is confusing, but I believe the intent is that this provides a hook for external logic to participate in password validation; A custom provider would still need to write its own validation logic.

If you take a look at the source code for the SQL Membership Provider (download the Provider Toolkit Samples), you'll see that it includes logic to validate the password, and also calls OnValidatingPassword. The following code is from the CreateUser method:

if( password.Length < MinRequiredPasswordLength )
{
    status = MembershipCreateStatus.InvalidPassword;
    return null;
}

int count = 0;

for( int i = 0; i < password.Length; i++ )
{
    if( !char.IsLetterOrDigit( password, i ) )
    {
        count++;
    }
}

if( count < MinRequiredNonAlphanumericCharacters )
{
    status = MembershipCreateStatus.InvalidPassword;
    return null;
}

if( PasswordStrengthRegularExpression.Length > 0 )
{
    if( !Regex.IsMatch( password, PasswordStrengthRegularExpression ) )
    {
        status = MembershipCreateStatus.InvalidPassword;
        return null;
    }
}

ValidatePasswordEventArgs e = new ValidatePasswordEventArgs( username, password, true );
OnValidatingPassword( e );

if( e.Cancel )
{
    status = MembershipCreateStatus.InvalidPassword;
    return null;
}

Edit

I think part of the confusion is based on the name of OnValidatingPassword, and that it seems to imply that it is handling password validation, rather than raising an event to let other code validate the password. For what it's worth, I understand the confusion - it would probably be clearer if the method had been named RaiseValidatingPasswordEvent.

In any case, you can check the Event Design guidelines for .NET 4. About halfway down the page, you'll find this:

Do use a protected virtual method to raise each event.

The name of the protected virtual method should be the same as the event name prefixed with On. For example, the protected virtual method for an event named "TimeChanged" is named "OnTimeChanged".

Jeff Ogata
  • 56,645
  • 19
  • 114
  • 127
  • I may not have made it clear, but when I do override the base method, my method does get called. So it's not a question of whether or not the method gets called -- it just seems to *not do anything* – pc1oad1etter Oct 04 '11 at 21:41
  • Right - it doesn't do anything besides raise the `ValidatingPassword` event. `OnValidatingPassword` does not do any validation itself. – Jeff Ogata Oct 04 '11 at 21:47
  • Thanks for the response. How can OnValidatingEvent be responsible for raising the ValidatingPassword event -- isn't it responding *to* the ValidatingPassword event? – pc1oad1etter Oct 04 '11 at 21:54
  • It's common to create virtual methods to raise events named `OnSomeEvent(EventArgs args)` and then actually raise the event there. See this [answer](http://stackoverflow.com/questions/724085/events-naming-convention-and-style/724114#724114). So `OnValidatingEvent` isn't responding to the event - it's raising it. – Jeff Ogata Oct 04 '11 at 22:01
  • @pc1oad1etter, please see my edit - I added a better source of information regarding the name of `OnValidatingPassword`. HTH. – Jeff Ogata Oct 04 '11 at 22:21
  • Thanks for your time. Let me see if I can summarize your position -- the base class does do something (it raises the event.) However, the implementer is required to handle even cases such as minimum password length on his own. Additionally, the Microsoft example is either incomplete or in error, as is the answer I linked to that says one does not need to override the method. Accurate? – pc1oad1etter Oct 07 '11 at 15:10
  • @pc1oad1etter yes, that is accurate. I believe that example is incorrect - nowhere do they have code that actually validates the password, and we know that `MembershipProvider` does not do it. The answer you linked to is correct - you can override `OnValidatingPassword` and put your validation logic there, but you don't *have* to - see my next comment. – Jeff Ogata Oct 07 '11 at 18:18
  • Other ways you could do this instead of overriding `OnValidatingPassword`: (1) attach a handler to the `ValidatingPassword` event with the validation logic and let the base `MembershipProvider.OnValidatingPassword` call it, (2) put the validation logic in the `CreateUser` method (as the `SqlMembershipProvider` does), or (3) put validation logic in a separate method in your provider and call that method from `CreateUser`, `ChangePassword`, and wherever else you might need to validate a password. – Jeff Ogata Oct 07 '11 at 18:19
  • I'm marking this as correct, but I'm pretty surprised to hear that the linked resources have such misinformation. – pc1oad1etter May 07 '12 at 15:59