HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Abstracting a Password Service

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
abstractingservicepassword

Problem

I want to use Microsoft.AspNet.Identity's PasswordHasher but I don't want to pollute my Domain layer with knowledge of it. As such I created an interface in my Domain layer

public interface IPasswordService
{
    string HashPassword(string password);

    bool VerifyPassword(string hashedPassword, string testPassword);
}


So I can use DI for both IPasswordHasher and IPasswordService I created an adaptor:

public class PasswordServiceAdaptor : IPasswordService, IPasswordHasher
{
    private readonly PasswordHasher hasher;

    public PasswordServiceAdaptor()
    {
        this.hasher = new PasswordHasher();
    }

    string IPasswordHasher.HashPassword(string password)
    {
        return this.hasher.HashPassword(password);
    }

    PasswordVerificationResult IPasswordHasher.VerifyHashedPassword(
        string hashedPassword, 
        string providedPassword)
    {
        return this.hasher.VerifyHashedPassword(hashedPassword, providedPassword);
    }

    string IPasswordService.HashPassword(string password)
    {
        return this.AsPasswordHasher().HashPassword(password);
    }

    bool IPasswordService.VerifyPassword(string hashedPassword, string testPassword)
    {
        var result = this.AsPasswordHasher().VerifyHashedPassword(
                         hashedPassword, 
                         testPassword);

        return result == PasswordVerificationResult.Success;
    }

    private IPasswordHasher AsPasswordHasher()
    {
        return this;
    }
}


Is this a reasonable way to go about this? Are there any better patterns I can use?

Solution

This looks quite good, but as usual improvements can be made.


private readonly PasswordHasher hasher;

instead of using the implementation, you should use the interface

private readonly IPasswordHasher hasher;


I don't see why you want to use both IPasswordHasher and IPasswordService. If your application is built upon IPasswordService you can just skip the implementation of the IPasswordHasher interface like

public class PasswordServiceAdaptor : IPasswordService
{
    private readonly IPasswordHasher hasher;

    public PasswordServiceAdaptor()
    {
        this.hasher = new PasswordHasher();
    }

    string IPasswordService.HashPassword(string password)
    {
        return this.hasher.HashPassword(password);
    }

    bool IPasswordService.VerifyPassword(string hashedPassword, string testPassword)
    {
        var result = this.hasher.VerifyHashedPassword(hashedPassword, providedPassword);

        return result == PasswordVerificationResult.Success;
    }
}


As it seems from the comments that you need to implement both interfaces, you should consider to just call the hasher directly without the call to AsPasswordHasher().

public class PasswordServiceAdaptor : IPasswordService, IPasswordHasher
{
    private readonly IPasswordHasher hasher;

    public PasswordServiceAdaptor()
    {
        this.hasher = new PasswordHasher();
    }

    string IPasswordHasher.HashPassword(string password)
    {
        return this.hasher.HashPassword(password);
    }

    PasswordVerificationResult IPasswordHasher.VerifyHashedPassword(
        string hashedPassword, 
        string providedPassword)
    {
        return this.hasher.VerifyHashedPassword(hashedPassword, providedPassword);
    }

    string IPasswordService.HashPassword(string password)
    {
        return this.hasher.HashPassword(password);
    }

    bool IPasswordService.VerifyPassword(string hashedPassword, string testPassword)
    {
        var result = this.hasher.VerifyHashedPassword(
                         hashedPassword, 
                         testPassword);

        return result == PasswordVerificationResult.Success;
    }
}

Code Snippets

private readonly IPasswordHasher hasher;
public class PasswordServiceAdaptor : IPasswordService
{
    private readonly IPasswordHasher hasher;

    public PasswordServiceAdaptor()
    {
        this.hasher = new PasswordHasher();
    }

    string IPasswordService.HashPassword(string password)
    {
        return this.hasher.HashPassword(password);
    }

    bool IPasswordService.VerifyPassword(string hashedPassword, string testPassword)
    {
        var result = this.hasher.VerifyHashedPassword(hashedPassword, providedPassword);

        return result == PasswordVerificationResult.Success;
    }
}
public class PasswordServiceAdaptor : IPasswordService, IPasswordHasher
{
    private readonly IPasswordHasher hasher;

    public PasswordServiceAdaptor()
    {
        this.hasher = new PasswordHasher();
    }

    string IPasswordHasher.HashPassword(string password)
    {
        return this.hasher.HashPassword(password);
    }

    PasswordVerificationResult IPasswordHasher.VerifyHashedPassword(
        string hashedPassword, 
        string providedPassword)
    {
        return this.hasher.VerifyHashedPassword(hashedPassword, providedPassword);
    }

    string IPasswordService.HashPassword(string password)
    {
        return this.hasher.HashPassword(password);
    }

    bool IPasswordService.VerifyPassword(string hashedPassword, string testPassword)
    {
        var result = this.hasher.VerifyHashedPassword(
                         hashedPassword, 
                         testPassword);

        return result == PasswordVerificationResult.Success;
    }
}

Context

StackExchange Code Review Q#73812, answer score: 4

Revisions (0)

No revisions yet.