1
0
mirror of https://github.com/volatiletech/authboss.git synced 2025-02-03 13:21:22 +02:00

Add mountedpath so forms work on mounted paths.

- Refactor naming for config "redirect" variables.
- Removed flash messages from config, Fix #19
This commit is contained in:
Aaron 2015-02-25 23:05:14 -08:00
parent 1ad9351b8c
commit bf0a8b098c
13 changed files with 100 additions and 93 deletions

View File

@ -66,7 +66,7 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
case methodGET:
if _, ok := ctx.SessionStorer.Get(authboss.SessionKey); ok {
if halfAuthed, ok := ctx.SessionStorer.Get(authboss.SessionHalfAuthKey); !ok || halfAuthed == "false" {
http.Redirect(w, r, authboss.Cfg.AuthLoginSuccessRoute, http.StatusFound)
http.Redirect(w, r, authboss.Cfg.AuthLoginOKPath, http.StatusFound)
return nil
}
}
@ -79,21 +79,6 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
)
return a.templates.Render(ctx, w, r, tplLogin, data)
case methodPOST:
interrupted, err := authboss.Cfg.Callbacks.FireBefore(authboss.EventAuth, ctx)
if err != nil {
return err
} else if interrupted != authboss.InterruptNone {
var reason string
switch interrupted {
case authboss.InterruptAccountLocked:
reason = "Your account has been locked."
case authboss.InterruptAccountNotConfirmed:
reason = "Your account has not been confirmed."
}
render.Redirect(ctx, w, r, "/login", "", reason)
return nil
}
key, _ := ctx.FirstPostFormValue(authboss.Cfg.PrimaryID)
password, _ := ctx.FirstPostFormValue("password")
@ -114,8 +99,26 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
return a.templates.Render(ctx, w, r, tplLogin, errData)
}
interrupted, err := authboss.Cfg.Callbacks.FireBefore(authboss.EventAuth, ctx)
if err != nil {
return err
} else if interrupted != authboss.InterruptNone {
var reason string
switch interrupted {
case authboss.InterruptAccountLocked:
reason = "Your account has been locked."
case authboss.InterruptAccountNotConfirmed:
reason = "Your account has not been confirmed."
}
render.Redirect(ctx, w, r, authboss.Cfg.AuthLoginFailPath, "", reason)
return nil
}
ctx.SessionStorer.Put(authboss.SessionKey, key)
ctx.SessionStorer.Del(authboss.SessionHalfAuthKey)
authboss.Cfg.Callbacks.FireAfter(authboss.EventAuth, ctx)
http.Redirect(w, r, authboss.Cfg.AuthLoginSuccessRoute, http.StatusFound)
http.Redirect(w, r, authboss.Cfg.AuthLoginOKPath, http.StatusFound)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
@ -137,7 +140,6 @@ func validateCredentials(ctx *authboss.Context, key, password string) error {
return err
}
ctx.SessionStorer.Put(authboss.SessionKey, key)
return nil
}
@ -145,7 +147,7 @@ func (a *Auth) logoutHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
switch r.Method {
case methodGET:
ctx.SessionStorer.Del(authboss.SessionKey)
http.Redirect(w, r, authboss.Cfg.AuthLogoutRoute, http.StatusFound)
http.Redirect(w, r, authboss.Cfg.AuthLogoutOKPath, http.StatusFound)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}

View File

