1
0
mirror of https://github.com/volatiletech/authboss.git synced 2024-11-28 08:58:38 +02:00
authboss/internal/mocks/mocks.go
Aaron L 06edd2e615 Make OAuth2 implementation less shoddy.
- Add a new storer specifically for OAuth2 to enable clients to choose
  regular database storing OR Oauth2 but not have to have both.
- Stop storing OAuth2 credentials in a combined form inside username.
- Add new events to capture OAuth events just like auth.
- Have pass-through parameters for OAuth init urls, this allows us to
  pass additional behavior options (redirects and remember me) as well
  as other things that should be present on the page that is redirected
  to.
- Context.LoadUser is now OAuth aware.
- Remember's callbacks now include an OAuth check to see if a horribly
  packed state variable contains a flag to say that we want to be
  remembered.
- Change the OAuth2 Callback to use Attributes instead of that custom
  struct to allow people to append whatever attributes they want into
  the user that will be saved.
2015-03-13 16:29:58 -07:00

324 lines
6.8 KiB
Go

// mocks defines implemented interfaces for testing modules
package mocks
import (
"bytes"
"errors"
"fmt"
"net/http"
"time"
"gopkg.in/authboss.v0"
)
// MockUser represents all possible fields a authboss User may have
type MockUser struct {
Username string
Email string
Password string
RecoverToken string
RecoverTokenExpiry time.Time
ConfirmToken string
Confirmed bool
Locked bool
AttemptNumber int
AttemptTime time.Time
OauthToken string
OauthRefresh string
OauthExpiry time.Time
}
// MockStorer should be valid for any module storer defined in authboss.
type MockStorer struct {
Users map[string]authboss.Attributes
Tokens map[string][]string
CreateErr string
PutErr string
GetErr string
AddTokenErr string
DelTokensErr string
UseTokenErr string
RecoverUserErr string
ConfirmUserErr string
}
func NewMockStorer() *MockStorer {
return &MockStorer{
Users: make(map[string]authboss.Attributes),
Tokens: make(map[string][]string),
}
}
func (m *MockStorer) Create(key string, attr authboss.Attributes) error {
if len(m.CreateErr) > 0 {
return errors.New(m.CreateErr)
}
m.Users[key] = attr
return nil
}
func (m *MockStorer) Put(key string, attr authboss.Attributes) error {
if len(m.PutErr) > 0 {
return errors.New(m.PutErr)
}
if _, ok := m.Users[key]; !ok {
m.Users[key] = attr
return nil
}
for k, v := range attr {
m.Users[key][k] = v
}
return nil
}
func (m *MockStorer) Get(key string, attrMeta authboss.AttributeMeta) (result interface{}, err error) {
if len(m.GetErr) > 0 {
return nil, errors.New(m.GetErr)
}
userAttrs, ok := m.Users[key]
if !ok {
return nil, authboss.ErrUserNotFound
}
u := &MockUser{}
if err := userAttrs.Bind(u, true); err != nil {
panic(err)
}
return u, nil
}
func (m *MockStorer) PutOAuth(uid, provider string, attr authboss.Attributes) error {
if len(m.PutErr) > 0 {
return errors.New(m.PutErr)
}
if _, ok := m.Users[uid+provider]; !ok {
m.Users[uid+provider] = attr
return nil
}
for k, v := range attr {
m.Users[uid+provider][k] = v
}
return nil
}
func (m *MockStorer) GetOAuth(uid, provider string, attrMeta authboss.AttributeMeta) (result interface{}, err error) {
if len(m.GetErr) > 0 {
return nil, errors.New(m.GetErr)
}
userAttrs, ok := m.Users[uid+provider]
if !ok {
return nil, authboss.ErrUserNotFound
}
u := &MockUser{}
if err := userAttrs.Bind(u, true); err != nil {
panic(err)
}
return u, nil
}
func (m *MockStorer) AddToken(key, token string) error {
if len(m.AddTokenErr) > 0 {
return errors.New(m.AddTokenErr)
}
arr := m.Tokens[key]
m.Tokens[key] = append(arr, token)
return nil
}
func (m *MockStorer) DelTokens(key string) error {
if len(m.DelTokensErr) > 0 {
return errors.New(m.DelTokensErr)
}
delete(m.Tokens, key)
return nil
}
func (m *MockStorer) UseToken(givenKey, token string) (key string, err error) {
if len(m.UseTokenErr) > 0 {
return "", errors.New(m.UseTokenErr)
}
if arr, ok := m.Tokens[givenKey]; ok {
for _, tok := range arr {
if tok == token {
return givenKey, nil
}
}
}
return "", authboss.ErrTokenNotFound
}
func (m *MockStorer) RecoverUser(token string) (result interface{}, err error) {
if len(m.RecoverUserErr) > 0 {
return nil, errors.New(m.RecoverUserErr)
}
for _, user := range m.Users {
if user["recover_token"] == token {
u := &MockUser{}
if err = user.Bind(u, false); err != nil {
panic(err)
}
return u, nil
}
}
return nil, authboss.ErrUserNotFound
}
func (m *MockStorer) ConfirmUser(confirmToken string) (result interface{}, err error) {
if len(m.ConfirmUserErr) > 0 {
return nil, errors.New(m.ConfirmUserErr)
}
for _, user := range m.Users {
if user["confirm_token"] == confirmToken {
u := &MockUser{}
if err = user.Bind(u, false); err != nil {
panic(err)
}
return u, nil
}
}
return nil, authboss.ErrUserNotFound
}
func (m *MockStorer) OAuth2NewOrUpdate(key string, attr authboss.Attributes) error {
if len(m.CreateErr) > 0 {
return errors.New(m.CreateErr)
}
m.Users[key] = attr
return nil
}
// MockFailStorer is used for testing module initialize functions that recover more than the base storer
type MockFailStorer struct{}
func (_ MockFailStorer) Create(_ string, _ authboss.Attributes) error {
return errors.New("fail storer: create")
}
func (_ MockFailStorer) Put(_ string, _ authboss.Attributes) error {
return errors.New("fail storer: put")
}
func (_ MockFailStorer) Get(_ string, _ authboss.AttributeMeta) (interface{}, error) {
return nil, errors.New("fail storer: get")
}
// MockClientStorer is used for testing the client stores on context
type MockClientStorer struct {
Values map[string]string
GetShouldFail bool
}
func NewMockClientStorer(data ...string) *MockClientStorer {
if len(data)%2 != 0 {
panic("It should be a key value list of arguments.")
}
values := make(map[string]string)
for i := 0; i < len(data)-1; i += 2 {
values[data[i]] = data[i+1]
}
return &MockClientStorer{Values: values}
}
func (m *MockClientStorer) Get(key string) (string, bool) {
if m.GetShouldFail {
return "", false
}
v, ok := m.Values[key]
return v, ok
}
func (m *MockClientStorer) GetErr(key string) (string, error) {
if m.GetShouldFail {
return "", authboss.ClientDataErr{key}
}
v, ok := m.Values[key]
if !ok {
return v, authboss.ClientDataErr{key}
}
return v, nil
}
func (m *MockClientStorer) Put(key, val string) { m.Values[key] = val }
func (m *MockClientStorer) Del(key string) { delete(m.Values, key) }
// MockRequestContext returns a new context as if it came from POST request.
func MockRequestContext(postKeyValues ...string) *authboss.Context {
keyValues := &bytes.Buffer{}
for i := 0; i < len(postKeyValues); i += 2 {
if i != 0 {
keyValues.WriteByte('&')
}
fmt.Fprintf(keyValues, "%s=%s", postKeyValues[i], postKeyValues[i+1])
}
req, err := http.NewRequest("POST", "http://localhost", keyValues)
if err != nil {
panic(err.Error())
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
ctx, err := authboss.ContextFromRequest(req)
if err != nil {
panic(err)
}
return ctx
}
// MockMailer helps simplify mailer testing by storing the last sent email
type MockMailer struct {
Last authboss.Email
SendErr string
}
func NewMockMailer() *MockMailer {
return &MockMailer{}
}
func (m *MockMailer) Send(email authboss.Email) error {
if len(m.SendErr) > 0 {
return errors.New(m.SendErr)
}
m.Last = email
return nil
}
type MockAfterCallback struct {
HasBeenCalled bool
Fn authboss.After
}
func NewMockAfterCallback() *MockAfterCallback {
m := MockAfterCallback{}
m.Fn = func(_ *authboss.Context) error {
m.HasBeenCalled = true
return nil
}
return &m
}