1
0
mirror of https://github.com/volatiletech/authboss.git synced 2025-03-05 15:15:45 +02:00

password hashing via hasher (defaults: bcrypt)

This commit is contained in:
Evghenii Maslennikov 2022-04-18 23:42:02 +03:00 committed by Stephen Afam-Osemene
parent ccfe4d1c31
commit 42f90e2471
13 changed files with 83 additions and 8 deletions

View File

@ -65,12 +65,12 @@ func (a *Authboss) Init(modulesToLoad ...string) error {
// in sessions for a user requires special mechanisms not currently provided
// by authboss.
func (a *Authboss) UpdatePassword(ctx context.Context, user AuthableUser, newPassword string) error {
pass, err := bcrypt.GenerateFromPassword([]byte(newPassword), a.Config.Modules.BCryptCost)
pass, err := a.Config.Core.Hasher.GenerateHash(newPassword)
if err != nil {
return err
}
user.PutPassword(string(pass))
user.PutPassword(pass)
storer := a.Config.Storage.Server
if err := storer.Save(ctx, user); err != nil {

View File

@ -25,6 +25,7 @@ func TestAuthbossUpdatePassword(t *testing.T) {
ab := New()
ab.Config.Storage.Server = storer
ab.Config.Core.Hasher = mockHasher{}
if err := ab.UpdatePassword(context.Background(), user, "hello world"); err != nil {
t.Error(err)

View File

@ -239,6 +239,9 @@ type Config struct {
// Mailer is the mailer being used to send e-mails out via smtp
Mailer Mailer
// Hasher hashes passwords into hashes
Hasher Hasher
// Logger implies just a few log levels for use, can optionally
// also implement the ContextLogger to be able to upgrade to a
// request specific logger.

View File

@ -6,6 +6,7 @@ import (
"crypto/sha512"
"encoding/base64"
"errors"
"github.com/volatiletech/authboss/v3/defaults"
"net/http"
"net/http/httptest"
"testing"
@ -71,6 +72,7 @@ func testSetup() *testHarness {
harness.ab.Config.Core.BodyReader = harness.bodyReader
harness.ab.Config.Core.Logger = mocks.Logger{}
harness.ab.Config.Core.Hasher = defaults.NewBCryptHasher(harness.ab.Modules.BCryptCost)
harness.ab.Config.Core.Mailer = harness.mailer
harness.ab.Config.Core.Redirector = harness.redirector
harness.ab.Config.Core.MailRenderer = harness.renderer

View File

@ -25,5 +25,6 @@ func SetCore(config *authboss.Config, readJSON, useUsername bool) {
config.Core.Redirector = NewRedirector(config.Core.ViewRenderer, authboss.FormValueRedirect)
config.Core.BodyReader = NewHTTPBodyReader(readJSON, useUsername)
config.Core.Mailer = NewLogMailer(os.Stdout)
config.Core.Hasher = NewBCryptHasher(config.Modules.BCryptCost)
config.Core.Logger = logger
}

20
defaults/hasher.go Normal file
View File

@ -0,0 +1,20 @@
package defaults
import "golang.org/x/crypto/bcrypt"
type BCryptHasher struct {
cost int
}
func NewBCryptHasher(cost int) *BCryptHasher {
return &BCryptHasher{cost: cost}
}
func (h *BCryptHasher) GenerateHash(raw string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(raw), h.cost)
if err != nil {
return "", err
}
return string(hash), nil
}

29
defaults/hasher_test.go Normal file
View File

@ -0,0 +1,29 @@
package defaults
import (
"golang.org/x/crypto/bcrypt"
"strings"
"testing"
)
func TestHasher(t *testing.T) {
t.Parallel()
hasher := NewBCryptHasher(bcrypt.DefaultCost)
hash, err := hasher.GenerateHash("qwerty")
if err != nil {
t.Error(err)
}
if hash == "" {
t.Error("Result Hash must be not empty")
}
if len(hash) != 60 {
t.Error("hash was invalid length", len(hash))
}
if !strings.HasPrefix(hash, "$2a$10$") {
t.Error("hash was wrong", hash)
}
}

5
hasher.go Normal file
View File

@ -0,0 +1,5 @@
package authboss
type Hasher interface {
GenerateHash(s string) (string, error)
}

View File

@ -3,6 +3,7 @@ package authboss
import (
"context"
"encoding/json"
"golang.org/x/crypto/bcrypt"
"net/http"
"time"
)
@ -213,3 +214,14 @@ type mockLogger struct{}
func (m mockLogger) Info(s string) {}
func (m mockLogger) Error(s string) {}
type mockHasher struct{}
func (m mockHasher) GenerateHash(s string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(s), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(hash), nil
}

View File

@ -16,7 +16,6 @@ import (
"time"
"github.com/volatiletech/authboss/v3"
"golang.org/x/crypto/bcrypt"
)
// Constants for templates etc.
@ -271,12 +270,12 @@ func (r *Recover) EndPost(w http.ResponseWriter, req *http.Request) error {
return nil
}
pass, err := bcrypt.GenerateFromPassword([]byte(password), r.Authboss.Config.Modules.BCryptCost)
pass, err := r.Authboss.Config.Core.Hasher.GenerateHash(password)
if err != nil {
return err
}
user.PutPassword(string(pass))
user.PutPassword(pass)
user.PutRecoverSelector("") // Don't allow another recovery
user.PutRecoverVerifier("") // Don't allow another recovery
user.PutRecoverExpiry(time.Now().UTC()) // Put current time for those DBs that can't handle 0 time

View File

@ -5,6 +5,7 @@ import (
"crypto/sha512"
"encoding/base64"
"errors"
"github.com/volatiletech/authboss/v3/defaults"
"net/http"
"net/http/httptest"
"strings"
@ -85,6 +86,7 @@ func testSetup() *testHarness {
harness.ab.Config.Core.BodyReader = harness.bodyReader
harness.ab.Config.Core.Logger = mocks.Logger{}
harness.ab.Config.Core.Hasher = defaults.NewBCryptHasher(harness.ab.Config.Modules.BCryptCost)
harness.ab.Config.Core.Mailer = harness.mailer
harness.ab.Config.Core.Redirector = harness.redirector
harness.ab.Config.Core.MailRenderer = harness.renderer

View File

@ -9,7 +9,6 @@ import (
"github.com/friendsofgo/errors"
"github.com/volatiletech/authboss/v3"
"golang.org/x/crypto/bcrypt"
)
// Pages
@ -92,13 +91,13 @@ func (r *Register) Post(w http.ResponseWriter, req *http.Request) error {
storer := authboss.EnsureCanCreate(r.Config.Storage.Server)
user := authboss.MustBeAuthable(storer.New(req.Context()))
pass, err := bcrypt.GenerateFromPassword([]byte(password), r.Config.Modules.BCryptCost)
pass, err := r.Authboss.Config.Core.Hasher.GenerateHash(password)
if err != nil {
return err
}
user.PutPID(pid)
user.PutPassword(string(pass))
user.PutPassword(pass)
if arbUser, ok := user.(authboss.ArbitraryUser); ok && arbitrary != nil {
arbUser.PutArbitrary(arbitrary)

View File

@ -9,6 +9,7 @@ import (
"github.com/friendsofgo/errors"
"github.com/volatiletech/authboss/v3"
"github.com/volatiletech/authboss/v3/defaults"
"github.com/volatiletech/authboss/v3/mocks"
)
@ -88,6 +89,7 @@ func testSetup() *testHarness {
harness.ab.Config.Core.BodyReader = harness.bodyReader
harness.ab.Config.Core.Logger = mocks.Logger{}
harness.ab.Config.Core.Hasher = defaults.NewBCryptHasher(harness.ab.Modules.BCryptCost)
harness.ab.Config.Core.Responder = harness.responder
harness.ab.Config.Core.Redirector = harness.redirector
harness.ab.Config.Storage.SessionState = harness.session