2

I have a base abstract class that needs an algorithm for Authentication. I have two implementations of this, one will hash a password and compare it to a stored hash, the other will use windows active directory.

But before actually doing the hash check or the windows authentication, I have extra workflow logic that must absolutely be implemented. So things like failedPasswordCount, lastAuthenticationAttemptDate, IsUserApproved, etc. must always be modified or used in the same way no matter the algorithm for Authentication.

This problem seems to me like it can be resolved using Template Method Pattern, except that, the information required to implement my two Authentication methods are different depending on which one is used.

public abstract class User
{
    public bool Authenticate() // my template method
    {
        lastAuthenticationAttemptDate = DateTime.UtcNow();
        if(IsUserApproved)
        {
            if(DoAuthenticate()) // implemented by childs
            {
                return true;
            }
            else
            {
                failedPasswordCount++;
                return false;
            }
        }
    }

    public abstract DoAuthenticate();
}

public UserWindowsLogon : User
{
    public override bool DoAuthenticate(string windowsDomain, string password)
    {
         ...
    }
}

public UserApplicationLogon : User
{
    public override bool DoAuthenticate(string password)
    {
         ...
    }
}

What is the best way to solve this problem? Is there another known pattern that already addresses this? Or anyone has a good idea?

Didier A.
  • 4,609
  • 2
  • 43
  • 45

3 Answers3

4

You could keep your base interface's "DoAuthenticate()" clean of parameters this way

public UserWindowsLogon : User
{
    public string windowsDomain;
    public string password;
    public override bool DoAuthenticate()
    {
         // Check and use windowsDomain/password values here
    }
}

or

public UserApplicationLogon : User
{
    public UserApplicationLogon(string password) : base()
    {
         this.password = password;
    }

    private string password;
    public override bool DoAuthenticate()
    {
         // use password value here
    }
}

And provide the parameter values to use when you instantiate the User derived object.

Marvin Smit
  • 4,088
  • 1
  • 22
  • 21
  • 1
    This is certainly the best way to go, and is very standard even. Each implementation get's the parameters it needs via constructor, and handles the authentication as needed. – julealgon May 06 '14 at 21:05
  • This is certainly one way to do it, but it wouldn't work in my case, because I do not know the arguments value at creation of the User, I only know them at the call point of Authenticate. – Didier A. May 06 '14 at 22:11
  • @DidierA.It indicates that `Authenticate` and `DoAuthenticate` methods should be separated into different classes, like `Authenticator.Authenticate(User)` and `User.DoAuthenticate()`. – Lightman Feb 27 '17 at 12:11
3

Assuming your client code knows what to do (what actual parameters should be applied), you can easily introduce a class hierarchy around your authentication, thus making it possible to declare the contract on the base class of such hierarchy.

public abstract DoAuthenticate( AuthenticationContext context );
...

public UserWindowsLogon : User
{
  public override bool DoAuthenticate( AuthenticationContext context )
  { 
     if ( context is UserWindowsAuthenticationContext )
     {
        // proceed
     }
  }
}

public UserApplicationLogon : User
{
  public override bool DoAuthenticate( AuthenticationContext context )
  {
     if ( context is UserAplicationAuthenticationContext )
     {
        // proceed
     }
   } 
}

public abstract class AuthenticationContext { }

public class UserWindowsAuthenticationContext : AuthenticationContext
{
   public string windowsDomain;
   public string password;
}

public class UserApplicationAuthenticationContext : AuthenticationContext
{
   public string password;
}
Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
1

This is really an example of a Strategy pattern (where is strategy is the authentication/validation mechanism) meets a Composite pattern

Validation is frequently a Composite pattern. When you break it down, you want to separate the what you want to from the how you want to do it, you get:

If foo is valid
then do something.

Here we have the abstraction is valid

I just wrote about, essentially, your case here. If you find this answer to be most awesesome, then give IT a check/vote too :)

Community
  • 1
  • 1
Christian Bongiorno
  • 5,150
  • 3
  • 38
  • 76
  • I don't see the point of Composite, but I considered using the Strategy pattern. Authenticate would take a IAuthStrategy and it would call authStrategy.Authenticate() inside the if() statement. Each strategy would take whatever parameters they need to perform their logic through it's constructor. Though I decided to go with @Wiktor Zychla answers, because it allows me to verify that the correct implementation for my type was chosen, if not, I can throw an exception. See, in my case, I do not want to give a choice of algorithm to the caller. The type should know it's implementation. – Didier A. May 06 '14 at 22:23