loginsrv

Unnamed repository; edit this file 'description' to name the repository.
git clone git@jamesshield.xyz:repos/loginsrv.git
Log | Files | Refs | README | LICENSE

commit a3d3e71ff37190adadff25846560afa141c58ba3
parent 1c4e3d7311ec226ee2c06148baf90217710a28c7
Author: Sebastian Mancke <s.mancke@tarent.de>
Date:   Mon, 21 Nov 2016 23:37:10 +0100

started htpasswd implementation

Diffstat:
Ahtpasswd/auth.go | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahtpasswd/auth_file_test.go | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/htpasswd/auth.go b/htpasswd/auth.go @@ -0,0 +1,57 @@ +package htpasswd + +import ( + "encoding/csv" + "fmt" + "golang.org/x/crypto/bcrypt" + "os" + "strings" +) + +type Auth struct { + filename string + userHash map[string]string +} + +func NewAuth(filename string) (*Auth, error) { + a := &Auth{ + filename: filename, + } + return a, a.parse(filename) +} + +func (a *Auth) parse(filename string) error { + r, err := os.Open(filename) + if err != nil { + panic(err) + } + cr := csv.NewReader(r) + cr.Comma = ':' + cr.Comment = '#' + cr.TrimLeadingSpace = true + + records, err := cr.ReadAll() + if err != nil { + return err + } + + a.userHash = map[string]string{} + for _, record := range records { + if len(record) < 2 { + continue + } + a.userHash[record[0]] = record[1] + } + return nil +} + +func (a *Auth) Authenticate(username, password string) (bool, error) { + if hash, exist := a.userHash[username]; exist { + if strings.HasPrefix(hash, "$2y$") { + matchErr := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return (matchErr == nil), nil + } + return false, fmt.Errorf("unknown algorythm for user %q", username) + } + return false, nil +} diff --git a/htpasswd/auth_file_test.go b/htpasswd/auth_file_test.go @@ -0,0 +1,55 @@ +package htpasswd + +import ( + "github.com/stretchr/testify/assert" + "io/ioutil" + "testing" +) + +// password for all of them is 'secret' +const testfile = `bob-md5:$apr1$IDZSCL/o$N68zaFDDRivjour94OVeB. +bob-bcrypt:$2y$05$Hw6y1sFwh6CdwiPOKFMYj..xVSQWI3wzyQvt5th392ig8RLmeLU.6 +bob-sha:{SHA}5en6G6MezRroT3XKqkdPOmY/BfQ= +bob-foo:{fooo}sdcsdcsdc/BfQ= +` + +func TestClient_Hashes(t *testing.T) { + auth, err := NewAuth(writeTestfile()) + assert.NoError(t, err) + + //testUsers := []string{"bob-md5", "bob-bcrypt", "bob-sha"} + testUsers := []string{"bob-bcrypt"} + for _, name := range testUsers { + t.Run(name, func(t *testing.T) { + authenticated, err := auth.Authenticate(name, "secret") + assert.NoError(t, err) + assert.True(t, authenticated) + + authenticated, err = auth.Authenticate(name, "XXXXX") + assert.NoError(t, err) + assert.False(t, authenticated) + }) + } +} + +func TestClient_Hashes_UnknownAlgoError(t *testing.T) { + auth, err := NewAuth(writeTestfile()) + assert.NoError(t, err) + + authenticated, err := auth.Authenticate("bob-foo", "secret") + assert.Error(t, err) + assert.False(t, authenticated) +} + +func writeTestfile() string { + f, err := ioutil.TempFile("", "loginsrv_htpasswdtest") + if err != nil { + panic(err) + } + defer f.Close() + _, err = f.WriteString(testfile) + if err != nil { + panic(err) + } + return f.Name() +}