Skip to content

Commit

Permalink
refactor: basic and support custom password compare
Browse files Browse the repository at this point in the history
  • Loading branch information
shaj13 committed Sep 16, 2020
1 parent c220d5c commit ed638f8
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 28 deletions.
40 changes: 12 additions & 28 deletions auth/strategies/basic/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package basic
import (
"context"
"crypto"
"encoding/hex"
"errors"
"fmt"
"net/http"
Expand Down Expand Up @@ -66,8 +65,8 @@ func (auth AuthenticateFunc) credentials(r *http.Request) (string, string, error

type cachedBasic struct {
AuthenticateFunc
hash crypto.Hash
cache store.Cache
comparator Comparator
cache store.Cache
}

func (c *cachedBasic) authenticate(ctx context.Context, r *http.Request, userName, pass string) (auth.Info, error) { // nolint:lll
Expand All @@ -94,8 +93,7 @@ func (c *cachedBasic) authenticate(ctx context.Context, r *http.Request, userNam
return c.authenticatAndHash(ctx, r, userName, pass)
}

err = password(pass).compare(c.hash, hashedPass[0])
return info, err
return info, c.comparator.Verify(hashedPass[0], pass)
}

func (c *cachedBasic) authenticatAndHash(ctx context.Context, r *http.Request, userName, pass string) (auth.Info, error) { //nolint:lll
Expand All @@ -109,7 +107,7 @@ func (c *cachedBasic) authenticatAndHash(ctx context.Context, r *http.Request, u
ext = make(map[string][]string)
}

hashedPass := password(pass).hash(c.hash)
hashedPass, _ := c.comparator.Hash(pass)
ext[ExtensionKey] = []string{hashedPass}
info.SetExtensions(ext)

Expand All @@ -133,6 +131,7 @@ func NewWithOptions(f AuthenticateFunc, cache store.Cache, opts ...auth.Option)
cb := &cachedBasic{
AuthenticateFunc: f,
cache: cache,
comparator: plainText{},
}

for _, opt := range opts {
Expand All @@ -144,30 +143,15 @@ func NewWithOptions(f AuthenticateFunc, cache store.Cache, opts ...auth.Option)

// SetHash set the hashing algorithm to hash the user password.
func SetHash(h crypto.Hash) auth.Option {
b := basicHashing{h}
return SetComparator(b)
}

// SetComparator set password comparator.
func SetComparator(c Comparator) auth.Option {
return auth.OptionFunc(func(v interface{}) {
if v, ok := v.(*cachedBasic); ok {
v.hash = h
v.comparator = c
}
})
}

type password string

func (p password) hash(h crypto.Hash) string {
// check if allow to hash, otherwise return plain password.
if h < crypto.MD4 {
return string(p)
}

hasher := h.New()
_, _ = hasher.Write([]byte(p))
sum := hasher.Sum(nil)
return hex.EncodeToString(sum)
}

func (p password) compare(h crypto.Hash, hashedPass string) error {
if p.hash(h) == hashedPass {
return nil
}
return ErrInvalidCredentials
}
52 changes: 52 additions & 0 deletions auth/strategies/basic/comparator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package basic

import (
"crypto"
"crypto/subtle"
"encoding/hex"
)

// Comparator is the interface implemented by types,
// that can generate password hash and compares the hashed password
// with its possible plaintext equivalent
type Comparator interface {
Hash(password string) (string, error)
Verify(hashedPassword, password string) error
}

type basicHashing struct {
h crypto.Hash
}

func (b basicHashing) Hash(password string) (string, error) {
hasher := b.h.New()
_, _ = hasher.Write([]byte(password))
sum := hasher.Sum(nil)
return hex.EncodeToString(sum), nil
}

func (b basicHashing) Verify(hashedPassword, password string) error {
hash, err := b.Hash(password)
if err != nil {
return err
}

if subtle.ConstantTimeCompare([]byte(hash), []byte(hashedPassword)) == 1 {
return nil
}

return ErrInvalidCredentials
}

type plainText struct{}

func (p plainText) Hash(password string) (string, error) {
return password, nil
}

func (p plainText) Verify(hashedPassword, password string) error {
if subtle.ConstantTimeCompare([]byte(hashedPassword), []byte(password)) == 1 {
return nil
}
return ErrInvalidCredentials
}
34 changes: 34 additions & 0 deletions auth/strategies/basic/comparator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package basic

import (
"crypto"
"testing"

"github.com/stretchr/testify/assert"
)

func TestBasicHashing(t *testing.T) {
b := basicHashing{h: crypto.SHA256}
pass := "password"
hash, err := b.Hash(pass)
match := b.Verify(hash, pass)
missmatch := b.Verify(hash, "pass")

assert.NoError(t, err)
assert.NotEqual(t, hash, pass)
assert.NoError(t, match)
assert.Equal(t, ErrInvalidCredentials, missmatch)
}

func TestPlainText(t *testing.T) {
p := plainText{}
pass := "password"
hash, err := p.Hash(pass)
match := p.Verify(hash, pass)
missmatch := p.Verify(hash, "pass")

assert.NoError(t, err)
assert.Equal(t, hash, pass)
assert.NoError(t, match)
assert.Equal(t, ErrInvalidCredentials, missmatch)
}

0 comments on commit ed638f8

Please sign in to comment.