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:
parent
ccfe4d1c31
commit
42f90e2471
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
20
defaults/hasher.go
Normal 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
29
defaults/hasher_test.go
Normal 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
5
hasher.go
Normal file
@ -0,0 +1,5 @@
|
||||
package authboss
|
||||
|
||||
type Hasher interface {
|
||||
GenerateHash(s string) (string, error)
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user