@ -72,7 +72,7 @@ func TestAuth_loginHandlerFunc_GET_RedirectsWhenHalfAuthed(t *testing.T) {
sessionStore.Put(authboss.SessionKey, "a")
sessionStore.Put(authboss.SessionHalfAuthKey, "false")
authboss.Cfg.AuthLoginSuccessRoute = "/dashboard"
authboss.Cfg.AuthLoginOKPath = "/dashboard"
if err := a.loginHandlerFunc(ctx, w, r); err != nil {
t.Error("Unexpeced error:", err)
@ -83,7 +83,7 @@ func TestAuth_loginHandlerFunc_GET_RedirectsWhenHalfAuthed(t *testing.T) {
}
loc := w.Header().Get("Location")
if loc != authboss.Cfg.AuthLoginSuccessRoute {
if loc != authboss.Cfg.AuthLoginOKPath {
t.Error("Unexpected redirect:", loc)
}
}
@ -113,14 +113,15 @@ func TestAuth_loginHandlerFunc_GET(t *testing.T) {
}
func TestAuth_loginHandlerFunc_POST_ReturnsErrorOnCallbackFailure(t *testing.T) {
a, _ := testSetup()
a, storer := testSetup()
storer.Users["john"] = authboss.Attributes{"password": "$2a$10$B7aydtqVF9V8RSNx3lCKB.l09jqLV/aMiVqQHajtL7sWGhCS9jlOu"}
authboss.Cfg.Callbacks = authboss.NewCallbacks()
authboss.Cfg.Callbacks.Before(authboss.EventAuth, func(_ *authboss.Context) (authboss.Interrupt, error) {
return authboss.InterruptNone, errors.New("explode")
})
ctx, w, r, _ := testRequest("POST")
ctx, w, r, _ := testRequest("POST", "username", "john", "password", "1234")
if err := a.loginHandlerFunc(ctx, w, r); err.Error() != "explode" {
t.Error("Unexpected error:", err)
@ -128,14 +129,15 @@ func TestAuth_loginHandlerFunc_POST_ReturnsErrorOnCallbackFailure(t *testing.T)
}
func TestAuth_loginHandlerFunc_POST_RedirectsWhenInterrupted(t *testing.T) {
a, _ := testSetup()
a, storer := testSetup()
storer.Users["john"] = authboss.Attributes{"password": "$2a$10$B7aydtqVF9V8RSNx3lCKB.l09jqLV/aMiVqQHajtL7sWGhCS9jlOu"}
authboss.Cfg.Callbacks = authboss.NewCallbacks()
authboss.Cfg.Callbacks.Before(authboss.EventAuth, func(_ *authboss.Context) (authboss.Interrupt, error) {
return authboss.InterruptAccountLocked, nil
})
ctx, w, r, sessionStore := testRequest("POST")
ctx, w, r, sessionStore := testRequest("POST", "username", "john", "password", "1234")
if err := a.loginHandlerFunc(ctx, w, r); err != nil {
t.Error("Unexpected error:", err)
@ -146,7 +148,7 @@ func TestAuth_loginHandlerFunc_POST_RedirectsWhenInterrupted(t *testing.T) {
}
loc := w.Header().Get("Location")
if loc != "/login" {
if loc != authboss.Cfg.AuthLoginFailPath {
t.Error("Unexpeced location:", loc)
}
@ -169,7 +171,7 @@ func TestAuth_loginHandlerFunc_POST_RedirectsWhenInterrupted(t *testing.T) {
}
loc = w.Header().Get("Location")
if loc != "/login" {
if loc != authboss.Cfg.AuthLoginFailPath {
t.Error("Unexpeced location:", loc)
}
@ -222,7 +224,10 @@ func TestAuth_loginHandlerFunc_POST(t *testing.T) {
authboss.Cfg.Callbacks = authboss.NewCallbacks()
authboss.Cfg.Callbacks.After(authboss.EventAuth, cb.Fn)
authboss.Cfg.AuthLoginSuccessRoute = "/dashboard"
authboss.Cfg.AuthLoginOKPath = "/dashboard"
sessions := mocks.NewMockClientStorer()
ctx.SessionStorer = sessions
if err := a.loginHandlerFunc(ctx, w, r); err != nil {
t.Error("Unexpected error:", err)
@ -237,9 +242,16 @@ func TestAuth_loginHandlerFunc_POST(t *testing.T) {
}
loc := w.Header().Get("Location")
if loc != authboss.Cfg.AuthLoginSuccessRoute {
if loc != authboss.Cfg.AuthLoginOKPath {
t.Error("Unexpeced location:", loc)
}
val, ok := sessions.Values[authboss.SessionKey]
if !ok {
t.Error("Expected session to be set")
} else if val != "john" {
t.Error("Expected session value to be authed username")
}
}
func TestAuth_loginHandlerFunc_OtherMethods(t *testing.T) {
@ -283,24 +295,15 @@ func TestAuth_validateCredentials(t *testing.T) {
t.Error("Expected error about passwords mismatch")
}
sessions := mocks.NewMockClientStorer()
ctx.SessionStorer = sessions
if err := validateCredentials(&ctx, "john", "a"); err != nil {
t.Error("Unexpected error:", err)
}
val, ok := sessions.Values[authboss.SessionKey]
if !ok {
t.Error("Expected session to be set")
} else if val != "john" {
t.Error("Expected session value to be authed username")
}
}
func TestAuth_logoutHandlerFunc_GET(t *testing.T) {
a, _ := testSetup()
authboss.Cfg.AuthLogoutRoute = "/dashboard"
authboss.Cfg.AuthLogoutOKPath = "/dashboard"
ctx, w, r, sessionStorer := testRequest("GET")

View File

@ -40,14 +40,12 @@ type Config struct {
// NotFoundHandler handles would be 404 errors.
NotFoundHandler http.Handler
AuthLogoutRoute string
AuthLoginSuccessRoute string
AuthLoginOKPath string
AuthLoginFailPath string
AuthLogoutOKPath string
RecoverRedirect string
RecoverInitiateSuccessFlash string
RecoverTokenDuration time.Duration
RecoverTokenExpiredFlash string
RecoverFailedErrorFlash string
RecoverOKPath string
RecoverTokenDuration time.Duration
Policies []Validator
ConfirmFields []string
@ -86,8 +84,9 @@ func NewConfig() *Config {
Layout: template.Must(template.New("").Parse(`<html><body>{{template "authboss" .}}</body></html>`)),
LayoutEmail: template.Must(template.New("").Parse(`<html><body>{{template "authboss" .}}</body></html>`)),
AuthLogoutRoute: "/login",
AuthLoginSuccessRoute: "/",
AuthLoginOKPath: "/",
AuthLoginFailPath: "/",
AuthLogoutOKPath: "/",
Policies: []Validator{
Rules{
@ -112,11 +111,8 @@ func NewConfig() *Config {
StorePassword, ConfirmPrefix + StorePassword,
},
RecoverRedirect: "/login",
RecoverInitiateSuccessFlash: "An email has been sent with further insructions on how to reset your password",
RecoverTokenDuration: time.Duration(24) * time.Hour,
RecoverTokenExpiredFlash: "Account recovery request has expired. Please try agian.",
RecoverFailedErrorFlash: "Account recovery has failed. Please contact tech support.",
RecoverOKPath: "/",
RecoverTokenDuration: time.Duration(24) * time.Hour,
LogWriter: ioutil.Discard,
Callbacks: NewCallbacks(),

View File

@ -4,7 +4,6 @@
package expire
import (
"errors"
"net/http"
"time"
@ -12,12 +11,8 @@ import (
)
const (
// StoreLastAction is the session key to retrieve the last action of a user.
StoreLastAction = "last_action"
)
var (
ErrExpired = errors.New("The user session has expired.")
// SessionLastAction is the session key to retrieve the last action of a user.
SessionLastAction = "last_action"
)
// E is the singleton instance of the expire module which will have been
@ -46,7 +41,7 @@ func (e *Expire) BeforeGet(ctx *authboss.Context) (authboss.Interrupt, error) {
return authboss.InterruptNone, nil
}
dateStr, ok := ctx.SessionStorer.Get(StoreLastAction)
dateStr, ok := ctx.SessionStorer.Get(SessionLastAction)
if ok {
if date, err := time.Parse(time.RFC3339, dateStr); err != nil {
Touch(ctx.SessionStorer)
@ -61,7 +56,7 @@ func (e *Expire) BeforeGet(ctx *authboss.Context) (authboss.Interrupt, error) {
// Touch updates the last action for the user, so he doesn't become expired.
func Touch(session authboss.ClientStorer) {
session.Put(StoreLastAction, time.Now().UTC().Format(time.RFC3339))
session.Put(SessionLastAction, time.Now().UTC().Format(time.RFC3339))
}
type middleware struct {

View File

@ -13,11 +13,11 @@ func TestExpire_Touch(t *testing.T) {
authboss.NewConfig()
session := mocks.NewMockClientStorer()
if _, ok := session.Get(StoreLastAction); ok {
if _, ok := session.Get(SessionLastAction); ok {
t.Error("It should not have been set")
}
Touch(session)
if dateStr, ok := session.Get(StoreLastAction); !ok || len(dateStr) == 0 {
if dateStr, ok := session.Get(SessionLastAction); !ok || len(dateStr) == 0 {
t.Error("It should have been set")
} else if date, err := time.Parse(time.RFC3339, dateStr); err != nil {
t.Error("Date is malformed:", dateStr)
@ -40,11 +40,11 @@ func TestExpire_BeforeGet(t *testing.T) {
}
session.Values[authboss.SessionKey] = "moo"
session.Values[StoreLastAction] = "cow"
session.Values[SessionLastAction] = "cow"
if interrupted, err := expire.BeforeGet(ctx); err != nil || interrupted != authboss.InterruptNone {
t.Error("There's a malformed date, this should not error, just fix it:", err, interrupted)
}
if dateStr, ok := session.Get(StoreLastAction); !ok || len(dateStr) == 0 {
if dateStr, ok := session.Get(SessionLastAction); !ok || len(dateStr) == 0 {
t.Error("It should have been set")
} else if date, err := time.Parse(time.RFC3339, dateStr); err != nil {
t.Error("Date is malformed:", dateStr)
@ -52,7 +52,7 @@ func TestExpire_BeforeGet(t *testing.T) {
t.Error("The time is set in the future.")
}
session.Values[StoreLastAction] = time.Now().UTC().Add(-2 * time.Hour).Format(time.RFC3339)
session.Values[SessionLastAction] = time.Now().UTC().Add(-2 * time.Hour).Format(time.RFC3339)
if interrupted, err := expire.BeforeGet(ctx); err != nil {
t.Error(err)
} else if interrupted != authboss.InterruptSessionExpired {
@ -86,7 +86,7 @@ func TestExpire_Middleware(t *testing.T) {
t.Error("Expected middleware's chain to be called.")
}
if dateStr, ok := session.Get(StoreLastAction); !ok || len(dateStr) == 0 {
if dateStr, ok := session.Get(SessionLastAction); !ok || len(dateStr) == 0 {
t.Error("It should have been set")
} else if date, err := time.Parse(time.RFC3339, dateStr); err != nil {
t.Error("Date is malformed:", dateStr)

View File

@ -76,7 +76,7 @@ func confirm_email_html_tpl() (*asset, error) {
return nil, err
}
info := bindata_file_info{name: "confirm_email.html.tpl", size: 26, mode: os.FileMode(438), modTime: time.Unix(1424471280, 0)}
info := bindata_file_info{name: "confirm_email.html.tpl", size: 26, mode: os.FileMode(438), modTime: time.Unix(1424498554, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -96,12 +96,12 @@ func confirm_email_txt_tpl() (*asset, error) {
return nil, err
}
info := bindata_file_info{name: "confirm_email.txt.tpl", size: 9, mode: os.FileMode(438), modTime: time.Unix(1424471280, 0)}
info := bindata_file_info{name: "confirm_email.txt.tpl", size: 9, mode: os.FileMode(438), modTime: time.Unix(1424498554, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _login_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x7c\x92\xcb\x6a\xeb\x30\x10\x86\xf7\x81\xbc\x83\xd0\xfe\xc4\x2f\x60\x1b\x0e\x74\x53\xe8\x25\xb4\xa1\xdb\x22\xcb\xe3\x5a\xc4\xd2\x98\xd1\x38\x17\x8c\xdf\xbd\x52\xed\x34\x51\x29\xcd\x2a\xfe\x67\xf4\xe9\xd3\x48\xe3\xb8\x69\x3a\xe5\xdb\x77\x3f\x68\x0d\xde\x4f\xd3\x7a\x95\x37\x48\x56\x28\xcd\x06\x5d\x21\xb3\x0e\x3f\x8c\x93\xc2\x02\xb7\x58\x17\x72\xfb\xfc\xba\x93\xe5\x7a\x25\xc2\x6f\x1c\x4d\x23\x36\x40\x84\x34\x4d\x01\xb5\xfc\xcb\x2b\x12\x59\x39\x8e\xe0\xea\xc8\x8b\x9d\xb9\x71\xfd\xc0\x82\xcf\x3d\x14\x92\xe1\xc4\x52\xe8\xb0\xaf\x2f\x64\xdc\xec\x9f\x46\xc7\x84\x9d\x14\x4e\xd9\xd0\x10\x50\x3d\x19\xab\xe8\x7c\x7f\x37\x4d\x52\xf4\x9d\xd2\xd0\x62\x57\x03\xc5\x22\x1b\xee\x40\xa4\x2d\x07\xd5\x0d\x3f\x56\xbe\xc5\x28\xd4\xca\xd9\x27\x11\x59\x4c\xfa\xa0\x70\x44\xaa\xff\xb4\xb9\x36\x25\x1e\xdb\x4b\xfc\x1b\x7f\xc6\xb7\xa6\xae\xc1\xdd\x9c\xea\xe4\xa9\x79\x0a\x1f\xa9\x71\x4c\x77\xb8\x07\x17\xe3\x2c\x99\xad\x6f\xf1\xf8\x02\x16\x6c\x05\x71\xb0\xb7\x70\xdd\x82\xde\x57\x78\xba\xe0\xc9\x7e\x33\x99\x06\x90\xa5\xb8\x2c\x14\x8f\x90\x5e\x46\x35\x30\xa3\x5b\x38\x7e\xa8\xac\x61\x59\x3e\xc4\x7b\xce\xb3\xb9\x96\x9c\xe9\x56\x45\xe3\xe1\xcb\x44\x89\x96\xa0\x09\xcf\x83\xe6\x48\x96\x4b\x4d\xfc\xd7\x1a\x07\xc7\x79\xa6\xae\x4f\x20\xcf\xe2\x60\xcb\xcf\x00\x00\x00\xff\xff\x7f\x7f\xf0\x07\x6e\x02\x00\x00")
var _login_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x7c\x92\xcb\x6a\xf3\x30\x10\x85\xf7\x81\xbc\x83\xd0\xfe\x8f\x5f\xc0\x36\xfc\xd0\x4d\xa1\x97\xd0\x86\x6e\x8b\x2c\x8f\x2b\x11\x4b\x63\x46\xe3\x5c\x10\x7e\xf7\x5a\xb5\xd3\xc4\xa5\xd4\x2b\xeb\x9c\xd1\x99\x4f\x23\xc5\xb8\x69\x5a\x15\xcc\x7b\xe8\xb5\x86\x10\x86\x61\xbd\xca\x1b\x24\x27\x94\x66\x8b\xbe\x90\x31\x3a\xec\x3d\x77\x8a\x0d\xd4\x42\xb6\xf8\x61\xbd\x1c\x06\x29\x1c\xb0\xc1\xba\x90\xdb\xe7\xd7\x9d\x2c\xd7\x2b\x31\x7e\x31\xda\x46\x6c\x80\x08\x69\x18\xc6\xec\xf9\x2f\xaf\x48\x64\x65\x8c\xe0\xeb\xd4\x20\x55\xe6\xd6\x77\x3d\x0b\x3e\x77\x50\x48\x86\x13\x4b\xa1\x47\x90\x50\xc8\xd4\xfd\x9f\x46\xcf\x84\xad\x14\x5e\x39\x48\x10\x9b\x8e\xac\x53\x74\xbe\xbf\x4b\xbd\xbb\x56\x69\x30\xd8\xd6\x40\xc9\x64\xcb\x2d\x88\x65\xc9\x41\xb5\xfd\x8f\x9d\x6f\x49\x1a\xbd\x72\xe2\x59\x80\xcc\x24\xdd\x88\x70\x44\xaa\xff\xa4\xb9\x16\x2d\x38\xb6\x17\xf9\xb7\xfc\x29\xde\xd8\xba\x06\x7f\x73\xaa\x53\xa0\xe6\x69\x5c\x2c\x89\x93\xba\xc3\x3d\xf8\x24\x67\x8b\xd9\x06\x83\xc7\x17\x70\xe0\x2a\x48\x83\xbd\x0d\xd7\x06\xf4\xbe\xc2\xd3\x25\x9e\xdc\x77\x26\x53\x0f\xb2\x14\x97\x8d\xe2\x11\x96\x97\x51\xf5\xcc\xe8\xe7\x9c\xd0\x57\xce\xb2\x2c\x1f\xd2\x55\xe7\xd9\xe4\x2d\xce\x74\x8b\xa2\xf1\xf0\x45\xa2\x84\x21\x68\x0a\x99\xd1\x24\xc9\x72\xf6\xc4\x7f\xad\xd3\x0b\xca\x33\x75\x7d\x02\x79\x96\x06\x5b\x7e\x06\x00\x00\xff\xff\x65\x0d\x58\xda\x7f\x02\x00\x00")
func login_tpl_bytes() ([]byte, error) {
return bindata_read(
@ -116,12 +116,12 @@ func login_tpl() (*asset, error) {
return nil, err
}
info := bindata_file_info{name: "login.tpl", size: 622, mode: os.FileMode(438), modTime: time.Unix(1424815807, 0)}
info := bindata_file_info{name: "login.tpl", size: 639, mode: os.FileMode(438), modTime: time.Unix(1424932706, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _recover_complete_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x52\xc1\x6e\xea\x30\x10\xbc\xf3\x15\x2b\xeb\x9d\xf1\xfd\xc9\xc9\x85\x7b\x8b\x5a\xee\x95\x89\x37\xc4\xaa\xb3\x8e\xd6\x0e\x50\x45\xf9\xf7\xda\x04\x08\x6d\xa9\x7a\xa8\x9a\x4b\x3c\xeb\x9d\x19\x8f\x34\xaa\xf6\xdc\x82\xae\xa2\xf5\x54\x08\xc9\x58\xf9\x3d\xb2\xac\x7c\xdb\x39\x8c\x28\xa0\xc5\xd8\x78\x53\x88\xf5\xe3\xf3\x46\x94\x0b\x48\x9f\xb2\xd4\xf5\x11\xe2\x5b\x87\x85\x68\xac\x31\x48\x02\x48\xb7\x09\x45\xff\x9a\xc1\x5e\xbb\x3e\xa1\x61\x58\x9e\x06\xe3\x28\x40\xde\xe1\x76\x3a\x84\x83\x67\x73\x61\xcf\xb8\x73\xba\xc2\xc6\x3b\x83\x9c\xac\xaf\xe3\x59\xf7\xb2\x3a\x49\xab\x2d\x5f\x0c\x86\xe1\x60\x63\x03\x4b\x64\x0e\xe3\x78\x46\xff\x12\x72\x36\x44\xf8\x5f\x80\x25\x83\x47\x58\xc2\xec\x96\xd7\x58\xd3\x0e\xaf\x7b\xe3\xa8\x42\xa7\xa9\x4c\x46\xe9\x28\x4f\xe7\xc9\x63\x18\x90\x4c\x26\xdc\xfe\x7e\x4e\x56\x79\xaa\x2d\xb7\x2f\xdf\x24\x5c\x4d\xd7\x70\x2f\xe9\x99\xba\xfe\x7d\xe0\x2f\x8f\xf8\x83\xe0\x1f\xeb\x90\x64\x8e\x81\xeb\x87\x04\xf2\xbb\xe7\x50\x79\xba\xf9\x5c\x8d\x6d\x1f\xa3\xa7\xb3\x50\xe8\xb7\xad\x8d\xa2\x7c\x9a\x1a\xa9\xe4\x74\x7b\x9b\x5c\x69\x68\x18\xeb\x54\x5b\xe7\x77\x96\x44\xb9\xd2\x54\xa1\x53\x52\x97\x0b\x25\x73\xb1\xcb\xf7\x00\x00\x00\xff\xff\x67\x02\x74\x02\xdf\x02\x00\x00")
var _recover_complete_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x52\xc1\x6e\xeb\x20\x10\xbc\xe7\x2b\x10\x7a\xe7\x70\x7f\xc2\xbe\xe4\xde\x46\x6d\xee\x15\x31\xeb\x18\x15\x16\x04\xeb\x24\x95\xe5\x7f\x2f\xc4\x49\x9c\xb6\xa9\x7a\xa8\xea\x8b\x99\x65\x67\x86\x91\x46\xb6\x3e\x3a\xa6\x1a\x32\x1e\x2b\x3e\x0c\xce\xf7\x48\x41\x51\x07\x9a\xf1\x08\x8d\xdf\x43\x14\x8d\x77\xc1\x02\x01\x1f\x47\xce\x1c\x50\xe7\x75\xc5\xd7\x8f\xcf\x1b\x5e\x2f\x58\xfe\xa4\xc1\xd0\x13\xa3\xb7\x00\x15\xef\x8c\xd6\x80\x9c\xa1\x72\x19\x91\x7f\x2d\x60\xaf\x6c\x0f\x45\x7f\x79\x1a\x14\x1d\x71\x87\x1b\x54\x4a\x07\x1f\xf5\x85\x3d\xe3\x60\x55\x03\x9d\xb7\x1a\x62\xb6\xbe\x8e\x67\xdd\xcb\xea\x24\x2d\xb7\xf1\x62\x30\x0c\x07\x43\x1d\x5b\x42\x8c\x69\x1c\xcf\xe8\x5f\x46\xd6\x24\x62\xff\x2b\x66\x50\xc3\x91\x2d\xd9\xec\x56\xd6\xa2\xc2\x1d\x5c\xf7\xc6\x51\xa6\xa0\xb0\xce\x46\xf9\x28\x4e\xe7\xc9\x63\x18\x00\x75\x21\xdc\xfe\x7e\x4e\xd6\x78\x6c\x4d\x74\x2f\xdf\x24\x5c\x4d\xd7\xec\x5e\xd2\x33\x75\xfd\xfb\xc0\x5f\x1e\xf1\x07\xc1\x3f\xd6\x21\xcb\x1c\x53\x6c\x1f\x32\x28\xef\x9e\x43\x95\xe9\xe6\x73\x35\xb6\x3d\x91\xc7\xb3\x50\xea\xb7\xce\x10\xaf\x9f\xa6\x52\x4a\x31\xdd\xde\x26\x97\x8a\x75\x11\xda\x8a\x0b\xeb\x77\x06\x79\xbd\x52\xd8\x80\x95\x42\xd5\x0b\x29\x4a\xd3\xeb\xf7\x00\x00\x00\xff\xff\xba\x89\x7e\x9e\xf0\x02\x00\x00")
func recover_complete_tpl_bytes() ([]byte, error) {
return bindata_read(
@ -136,7 +136,7 @@ func recover_complete_tpl() (*asset, error) {
return nil, err
}
info := bindata_file_info{name: "recover-complete.tpl", size: 735, mode: os.FileMode(438), modTime: time.Unix(1424735204, 0)}
info := bindata_file_info{name: "recover-complete.tpl", size: 752, mode: os.FileMode(438), modTime: time.Unix(1424932692, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -156,7 +156,7 @@ func recover_html_email() (*asset, error) {
return nil, err
}
info := bindata_file_info{name: "recover-html.email", size: 22, mode: os.FileMode(438), modTime: time.Unix(1424728125, 0)}
info := bindata_file_info{name: "recover-html.email", size: 22, mode: os.FileMode(438), modTime: time.Unix(1424804266, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -176,12 +176,12 @@ func recover_text_email() (*asset, error) {
return nil, err
}
info := bindata_file_info{name: "recover-text.email", size: 5, mode: os.FileMode(438), modTime: time.Unix(1424728129, 0)}
info := bindata_file_info{name: "recover-text.email", size: 5, mode: os.FileMode(438), modTime: time.Unix(1424804266, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _recover_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x53\x4d\x6f\xe2\x30\x10\xbd\xf3\x2b\x46\x16\x7b\x25\xf7\x55\xe2\x0b\xbb\x87\x5e\x5a\xd4\xa2\x5e\x2b\x93\x4c\x88\x55\xc7\x8e\x26\x13\x0a\x4a\xfd\xdf\x6b\x63\x8a\x48\x2b\x81\x7a\x68\x2e\x99\x8f\x37\x2f\xf3\x9e\x26\x79\xed\xa8\x05\x55\xb2\x76\xb6\x10\x19\x61\xe9\x76\x48\x02\x5a\xe4\xc6\x55\x85\x58\x3d\x3c\xad\x85\x9c\x41\x78\xc6\xf1\x4d\x73\x03\x8b\xda\xa8\xbe\xf9\x4f\xe4\xc8\xfb\x71\x5c\x78\x9f\x6f\x08\x32\x39\x8e\x68\x2b\xef\x8f\xd0\x5c\xdb\x6e\x60\xe0\x43\x87\x85\x60\xdc\xb3\x00\xab\xda\x10\x07\x7c\x47\xba\x55\x74\xb8\xfb\xe7\xbd\x80\xce\xa8\x12\x1b\x67\x2a\xa4\xd8\x64\xcd\x06\x61\x0a\xd9\x29\x33\x7c\x99\x7c\x8e\xa5\xd8\xcb\x64\xfa\xf6\x69\xbf\x79\xa7\x2b\xf8\x5b\x4c\x08\x3e\xb7\x46\xa2\xfe\x9c\xcd\x43\x66\x74\xcf\x11\xac\x6d\x85\x7b\x58\x40\x1c\x8e\x00\x52\x76\x8b\x67\x44\x50\xd7\x77\xca\xca\x24\x34\x3b\xc6\x13\xbd\xd3\xd7\x75\xf5\xa5\xb3\xb5\xa6\xf6\xe5\xaa\x0b\xcb\x04\x82\x5b\x6e\x9c\xc8\x56\x37\x4d\x29\xbf\xb9\x02\xef\x10\x62\xcb\x35\x9c\x57\xfa\xd3\x8b\x9f\x78\x55\xfe\x8e\x59\x8d\xae\x2a\xb4\x17\xc7\xb2\xef\xa9\xbe\x0f\xc9\x54\x7a\xac\xae\xdd\x2b\xda\x24\x37\xf1\x6c\x06\x66\x67\x4f\x44\xfd\xb0\x69\x35\x0b\xf9\x98\xee\x39\xcf\x52\xf7\xd2\x99\x5c\x41\x43\x58\x87\xa3\x37\x6e\xab\xad\x90\x4b\x65\x4b\x34\x79\xa6\xe4\x2c\xcf\xe2\x6f\x21\x3f\x02\x00\x00\xff\xff\x93\x4d\xba\xa6\x1d\x03\x00\x00")
var _recover_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb4\x53\xb1\x6e\xe3\x30\x0c\xdd\xf3\x15\x84\x90\x5b\xed\xfd\x60\x6b\xc9\xdd\x70\xcb\x5d\x70\x0d\xba\x16\x8a\x45\xc7\x42\x65\xc9\xa0\xe9\x34\x81\xaa\x7f\xaf\x15\xa7\x41\xdc\x02\x09\x3a\xd4\x8b\x45\xf1\xf1\x91\xef\x81\x2a\x6a\x4f\x2d\xa8\x8a\x8d\x77\xa5\x08\xa1\xf5\x83\xe3\x4e\x71\x83\x1a\x04\x61\xe5\xf7\x48\x22\x46\x01\x2d\x72\xe3\x75\x29\xd6\xff\x1e\x36\x42\x2e\x60\xfc\x42\x78\x31\xdc\x40\x56\x5b\xd5\x37\xbf\x89\x3c\xc5\x18\x42\x16\x63\xb1\x25\xc8\x65\x08\xe8\x74\x8c\x27\x68\x61\x5c\x37\x30\xf0\xb1\xc3\x52\x30\x1e\x58\x80\x53\x2d\xa6\x8e\x59\x47\xa6\x55\x74\xfc\xf3\x2b\xb5\xe9\xac\xaa\xb0\xf1\x56\x23\xa5\x24\x1b\xb6\x08\x73\xc8\x5e\xd9\xe1\x43\xe5\x63\xba\x4a\xb9\x5c\x4e\xbd\xcf\xf3\x2d\x3b\xa3\xe1\x67\x39\x23\x78\x9f\x1a\x89\xfa\x4b\xb4\x1c\x23\x6b\x7a\x4e\x60\xe3\x34\x1e\x20\x83\x54\x9c\x00\xa4\xdc\x0e\x2f\x88\x51\x5d\xdf\x29\x27\x27\xa1\xf9\xe9\x3c\xd3\x3b\xff\xdd\x56\x5f\x79\x57\x1b\x6a\x9f\x6e\xba\xb0\x9a\x40\x70\xcf\x8d\x33\xd9\xfa\xae\x29\xd5\x27\x57\xe0\x15\xc6\xb3\xe3\x1a\x2e\x23\xfd\xe8\xc5\x57\xbc\xaa\xbe\xc7\xac\xc6\x68\x8d\xee\x6a\x59\x0e\x3d\xd5\x7f\xc7\x60\x2e\x3d\xdd\x6e\xfc\x33\xba\x49\xee\xc4\xb3\x1d\x98\xbd\x3b\x13\xf5\xc3\xb6\x35\x2c\xe4\xff\x69\xa5\x8b\x7c\xca\x5e\x3b\x53\x28\x68\x08\xeb\x52\xe4\xd6\xef\x8c\x13\x72\xa5\x5c\x85\xb6\xc8\x95\x5c\x14\x79\x7a\x27\xf2\x2d\x00\x00\xff\xff\x3b\x0a\x54\x8b\x2e\x03\x00\x00")
func recover_tpl_bytes() ([]byte, error) {
return bindata_read(
@ -196,12 +196,12 @@ func recover_tpl() (*asset, error) {
return nil, err
}
info := bindata_file_info{name: "recover.tpl", size: 797, mode: os.FileMode(438), modTime: time.Unix(1424735212, 0)}
info := bindata_file_info{name: "recover.tpl", size: 814, mode: os.FileMode(438), modTime: time.Unix(1424932722, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _register_html_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x93\x31\x6f\xf3\x20\x10\x86\xe7\xf8\x57\x9c\x50\xe6\x78\x8f\x30\xcb\xf7\x2d\x95\xaa\x2a\x43\xd5\xb5\x22\xe6\x1c\xa3\x62\x40\x40\x9a\x44\x96\xff\x7b\xc1\x4e\xec\x38\x51\xdb\x74\xc1\xdc\xe9\x3d\xee\x7d\x4e\x67\x5a\x19\xd7\x00\x2f\x83\x34\xba\x20\x0e\x77\xd2\x07\x74\x04\x1a\x0c\xb5\x11\x05\xb1\xc6\x07\xc2\xb2\x05\x55\x7c\x8b\x0a\xa2\xba\x20\x6d\xbb\xb2\x4e\x36\xdc\x9d\x9e\xfe\x77\x1d\x61\xf3\x78\x4d\xf3\x5e\x9b\x8a\xa4\xb6\xfb\x00\x9a\x37\x78\x57\x05\xe1\x64\x63\x36\xe0\x31\x10\xf8\xe4\x6a\xdf\x4b\x0e\x32\xd4\x30\xe9\xde\x52\xbe\xeb\x62\x69\x3a\x50\x8b\x54\x68\x15\x2f\xb1\x36\x4a\xe0\xbd\x17\xc8\x19\xdd\xba\x78\x66\x8b\xb6\x5d\x5a\x29\x60\x5d\xc0\xb5\xe2\xd2\x02\x9d\xf3\x63\xb4\x8c\x91\x8a\xe0\x49\x2c\xb5\xc0\x23\xac\x20\x15\x27\x81\xe3\x7a\x87\xa3\xa2\xeb\xa8\xb7\x5c\xb3\xde\x11\xcd\xfb\xfb\xd0\xf0\x6c\x6f\xfe\x99\xcf\xcd\x72\xef\x0f\xc6\x09\xc2\x36\xe7\xdb\x77\xb3\x1a\x95\xe7\x29\x4d\xf1\x0c\x7e\x33\xa6\xaf\xb1\xe7\x80\x83\xff\xd5\xe5\x85\x47\x01\xe6\xce\x4b\xa3\x2b\xe9\x9a\xf7\x89\xe0\xdf\x90\x81\xdf\x48\xee\x2a\x7f\x26\xba\x7d\xf6\x01\xb2\xdb\x0e\x7f\x20\x1c\x8c\x0e\x86\xfc\x7e\xdb\xc8\x69\x15\x9f\xcd\x4e\x6a\x32\xf6\xa6\x1c\x6a\x87\x55\x41\xf2\x88\xce\x75\x89\x8a\xe6\x9c\x65\x37\x6f\xd4\x52\x08\xd4\x64\x5a\xf8\xa3\x77\xd5\x4b\x0c\xd2\x66\x8e\x3b\xde\x67\x5f\xcd\x07\xea\x61\x61\x33\x9a\xa7\x9f\x90\x7d\x05\x00\x00\xff\xff\xe5\x8f\x49\x7c\x8b\x03\x00\x00")
var _register_html_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x53\x4d\x6f\xe2\x30\x10\x3d\x93\x5f\x31\xb2\x38\x93\x3b\x72\x72\xd9\xbd\xec\x65\x85\x56\xab\x5e\x2b\x13\x4f\x88\x55\x7f\xc9\x76\x0a\x28\xca\x7f\xaf\x9d\x40\x42\x40\x6d\xe9\xc5\xf6\x8c\xde\x9b\x79\x6f\x34\xa6\xb5\x71\x0a\x58\x15\x84\xd1\x05\xe9\x3a\x65\x5a\x1d\x2c\x0b\x0d\x72\x20\x0e\x0f\xc2\x07\x74\xa4\xef\x09\x28\x0c\x8d\xe1\x05\xb1\xc6\x07\x52\x66\x2b\x2a\xd9\x1e\x25\x44\x7e\xe2\x6d\xac\x13\x8a\xb9\xf3\x9f\xdf\x11\x5b\x76\x5d\x10\x41\x22\xdc\x66\xb7\x34\x1f\x18\x89\x2a\xb4\x6d\x03\x68\xa6\xf0\x81\x0b\xe1\x6c\x63\x36\xe0\x29\x10\x78\x67\xb2\x1d\x20\x47\x11\x9a\x9b\x6a\x2f\x29\xdf\xf7\x91\x9a\x0e\xd4\x3c\x11\xad\x64\x15\x36\x46\x72\x1c\x14\x3d\x2a\x20\x90\x97\x74\xef\xe2\x99\xad\xba\x6e\x6d\x05\x87\x6d\xb1\x40\x5c\x1b\xa1\x73\x7e\x8a\xd6\x31\x92\x71\x0e\x09\x2c\x34\xc7\x13\x6c\x20\x91\x13\xc0\x31\x7d\xc0\x09\xd1\xf7\xd4\x5b\xa6\xcb\x41\x17\xcd\x87\xf7\xd8\xf0\x22\x72\x79\x2d\x67\x68\x99\xf7\x47\xe3\x38\x29\x77\x97\xd7\x67\x13\x9b\x90\x97\x59\xcd\xf1\x62\x04\xbb\x29\x7d\x6b\x7b\x69\x70\xd4\xbf\xb9\x56\x78\xd6\xc0\x52\x79\x65\x74\x2d\x9c\x7a\x9d\x1d\xfc\x1a\x33\xf0\x9d\x93\x07\xe6\xd7\x8e\xee\xcb\x3e\xe1\xec\xbe\xc3\x0f\x1c\x8e\x42\x47\x41\xbe\xdd\x2b\x31\x2f\xe4\xbf\xeb\xc7\x98\xda\x53\x06\x8d\xc3\xba\x20\x79\x74\xcf\x74\x85\x92\xe6\xac\xcc\xee\xca\x34\x82\x73\xd4\x64\xde\xfc\x93\x77\xf5\xdf\x18\xa4\xe5\x9c\x96\x7d\xc8\xfe\x37\x6f\xa8\xc7\x9d\xcd\x68\x9e\x7e\x69\xf9\x11\x00\x00\xff\xff\x0e\xa6\x2d\x81\xac\x03\x00\x00")
func register_html_tpl_bytes() ([]byte, error) {
return bindata_read(
@ -216,7 +216,7 @@ func register_html_tpl() (*asset, error) {
return nil, err
}
info := bindata_file_info{name: "register.html.tpl", size: 907, mode: os.FileMode(438), modTime: time.Unix(1424722297, 0)}
info := bindata_file_info{name: "register.html.tpl", size: 940, mode: os.FileMode(438), modTime: time.Unix(1424932595, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}

View File

@ -11,6 +11,7 @@ import (
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
@ -23,6 +24,12 @@ var (
funcMap = template.FuncMap{
"title": strings.Title,
"mountpathed": func(location string) string {
if authboss.Cfg.MountPath == "/" {
return location
}
return path.Join(authboss.Cfg.MountPath, location)
},
}
)

View File

@ -1,5 +1,5 @@
{{.flash_success}}
<form action="/login" method="POST">
<form action="{{mountpathed "login"}}" method="POST">
{{if .error}}{{.error}}<br />{{end}}
<input type="text" class="form-control" name="{{.primaryID}}" placeholder="{{title .primaryID}}" value="{{.primaryIDValue}}"><br />
<input type="password" class="form-control" name="password" placeholder="Password"><br />

View File

@ -1,4 +1,4 @@
<form action="/recover/complete" method="POST">
<form action="{{mountpathed "recover/complete"}}" method="POST">
<input type="hidden" name="token" value="{{.token}}" />
<input type="password" name="password" placeholder="Password" value="{{.password}}" /><br />
{{with .errs}}{{with $errlist := index . "password"}}{{range $errlist}}<span>{{.}}</span><br />{{end}}{{end}}{{end}}

View File

@ -1,4 +1,4 @@
<form action="/recover" method="POST">
<form action="{{mountpathed "recover"}}" method="POST">
{{with .flashError}}{{.}}<br />{{end}}
<input type="text" name="{{.primaryID}}" placeholder="{{title .primaryID}}" value="{{.primaryIDValue}}" /><br />
{{$pid := .primaryID}}{{with .errs}}{{with $errlist := index . $pid}}{{range $errlist}}<span>{{.}}</span><br />{{end}}{{end}}{{end}}

View File

@ -1,6 +1,6 @@
<form action="register" method="post">
<label for="{{.primaryID}}">{{.primaryID}}:</label>
<input name="{{.primaryID}}" type="text" value="{{with .primaryIDValue}}{{.}}{{end}}" placeholder="{{.primaryID}}" /><br />
<form action="{{mountpathed "register"}}" method="post">
<label for="{{.primaryID}}">{{title .primaryID}}:</label>
<input name="{{.primaryID}}" type="text" value="{{with .primaryIDValue}}{{.}}{{end}}" placeholder="{{title .primaryID}}" /><br />
{{$pid := .primaryID}}{{with .errs}}{{with $errlist := index . $pid}}{{range $errlist}}<span>{{.}}</span><br />{{end}}{{end}}{{end}}
<label for="password">Password:</label>
<input name="password" type="password" placeholder="Password" /><br />
@ -8,7 +8,7 @@
<label for="confirm_password">Confirm Password:</label>
<input name="confirm_password" type="password" placeholder="Confirm Password" /><br />
{{with .errs}}{{range .confirm_password}}<span>{{.}}</span><br />{{end}}{{end}}
<input type="submit" value="Login"><br />
<input type="submit" value="Register"><br />
<a href="/">Cancel</a>
<input type="hidden" name="{{.xsrfName}}" value="{{.xsrfToken}}" />

View File

@ -26,6 +26,10 @@ const (
StoreRecoverToken = "recover_token"
StoreRecoverTokenExpiry = "recover_token_expiry"
recoverInitiateSuccessFlash = "An email has been sent with further instructions on how to reset your password"
recoverTokenExpiredFlash = "Account recovery request has expired. Please try again."
recoverFailedErrorFlash = "Account recovery has failed. Please contact tech support."
)
var errRecoveryTokenExpired = errors.New("recovery token expired")
@ -123,7 +127,7 @@ func (rec *Recover) startHandlerFunc(ctx *authboss.Context, w http.ResponseWrite
}
if err := ctx.LoadUser(primaryID); err == authboss.ErrUserNotFound {
errData.MergeKV("flashError", authboss.Cfg.RecoverFailedErrorFlash)
errData.MergeKV("flashError", recoverFailedErrorFlash)
return rec.templates.Render(ctx, w, r, tplRecover, errData)
} else if err != nil {
return err
@ -148,8 +152,8 @@ func (rec *Recover) startHandlerFunc(ctx *authboss.Context, w http.ResponseWrite
go goRecoverEmail(rec, email, encodedToken)
ctx.SessionStorer.Put(authboss.FlashSuccessKey, authboss.Cfg.RecoverInitiateSuccessFlash)
http.Redirect(w, r, authboss.Cfg.RecoverRedirect, http.StatusFound)
ctx.SessionStorer.Put(authboss.FlashSuccessKey, recoverInitiateSuccessFlash)
http.Redirect(w, r, authboss.Cfg.RecoverOKPath, http.StatusFound)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
@ -190,7 +194,7 @@ func (r *Recover) completeHandlerFunc(ctx *authboss.Context, w http.ResponseWrit
case methodGET:
_, err = verifyToken(ctx)
if err == errRecoveryTokenExpired {
return authboss.ErrAndRedirect{err, "/recover", "", authboss.Cfg.RecoverTokenExpiredFlash}
return authboss.ErrAndRedirect{err, "/recover", "", recoverTokenExpiredFlash}
} else if err != nil {
return authboss.ErrAndRedirect{err, "/", "", ""}
}
@ -243,7 +247,7 @@ func (r *Recover) completeHandlerFunc(ctx *authboss.Context, w http.ResponseWrit
}
ctx.SessionStorer.Put(authboss.SessionKey, primaryID)
http.Redirect(w, req, authboss.Cfg.AuthLoginSuccessRoute, http.StatusFound)
http.Redirect(w, req, authboss.Cfg.AuthLoginOKPath, http.StatusFound)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}

View File

@ -92,7 +92,7 @@ func TestRecover_startHandlerFunc_GET(t *testing.T) {
}
body := w.Body.String()
if !strings.Contains(body, `<form action="/recover"`) {
if !strings.Contains(body, `<form action="recover"`) {
t.Error("Should have rendered a form")
}
if !strings.Contains(body, `name="`+authboss.Cfg.PrimaryID) {