1
0
mirror of https://github.com/volatiletech/authboss.git synced 2024-11-24 08:42:17 +02:00

Adjust mocks and code to fit new register

- Document various gotchas about Preserve fields.
- Move configuration around to the proper modules.
This commit is contained in:
Aaron L 2018-02-25 15:20:57 -08:00
parent 948aa8a115
commit dcd439e45a
5 changed files with 119 additions and 10 deletions

View File

@ -28,9 +28,6 @@ type Config struct {
}
Modules struct {
// BCryptCost is the cost of the bcrypt password hashing function.
AuthBCryptCost int
// AuthLogoutMethod is the method the logout route should use (default should be DELETE)
AuthLogoutMethod string
@ -45,8 +42,17 @@ type Config struct {
// LockDuration is how long an account is locked for.
LockDuration time.Duration
// RegBCryptCost is the cost of the bcrypt password hashing function.
RegisterBCryptCost int
// RegisterPreserveFields are fields used with registration that are to be rendered when
// post fails.
// post fails in a normal way (for example validation errors), they will be passed
// back in the data of the response under the key DataPreserve which will be a map[string]string.
//
// All fields that are to be preserved must be able to be returned by the ArbitraryValuer.GetValues()
//
// This means in order to have a field named "address" you would need to have that returned by
// the ArbitraryValuer.GetValues() method and then it would be available to be whitelisted by this
// configuration variable.
RegisterPreserveFields []string
// RecoverTokenDuration controls how long a token sent via email for password
@ -126,11 +132,11 @@ func (c *Config) Defaults() {
c.Paths.RecoverOK = "/"
c.Paths.RegisterOK = "/"
c.Modules.AuthBCryptCost = bcrypt.DefaultCost
c.Modules.AuthLogoutMethod = "DELETE"
c.Modules.ExpireAfter = 60 * time.Minute
c.Modules.LockAfter = 3
c.Modules.LockWindow = 5 * time.Minute
c.Modules.LockDuration = 5 * time.Hour
c.Modules.RecoverTokenDuration = time.Duration(24) * time.Hour
c.Modules.RegisterBCryptCost = bcrypt.DefaultCost
}

View File

@ -7,6 +7,8 @@ const (
DataErr = "error"
// DataValidation is for validation errors
DataValidation = "errors"
// DataPreserve preserves fields
DataPreserve = "preserve"
)
// HTMLData is used to render templates with.
@ -16,7 +18,7 @@ type HTMLData map[string]interface{}
// slice, where odd elements are keys, and the following even element is their value.
func NewHTMLData(data ...interface{}) HTMLData {
if len(data)%2 != 0 {
panic("It should be a key value list of arguments.")
panic("it should be a key value list of arguments.")
}
h := make(HTMLData)

View File

@ -28,6 +28,8 @@ type User struct {
OAuthToken string
OAuthRefresh string
OAuthExpiry time.Time
Arbitrary map[string]string
}
func (m User) GetPID() string { return m.Email }
@ -43,6 +45,7 @@ func (m User) GetAttemptTime() time.Time { return m.AttemptTime }
func (m User) GetOAuthToken() string { return m.OAuthToken }
func (m User) GetOAuthRefresh() string { return m.OAuthRefresh }
func (m User) GetOAuthExpiry() time.Time { return m.OAuthExpiry }
func (m User) GetArbitrary() map[string]string { return m.Arbitrary }
func (m *User) PutPID(email string) { m.Email = email }
func (m *User) PutUsername(username string) { m.Username = username }
@ -60,6 +63,7 @@ func (m *User) PutAttemptTime(attemptTime time.Time) { m.AttemptTime = attemptTi
func (m *User) PutOAuthToken(oAuthToken string) { m.OAuthToken = oAuthToken }
func (m *User) PutOAuthRefresh(oAuthRefresh string) { m.OAuthRefresh = oAuthRefresh }
func (m *User) PutOAuthExpiry(oAuthExpiry time.Time) { m.OAuthExpiry = oAuthExpiry }
func (m *User) PutArbitrary(arb map[string]string) { m.Arbitrary = arb }
// ServerStorer should be valid for any module storer defined in authboss.
type ServerStorer struct {
@ -75,6 +79,21 @@ func NewServerStorer() *ServerStorer {
}
}
// New constructs a blank user to later be created
func (s *ServerStorer) New(context.Context) authboss.User {
return &User{}
}
// Create a user
func (s *ServerStorer) Create(ctx context.Context, user authboss.User) error {
u := user.(*User)
if _, ok := s.Users[u.Email]; ok {
return authboss.ErrUserFound
}
s.Users[u.Email] = u
return nil
}
// Load a user
func (s *ServerStorer) Load(ctx context.Context, key string) (authboss.User, error) {
user, ok := s.Users[key]
@ -88,6 +107,9 @@ func (s *ServerStorer) Load(ctx context.Context, key string) (authboss.User, err
// Save a user
func (s *ServerStorer) Save(ctx context.Context, user authboss.User) error {
u := user.(*User)
if _, ok := s.Users[u.Email]; !ok {
return authboss.ErrUserNotFound
}
s.Users[u.Email] = u
return nil
}
@ -265,7 +287,7 @@ func (c *ClientStateRW) WriteState(w http.ResponseWriter, cstate authboss.Client
return nil
}
// Request returns a new request with optional key-value body (form-post)
// Request returns a new request with optional key-value body (form-post)
func Request(method string, postKeyValues ...string) *http.Request {
var body io.Reader
location := "http://localhost"
@ -399,13 +421,16 @@ type Redirector struct {
// Redirect a request
func (r *Redirector) Redirect(w http.ResponseWriter, req *http.Request, ro authboss.RedirectOptions) error {
r.Options = ro
if len(ro.RedirectPath) == 0 {
panic("no redirect path on redirect call")
}
http.Redirect(w, req, ro.RedirectPath, ro.Code)
return nil
}
// BodyReader reads the body of a request and returns some values
type BodyReader struct {
Return Values
Return authboss.Validator
}
// Read the return values
@ -417,6 +442,8 @@ func (b BodyReader) Read(page string, r *http.Request) (authboss.Validator, erro
type Values struct {
PID string
Password string
Errors []error
}
// GetPID from values
@ -431,7 +458,33 @@ func (v Values) GetPassword() string {
// Validate the values
func (v Values) Validate() []error {
return nil
return v.Errors
}
// ArbValues is arbitrary value storage
type ArbValues struct {
Values map[string]string
Errors []error
}
// GetPID gets the pid
func (a ArbValues) GetPID() string {
return a.Values["email"]
}
// GetPassword gets the password
func (a ArbValues) GetPassword() string {
return a.Values["password"]
}
// GetValues returns all values
func (a ArbValues) GetValues() map[string]string {
return a.Values
}
// Validate nothing
func (a ArbValues) Validate() []error {
return a.Errors
}
// Logger logs to the void

View File

@ -1,5 +1,12 @@
package authboss
// A concious decision was made to put all storer
// and user types into this file despite them truly
// belonging to outside modules. The reason for this
// is because documentation-wise, it was previously
// difficult to find what you had to implement or even
// what you could implement.
import (
"context"
"time"
@ -39,10 +46,33 @@ type ServerStorer interface {
// Load will look up the user based on the passed the PrimaryID
Load(ctx context.Context, key string) (User, error)
// Save persists the user in the database
// Save persists the user in the database, this should never
// create a user and instead return ErrUserNotFound if the user
// does not exist.
Save(ctx context.Context, user User) error
}
// CreatingServerStorer is used for creating new users
// like when Registration is being done.
type CreatingServerStorer interface {
// New creates a blank user, it is not yet persisted in the database
// but is just for storing data
New(ctx context.Context) User
// Create the user in storage, it should not overwrite a user
// and should return ErrUserFound if it currently exists.
Create(ctx context.Context, user User) error
}
// EnsureCanCreate makes sure the server storer supports create operations
func EnsureCanCreate(storer ServerStorer) CreatingServerStorer {
s, ok := storer.(CreatingServerStorer)
if !ok {
panic("could not upgrade serverstorer to creatingserverstorer, check your struct")
}
return s
}
// User has functions for each piece of data it requires.
// Data should not be persisted on each function call.
// User has a PID (primary ID) that is used on the site as

View File

@ -40,3 +40,21 @@ func MustHaveUserValues(v Validator) UserValuer {
panic(fmt.Sprintf("bodyreader returned a type that could not be upgraded to UserValuer: %T", v))
}
// ArbitraryValuer provides the "rest" of the fields
// that aren't strictly needed for anything in particular,
// address, secondary e-mail, etc.
//
// There are two important notes about this interface:
//
// 1. That this is composed with Validator, as these fields
// should both be validated and culled of invalid pieces
// as they will be passed into ArbitraryUser.PutArbitrary()
//
// 2. These values will also be culled according to the RegisterPreserveFields
// whitelist and sent back in the data under the key DataPreserve.
type ArbitraryValuer interface {
Validator
GetValues() map[string]string
}