mirror of
https://github.com/volatiletech/authboss.git
synced 2025-01-06 03:54:17 +02:00
Reworking auth
This commit is contained in:
parent
0840d9743c
commit
1198466d76
180
auth/auth.go
180
auth/auth.go
@ -3,66 +3,42 @@ package auth
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"gopkg.in/authboss.v0"
|
||||
"gopkg.in/authboss.v0/internal/views"
|
||||
"gopkg.in/authboss.v0/internal/render"
|
||||
)
|
||||
|
||||
const (
|
||||
methodGET = "GET"
|
||||
methodPOST = "POST"
|
||||
|
||||
pageLogin = "login.tpl"
|
||||
tplLogin = "login.tpl"
|
||||
|
||||
attrUsername = "username"
|
||||
attrPassword = "password"
|
||||
storeUsername = "username"
|
||||
storePassword = "password"
|
||||
)
|
||||
|
||||
func init() {
|
||||
a := &Auth{}
|
||||
a := &AuthModule{}
|
||||
authboss.RegisterModule("auth", a)
|
||||
}
|
||||
|
||||
type AuthPage struct {
|
||||
Error string
|
||||
Username string
|
||||
|
||||
ShowRemember bool
|
||||
ShowRecover bool
|
||||
|
||||
FlashSuccess string
|
||||
FlashError string
|
||||
|
||||
XSRFName string
|
||||
XSRFToken string
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
routes authboss.RouteTable
|
||||
storageOptions authboss.StorageOptions
|
||||
templates map[string]*template.Template
|
||||
|
||||
type AuthModule struct {
|
||||
templates render.Templates
|
||||
policies []authboss.Validator
|
||||
isRememberLoaded bool
|
||||
isRecoverLoaded bool
|
||||
}
|
||||
|
||||
func (a *Auth) Initialize() (err error) {
|
||||
if a.templates, err = views.Get(authboss.Cfg.Layout, authboss.Cfg.ViewsPath, pageLogin); err != nil {
|
||||
func (a *AuthModule) Initialize() (err error) {
|
||||
a.templates, err = render.LoadTemplates(authboss.Cfg.Layout, authboss.Cfg.ViewsPath, tplLogin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.routes = authboss.RouteTable{
|
||||
"login": a.loginHandlerFunc,
|
||||
"logout": a.logoutHandlerFunc,
|
||||
}
|
||||
a.storageOptions = authboss.StorageOptions{
|
||||
attrUsername: authboss.String,
|
||||
attrPassword: authboss.String,
|
||||
}
|
||||
a.policies = authboss.FilterValidators(authboss.Cfg.Policies, "username", "password")
|
||||
|
||||
a.isRememberLoaded = authboss.IsLoaded("remember")
|
||||
a.isRecoverLoaded = authboss.IsLoaded("recover")
|
||||
@ -70,15 +46,21 @@ func (a *Auth) Initialize() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Auth) Routes() authboss.RouteTable {
|
||||
return a.routes
|
||||
func (a *AuthModule) Routes() authboss.RouteTable {
|
||||
return authboss.RouteTable{
|
||||
"login": a.loginHandlerFunc,
|
||||
"logout": a.logoutHandlerFunc,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Auth) Storage() authboss.StorageOptions {
|
||||
return a.storageOptions
|
||||
func (a *AuthModule) Storage() authboss.StorageOptions {
|
||||
return authboss.StorageOptions{
|
||||
storeUsername: authboss.String,
|
||||
storePassword: authboss.String,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) {
|
||||
func (a *AuthModule) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
switch r.Method {
|
||||
case methodGET:
|
||||
if _, ok := ctx.SessionStorer.Get(authboss.SessionKey); ok {
|
||||
@ -87,96 +69,64 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
|
||||
}
|
||||
}
|
||||
|
||||
page := AuthPage{
|
||||
ShowRemember: a.isRememberLoaded,
|
||||
ShowRecover: a.isRecoverLoaded,
|
||||
XSRFName: authboss.Cfg.XSRFName,
|
||||
XSRFToken: authboss.Cfg.XSRFMaker(w, r),
|
||||
}
|
||||
|
||||
if msg, ok := ctx.SessionStorer.Get(authboss.FlashSuccessKey); ok {
|
||||
page.FlashSuccess = msg
|
||||
ctx.SessionStorer.Del(authboss.FlashSuccessKey)
|
||||
}
|
||||
|
||||
tpl := a.templates[pageLogin]
|
||||
tpl.Execute(w, page)
|
||||
data := authboss.NewHTMLData("showRemember", a.isRememberLoaded, "showRecover", a.isRecoverLoaded)
|
||||
return a.templates.Render(ctx, w, r, tplLogin, data)
|
||||
case methodPOST:
|
||||
u, ok := ctx.FirstPostFormValue("username")
|
||||
if !ok {
|
||||
fmt.Fprintln(authboss.Cfg.LogWriter, errors.New("auth: Expected postFormValue 'username' to be in the context"))
|
||||
interrupted, err := authboss.Cfg.Callbacks.FireBefore(authboss.EventAuth, ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if interrupted {
|
||||
return errors.New("auth interrupted")
|
||||
}
|
||||
|
||||
if err := authboss.Cfg.Callbacks.FireBefore(authboss.EventAuth, ctx); err != nil {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
username, _ := ctx.FirstPostFormValue("username")
|
||||
password, _ := ctx.FirstPostFormValue("password")
|
||||
|
||||
tpl := a.templates[pageLogin]
|
||||
tpl.ExecuteTemplate(w, tpl.Name(), AuthPage{
|
||||
Error: err.Error(),
|
||||
Username: u,
|
||||
ShowRemember: a.isRememberLoaded,
|
||||
ShowRecover: a.isRecoverLoaded,
|
||||
XSRFName: authboss.Cfg.XSRFName,
|
||||
XSRFToken: authboss.Cfg.XSRFMaker(w, r),
|
||||
})
|
||||
errData := authboss.NewHTMLData(
|
||||
"error", "invalid username and/or password",
|
||||
"username", username,
|
||||
"showRemember", a.isRememberLoaded,
|
||||
"showRecover", a.isRecoverLoaded,
|
||||
)
|
||||
|
||||
if validationErrs := ctx.Validate(a.policies); len(validationErrs) > 0 {
|
||||
fmt.Fprintln(authboss.Cfg.LogWriter, "auth: form validation failed:", validationErrs.Map())
|
||||
return a.templates.Render(ctx, w, r, tplLogin, errData)
|
||||
}
|
||||
|
||||
p, ok := ctx.FirstPostFormValue("password")
|
||||
if !ok {
|
||||
fmt.Fprintln(authboss.Cfg.LogWriter, errors.New("auth: Expected postFormValue 'password' to be in the context"))
|
||||
if err := validateCredentials(ctx, username, password); err != nil {
|
||||
fmt.Fprintln(authboss.Cfg.LogWriter, "auth: failed to validate credentials:", err)
|
||||
return a.templates.Render(ctx, w, r, tplLogin, errData)
|
||||
}
|
||||
|
||||
if err := a.authenticate(ctx, u, p); err != nil {
|
||||
fmt.Fprintln(authboss.Cfg.LogWriter, err)
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
tpl := a.templates[pageLogin]
|
||||
tpl.ExecuteTemplate(w, tpl.Name(), AuthPage{
|
||||
Error: "invalid username and/or password",
|
||||
Username: u,
|
||||
ShowRemember: a.isRememberLoaded,
|
||||
ShowRecover: a.isRecoverLoaded,
|
||||
XSRFName: authboss.Cfg.XSRFName,
|
||||
XSRFToken: authboss.Cfg.XSRFMaker(w, r),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SessionStorer.Put(authboss.SessionKey, u)
|
||||
ctx.SessionStorer.Put(authboss.SessionKey, username)
|
||||
authboss.Cfg.Callbacks.FireAfter(authboss.EventAuth, ctx)
|
||||
|
||||
http.Redirect(w, r, authboss.Cfg.AuthLoginSuccessRoute, http.StatusFound)
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Auth) authenticate(ctx *authboss.Context, username, password string) error {
|
||||
var userInter interface{}
|
||||
var err error
|
||||
if userInter, err = authboss.Cfg.Storer.Get(username, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx.User = authboss.Unbind(userInter)
|
||||
|
||||
pwdIntf, ok := ctx.User[attrPassword]
|
||||
if !ok {
|
||||
return errors.New("auth: User attributes did not include a password.")
|
||||
}
|
||||
|
||||
pwd, ok := pwdIntf.(string)
|
||||
if !ok {
|
||||
return errors.New("auth: User password was not a string somehow.")
|
||||
}
|
||||
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(pwd), []byte(password)); err != nil {
|
||||
return errors.New("invalid password")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Auth) logoutHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) {
|
||||
func validateCredentials(ctx *authboss.Context, username, password string) error {
|
||||
if err := ctx.LoadUser(username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
actualPassword, err := ctx.User.StringErr(storePassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(actualPassword), []byte(password)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AuthModule) logoutHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
switch r.Method {
|
||||
case methodGET:
|
||||
ctx.SessionStorer.Del(authboss.SessionKey)
|
||||
@ -184,4 +134,6 @@ func (a *Auth) logoutHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,262 +1 @@
|
||||
package auth
|
||||
|
||||
/*import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/authboss.v0"
|
||||
)
|
||||
|
||||
func getCompiledTemplate(path string, data interface{}) (b *bytes.Buffer, err error) {
|
||||
var file []byte
|
||||
if file, err = ioutil.ReadFile(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tpl *template.Template
|
||||
if tpl, err = template.New("tpl").Parse(string(file)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b = &bytes.Buffer{}
|
||||
if err = tpl.Execute(b, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func TestAuth_Storage(t *testing.T) {
|
||||
a := &Auth{}
|
||||
if err := a.Initialize(); err != nil {
|
||||
t.Errorf("Unexpected config error: %v", err)
|
||||
}
|
||||
options := a.Storage()
|
||||
|
||||
tests := []struct {
|
||||
Name string
|
||||
Type authboss.DataType
|
||||
}{
|
||||
{"username", authboss.String},
|
||||
{"password", authboss.String},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
if value, ok := options[test.Name]; !ok {
|
||||
t.Errorf("%d> Expected key %s", i, test.Name)
|
||||
continue
|
||||
} else if value != test.Type {
|
||||
t.Errorf("$d> Expected key %s to have value %v, got %v", i, test.Name, test.Type, value)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_Routes(t *testing.T) {
|
||||
a := &Auth{}
|
||||
if err := a.Initialize(); err != nil {
|
||||
t.Errorf("Unexpected config error: %v", err)
|
||||
}
|
||||
routes := a.Routes()
|
||||
|
||||
tests := []struct {
|
||||
Route string
|
||||
}{
|
||||
{"login"},
|
||||
{"logout"},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
if value, ok := routes[test.Route]; !ok {
|
||||
t.Errorf("%d> Expected key %s", i, test.Route)
|
||||
} else if value == nil {
|
||||
t.Errorf("%d> Expected key %s to have func", i, test.Route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_GET(t *testing.T) {
|
||||
a := &Auth{}
|
||||
if err := a.Initialize(); err != nil {
|
||||
t.Errorf("Unexpected config error: %v", err)
|
||||
}
|
||||
|
||||
r, err := http.NewRequest("GET", "/login", nil)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error '%s'", err)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
ctx, err := authboss.ContextFromRequest(r)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error '%s'", err)
|
||||
}
|
||||
ctx.SessionStorer = testClientStorer{}
|
||||
|
||||
a.loginHandlerFunc(ctx, w, r)
|
||||
|
||||
if tpl, err := getCompiledTemplate("views/login.tpl", nil); err != nil {
|
||||
t.Errorf("Unexpected error '%s'", err)
|
||||
} else {
|
||||
if !bytes.Equal(tpl.Bytes(), w.Body.Bytes()) {
|
||||
t.Errorf("Expected '%s', got '%s'", tpl.Bytes(), w.Body.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_POST(t *testing.T) {
|
||||
tests := []struct {
|
||||
Username, Password string
|
||||
StatusCode int
|
||||
LoginSuccess bool
|
||||
Location string
|
||||
BodyData *AuthPage
|
||||
}{
|
||||
{"john", "1234", http.StatusFound, true, "/dashboard", nil},
|
||||
{"jane", "1234", http.StatusForbidden, false, "", &AuthPage{"invalid username and/or password", "jane", false, false, "", ""}},
|
||||
{"mike", "", http.StatusForbidden, false, "", &AuthPage{"invalid username and/or password", "jane", false, false, "", ""}},
|
||||
}
|
||||
|
||||
authboss.Cfg.Storer = NewMockUserStorer()
|
||||
authboss.Cfg.AuthLoginSuccessRoute = "/dashboard"
|
||||
|
||||
for i, test := range tests {
|
||||
a := &Auth{}
|
||||
if err := a.Initialize(); err != nil {
|
||||
t.Errorf("%d> Unexpected config error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
postData := url.Values{}
|
||||
postData.Set("username", test.Username)
|
||||
postData.Set("password", test.Password)
|
||||
|
||||
r, err := http.NewRequest("POST", "/login", strings.NewReader(postData.Encode()))
|
||||
if err != nil {
|
||||
t.Errorf("%d> Unexpected error '%s'", i, err)
|
||||
continue
|
||||
}
|
||||
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
ctx, err := authboss.ContextFromRequest(r)
|
||||
if err != nil {
|
||||
t.Errorf("%d> Unexpected error '%s'", i, err)
|
||||
continue
|
||||
}
|
||||
ctx.SessionStorer = testClientStorer{}
|
||||
|
||||
a.loginHandlerFunc(ctx, w, r)
|
||||
|
||||
if test.LoginSuccess {
|
||||
if val, ok := ctx.SessionStorer.Get(authboss.SessionKey); !ok {
|
||||
t.Errorf("%d> Expected login to be present", i)
|
||||
} else if val != test.Username {
|
||||
t.Errorf("%d> Expected username %s, got %s", i, test.Username, val)
|
||||
}
|
||||
}
|
||||
|
||||
if test.StatusCode != w.Code {
|
||||
t.Errorf("%d> Expected status code %d, got %d", i, test.StatusCode, w.Code)
|
||||
continue
|
||||
}
|
||||
|
||||
location := w.Header().Get("Location")
|
||||
if test.Location != location {
|
||||
t.Errorf("%d> Expected lcoation %s, got %s", i, test.Location, location)
|
||||
continue
|
||||
}
|
||||
|
||||
if test.BodyData != nil {
|
||||
if tpl, err := getCompiledTemplate("views/login.tpl", test.BodyData); err != nil {
|
||||
t.Errorf("%d> Unexpected error '%s'", i, err)
|
||||
continue
|
||||
} else {
|
||||
if !bytes.Equal(tpl.Bytes(), w.Body.Bytes()) {
|
||||
t.Errorf("%d> Expected '%s', got '%s'", i, tpl.Bytes(), w.Body.Bytes())
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_OtherMethods(t *testing.T) {
|
||||
a := Auth{}
|
||||
methods := []string{"HEAD", "PUT", "DELETE", "TRACE", "CONNECT"}
|
||||
|
||||
for i, method := range methods {
|
||||
r, err := http.NewRequest(method, "/login", nil)
|
||||
if err != nil {
|
||||
t.Errorf("%d> Unexpected error '%s'", i, err)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
a.loginHandlerFunc(nil, w, r)
|
||||
|
||||
if http.StatusMethodNotAllowed != w.Code {
|
||||
t.Errorf("%d> Expected status code %d, got %d", i, http.StatusMethodNotAllowed, w.Code)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_logoutHandlerFunc_GET(t *testing.T) {
|
||||
authboss.Cfg.AuthLogoutRoute = "/dashboard"
|
||||
a := Auth{}
|
||||
if err := a.Initialize(); err != nil {
|
||||
t.Errorf("Unexpeced config error '%s'", err)
|
||||
}
|
||||
r, err := http.NewRequest("GET", "/logout", nil)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error '%s'", err)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
ctx, err := authboss.ContextFromRequest(r)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error '%s'", err)
|
||||
}
|
||||
ctx.SessionStorer = testClientStorer{authboss.SessionKey: "asdf"}
|
||||
a.logoutHandlerFunc(ctx, w, r)
|
||||
|
||||
if _, ok := ctx.SessionStorer.Get(authboss.SessionKey); ok {
|
||||
t.Errorf("Expected to be logged out")
|
||||
}
|
||||
|
||||
if http.StatusFound != w.Code {
|
||||
t.Errorf("Expected status code %d, got %d", http.StatusFound, w.Code)
|
||||
}
|
||||
|
||||
location := w.Header().Get("Location")
|
||||
if location != "/dashboard" {
|
||||
t.Errorf("Expected lcoation %s, got %s", "/dashboard", location)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_logoutHandlerFunc_OtherMethods(t *testing.T) {
|
||||
a := Auth{}
|
||||
methods := []string{"HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT"}
|
||||
|
||||
for i, method := range methods {
|
||||
r, err := http.NewRequest(method, "/logout", nil)
|
||||
if err != nil {
|
||||
t.Errorf("%d> Unexpected error '%s'", i, err)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
a.logoutHandlerFunc(nil, w, r)
|
||||
|
||||
if http.StatusMethodNotAllowed != w.Code {
|
||||
t.Errorf("%d> Expected status code %d, got %d", i, http.StatusMethodNotAllowed, w.Code)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -1,59 +0,0 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"strings"
|
||||
|
||||
"gopkg.in/authboss.v0"
|
||||
)
|
||||
|
||||
type MockUser struct {
|
||||
Username, Password string
|
||||
}
|
||||
|
||||
type MockUserStorer struct {
|
||||
Users []MockUser
|
||||
}
|
||||
|
||||
func NewMockUserStorer() *MockUserStorer {
|
||||
return &MockUserStorer{
|
||||
Users: []MockUser{
|
||||
{"John", "$2a$10$0hwgO.5fThx0DOHbErIxaemMTrU3RDNJchM6ToMOmFf.hkuX4RKRK"}, // 1234
|
||||
{"Jane", "$2a$10$tzIH0BU8BpOOsf768Iv4KecouL0gPgrvCpYZpBwJozlqezfabBpr2"}, // asdf
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s MockUserStorer) Create(key string, attr authboss.Attributes) error {
|
||||
return errors.New("Not implemented")
|
||||
}
|
||||
|
||||
func (s MockUserStorer) Put(key string, attr authboss.Attributes) error {
|
||||
return errors.New("Not implemented")
|
||||
}
|
||||
|
||||
func (s MockUserStorer) Get(key string, attrMeta authboss.AttributeMeta) (result interface{}, err error) {
|
||||
for _, u := range s.Users {
|
||||
if strings.EqualFold(u.Username, key) {
|
||||
return u, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("User not found")
|
||||
}
|
||||
|
||||
type testClientStorer map[string]string
|
||||
|
||||
func (t testClientStorer) Put(key, value string) {
|
||||
t[key] = value
|
||||
}
|
||||
|
||||
func (t testClientStorer) Get(key string) (string, bool) {
|
||||
s, ok := t[key]
|
||||
return s, ok
|
||||
}
|
||||
|
||||
func (t testClientStorer) Del(key string) {
|
||||
delete(t, key)
|
||||
}
|
@ -73,10 +73,10 @@ func NewConfig() *Config {
|
||||
HostName: "localhost:8080",
|
||||
BCryptCost: bcrypt.DefaultCost,
|
||||
|
||||
Layout: template.Must(template.New("").Parse(`{{template "authboss" .}}`)),
|
||||
LayoutEmail: template.Must(template.New("").Parse(`{{template "authboss" .}}`)),
|
||||
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: "/",
|
||||
AuthLogoutRoute: "/login",
|
||||
AuthLoginSuccessRoute: "/",
|
||||
|
||||
Policies: []Validator{
|
||||
|
@ -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(1424060528, 0)}
|
||||
info := bindata_file_info{name: "confirm_email.html.tpl", size: 26, mode: os.FileMode(438), modTime: time.Unix(1424471280, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@ -96,52 +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(1424060528, 0)}
|
||||
info := bindata_file_info{name: "confirm_email.txt.tpl", size: 9, mode: os.FileMode(438), modTime: time.Unix(1424471280, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _layout_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xd4\x95\xc1\x72\xd3\x30\x10\x86\xef\x79\x0a\x8d\x0e\xdc\x2c\xd1\x26\xc0\x4c\xeb\xe4\x06\x2f\xc0\x13\xc8\xd6\x3a\x56\x90\x25\xa3\x5d\xb7\xc9\x78\xfa\xee\xc8\x96\x1b\x5c\xd7\x40\x87\x03\x33\xe4\x60\x67\x37\xda\xff\xdf\xfd\x34\x52\xf2\x9a\x1a\x7b\xd8\xe4\x35\x28\x7d\xd8\xb0\xf8\xc9\xad\x71\xdf\x58\x1d\xa0\xda\x73\x29\x1d\x90\x76\x4a\x14\xde\x13\x52\x50\x6d\xa9\x9d\x28\x7d\x23\x2b\xef\x28\x53\x8f\x80\xbe\x01\xb9\x13\xef\xc5\x56\x96\x88\x2f\xd2\x22\x26\x38\x0b\x60\xf7\x1c\xe9\x62\x01\x6b\x00\xe2\x4c\xae\xd9\x34\xea\x3c\x28\xbf\xb2\xb9\x26\xe4\x56\x6c\xc5\xcd\xe8\x71\xcd\x89\xc6\xb8\x3f\x98\x60\x19\x4c\x4b\x0c\x43\xb9\xe7\x35\x51\x8b\x77\x52\xaa\x93\x3a\x8b\xa3\xf7\x47\x0b\xaa\x35\x38\xfa\x0c\x39\x69\x4d\x81\xf2\xf4\xbd\x83\x70\x91\xb7\xe2\x26\x8e\x94\x82\xd1\xe7\x84\xfc\x90\xcb\xa4\xb7\x22\xfe\xd6\x11\x6e\xe5\x69\x39\x41\x54\x66\x74\x69\x61\xcf\x09\xce\x24\x4f\xea\x41\x25\xe5\xb9\x61\x2e\xd3\x0e\xe5\x85\xd7\x97\xf8\xd2\xe6\x81\x95\x56\x21\xee\x79\x19\x99\x2b\xe3\x20\x64\x95\xed\x8c\xe6\xa9\xbb\xbe\x37\x15\x13\x5f\xe2\x92\xfa\x6b\x57\x96\x80\xf8\xf4\x94\xda\x9e\x95\x06\xff\x38\x2d\x5f\xfe\x52\x7a\x9b\x9d\x31\xf3\x55\x85\x40\xd9\x96\x0d\x71\xa3\xb3\x8f\xb3\xe5\xcb\x12\x65\x21\x10\x1b\x9f\x19\x26\xcb\x29\xd2\x06\x1b\x83\xa8\x0a\x0b\x9c\x8d\xdb\xb4\xe7\x8d\x0a\x47\xe3\x32\xf2\xed\x1d\xfb\xf4\xa1\x3d\xdf\x2f\x94\x47\xf5\xa2\x23\xf2\x6e\xa2\x93\x02\x7e\xed\xd0\x7a\x8c\x72\x5a\x91\x7a\x36\x98\x7a\x88\xdc\xb0\x55\xee\xf0\x8e\x4c\x03\x78\x1f\x21\x0e\x51\x2e\x93\xc0\x6b\x9b\xbe\x6f\x83\x71\xb4\x4a\xeb\xda\x8a\x8c\x93\xce\x50\xfd\x0c\x67\x5f\xfb\x1e\x9c\x9e\x0a\x67\xfc\x3f\x87\xe0\xc3\xbf\xa4\xaf\x95\x3b\x42\xf8\x1f\xe1\xcf\x51\xfd\x35\xfa\x25\xe3\xb5\xa9\x6f\x17\x53\x2f\xe9\x47\xda\x13\xfd\xdd\x33\xfd\xdd\x6f\xe8\xc7\x19\xc1\xb2\xf1\x99\x69\xa8\x54\x67\x69\x0d\xe9\xb2\x22\x1b\x0e\xb5\x71\xc7\xe1\xa4\xbf\x18\xf2\xd7\x15\xc3\xf9\x5f\x91\x4e\x0c\x08\x9a\xd6\x2a\x02\xc6\x55\x47\x75\xe1\x87\xbb\x51\x2c\x70\xae\x20\x7d\x13\xe5\xeb\x6b\xba\x81\x64\xfa\xe7\xd8\x6c\x7e\x04\x00\x00\xff\xff\x06\xe2\x8e\xc9\x43\x06\x00\x00")
|
||||
|
||||
func layout_tpl_bytes() ([]byte, error) {
|
||||
return bindata_read(
|
||||
_layout_tpl,
|
||||
"layout.tpl",
|
||||
)
|
||||
}
|
||||
|
||||
func layout_tpl() (*asset, error) {
|
||||
bytes, err := layout_tpl_bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindata_file_info{name: "layout.tpl", size: 1603, mode: os.FileMode(438), modTime: time.Unix(1423465727, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _layoutemail_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xb2\x49\xcd\xb5\xab\xae\x2e\x49\xcd\x2d\xc8\x49\x2c\x49\x55\x50\x4a\x2c\x2d\xc9\x48\xca\x2f\x2e\x56\x52\xd0\xab\xad\xb5\xd1\x07\xca\x02\x02\x00\x00\xff\xff\x3a\xdb\x96\xd1\x22\x00\x00\x00")
|
||||
|
||||
func layoutemail_tpl_bytes() ([]byte, error) {
|
||||
return bindata_read(
|
||||
_layoutemail_tpl,
|
||||
"layoutEmail.tpl",
|
||||
)
|
||||
}
|
||||
|
||||
func layoutemail_tpl() (*asset, error) {
|
||||
bytes, err := layoutemail_tpl_bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindata_file_info{name: "layoutEmail.tpl", size: 34, mode: os.FileMode(438), modTime: time.Unix(1423465727, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _login_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xcc\x94\xcd\x6e\xdc\x20\x10\xc7\xef\x95\xfa\x0e\x88\xbb\xe3\x17\xb0\x2d\xf5\xd0\x9e\xfa\x11\x65\x53\xa9\x57\x0c\xb3\x01\x2d\x30\x08\xc3\x26\x91\xb5\xef\x5e\x58\x7f\x14\x6f\x36\xdb\x6b\x2c\x21\x8d\xc6\xf3\xff\x7b\xe6\x07\xb8\xd9\xa3\x37\x84\xf1\xa0\xd0\xb6\xb4\xd6\xf8\xa4\x2c\x25\x06\x82\x44\xd1\xd2\xfb\x5f\xbb\x47\xda\x7d\xfe\x44\xd2\xd3\x08\x75\x24\x5c\xb3\x61\x68\x69\x16\x55\x4f\x1e\xa3\x1b\x47\xb5\x27\x77\x5f\xbd\x47\x7f\x3a\x11\xc9\x86\x0a\x72\x3c\x8e\x60\xc5\xe9\xb4\x68\x2f\xf5\xca\xba\x18\x26\x83\xb2\xe4\x5c\x36\x38\x66\xaf\xd4\x55\x4c\x08\xb4\xb4\x6b\xd4\xda\x04\x23\x7b\x56\xc5\x01\x7c\xca\xd6\x2a\xad\x2c\xbd\xb4\x3b\x5b\x90\xf0\xea\xa0\xa5\x01\x5e\x02\xdd\xcc\xc0\xd1\x06\x8f\x9a\x12\xcb\x4c\x2a\xc8\x66\x39\xa2\xc4\x69\xc6\x41\xa2\x16\xe0\x5b\xfa\x7b\x4d\x1f\x99\x8e\xa9\x6e\x1c\xef\x96\xdc\xc5\x90\x75\x9a\x72\x01\x56\xc6\x1f\x13\x9e\x46\x7e\xf8\x3f\xbc\x99\x9e\x4b\xc2\x67\xf4\xe2\x26\xc1\x7f\x45\x1b\x82\xf7\x4b\xfa\x1d\x56\x6f\x9a\x97\xa0\x5d\xd5\x4f\xfd\x25\xda\x33\xa3\x4d\x97\xa5\x7e\x22\xb9\x93\xf8\xfc\x00\x06\x4c\x0f\xa9\xf8\x2d\x79\x2e\x81\x1f\x7a\x7c\xd9\x74\xa1\x59\x0f\xfa\xd6\xa9\x59\x55\xf3\x88\xde\xac\xe7\x20\xf8\x08\xb4\x23\xcb\x37\xc9\x0f\x28\xc7\x2b\x9d\xb7\xcd\x9e\xf7\x77\x7e\xd1\xc7\x10\x70\x9d\xbb\x0f\x96\xa4\x55\x39\xaf\x0c\xf3\xaf\xe7\x78\xc2\x30\x77\x33\xc4\xde\xa8\x40\xbb\xef\xf9\xa6\x36\xf5\xa4\xbe\x42\x81\xe3\xb1\x80\xc0\x2e\xfd\xb5\xb2\x87\x77\xcd\x89\xf4\xb0\x4f\x7f\x03\x3f\xb9\xd0\x6e\xb6\x23\x5f\x38\xc7\x68\x43\x53\xb3\xab\xa3\x94\xd4\xa4\x12\x02\xec\xc2\x2c\x6d\xe1\x9f\xdd\xc3\xb7\x9f\xd3\x85\x29\xae\x51\xce\x3e\xe2\x01\x6c\x4e\xd7\xc9\xb5\xa9\xf3\xb1\xea\xfe\x06\x00\x00\xff\xff\xb5\x6b\x5e\x3d\x98\x04\x00\x00")
|
||||
var _login_tpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x7c\x52\x5b\x6e\x83\x30\x10\xfc\xaf\xd4\x3b\xac\xf6\xbf\xe5\x02\x80\xd4\xff\x3e\xa2\x36\x3d\x80\x31\x4b\x41\xc1\x5e\xb4\xd8\x49\x2a\xc4\xdd\x6b\x07\x9c\x87\x14\x95\xaf\xd5\xec\x30\x33\xcc\x92\x37\x2c\x06\x94\x76\x1d\xdb\x02\xb3\x9e\x7f\x3a\x8b\x60\xc8\xb5\x5c\x17\xb8\xf9\xf8\xda\x62\xf9\xf8\x00\xe1\x99\xa6\xae\x81\x67\x12\x61\x99\xe7\x69\x4a\x53\x5e\x09\x64\xe5\x34\x91\xad\xe7\x79\x61\xe6\x9d\x1d\xbc\x03\xf7\x3b\x50\x81\x8e\x8e\x0e\x41\xf7\x6a\x1c\x0b\x8c\x66\x4f\x9a\xad\x13\xee\x11\xac\x32\x81\xe0\x47\x92\x38\x21\x0c\xbd\xd2\xd4\x72\x5f\x93\x14\xf8\x7d\x86\xf7\xaa\xf7\x81\x17\x2c\x13\x75\x9e\x53\xa8\xd5\x6a\xf5\x1a\x82\xc9\x81\xa5\xfe\xd7\xef\x42\xba\xf1\xdb\x24\xb8\xbc\xf3\x11\x6d\x57\xd7\x64\x93\x42\x48\x72\x1c\xa5\x79\x5f\x92\x5c\xe5\x8b\xe8\x96\x77\x64\x23\x9c\xdd\xf4\x36\xb6\x7c\xf8\x24\x43\xa6\xa2\x58\xda\xb5\xb8\x6e\x49\xef\x2a\x3e\x26\x79\x31\x67\x4d\x27\x9e\xb0\x84\xf4\x22\xbc\xd1\x6d\xd1\xa7\xee\xd3\xec\x9d\x63\xbb\x6a\x8e\xbe\x32\x9d\xc3\xf2\x35\xde\x33\xcf\x96\xdd\x9d\x40\x9a\xf7\xa7\x3c\x0a\x5a\xa1\x26\xfc\x00\xb2\x40\x58\xae\x3b\x78\xd1\x9a\xbd\x75\x79\xa6\x2e\x47\xce\xb3\x58\x6c\xf9\x17\x00\x00\xff\xff\x1e\x0e\xca\x3a\x3c\x02\x00\x00")
|
||||
|
||||
func login_tpl_bytes() ([]byte, error) {
|
||||
return bindata_read(
|
||||
@ -156,7 +116,7 @@ func login_tpl() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindata_file_info{name: "login.tpl", size: 1176, mode: os.FileMode(438), modTime: time.Unix(1424065052, 0)}
|
||||
info := bindata_file_info{name: "login.tpl", size: 572, mode: os.FileMode(438), modTime: time.Unix(1424503580, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@ -176,7 +136,7 @@ func recover_complete_tpl() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindata_file_info{name: "recover-complete.tpl", size: 1235, mode: os.FileMode(438), modTime: time.Unix(1424063388, 0)}
|
||||
info := bindata_file_info{name: "recover-complete.tpl", size: 1235, mode: os.FileMode(438), modTime: time.Unix(1424471280, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@ -196,7 +156,7 @@ func recover_html_email() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindata_file_info{name: "recover-html.email", size: 26, mode: os.FileMode(438), modTime: time.Unix(1422773459, 0)}
|
||||
info := bindata_file_info{name: "recover-html.email", size: 26, mode: os.FileMode(438), modTime: time.Unix(1424471280, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@ -216,7 +176,7 @@ func recover_text_email() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindata_file_info{name: "recover-text.email", size: 9, mode: os.FileMode(438), modTime: time.Unix(1422773459, 0)}
|
||||
info := bindata_file_info{name: "recover-text.email", size: 9, mode: os.FileMode(438), modTime: time.Unix(1424471280, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@ -236,7 +196,7 @@ func recover_tpl() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindata_file_info{name: "recover.tpl", size: 1282, mode: os.FileMode(438), modTime: time.Unix(1424063407, 0)}
|
||||
info := bindata_file_info{name: "recover.tpl", size: 1282, mode: os.FileMode(438), modTime: time.Unix(1424471280, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@ -284,8 +244,6 @@ func AssetNames() []string {
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"confirm_email.html.tpl": confirm_email_html_tpl,
|
||||
"confirm_email.txt.tpl": confirm_email_txt_tpl,
|
||||
"layout.tpl": layout_tpl,
|
||||
"layoutEmail.tpl": layoutemail_tpl,
|
||||
"login.tpl": login_tpl,
|
||||
"recover-complete.tpl": recover_complete_tpl,
|
||||
"recover-html.email": recover_html_email,
|
||||
@ -337,10 +295,6 @@ var _bintree = &_bintree_t{nil, map[string]*_bintree_t{
|
||||
}},
|
||||
"confirm_email.txt.tpl": &_bintree_t{confirm_email_txt_tpl, map[string]*_bintree_t{
|
||||
}},
|
||||
"layout.tpl": &_bintree_t{layout_tpl, map[string]*_bintree_t{
|
||||
}},
|
||||
"layoutEmail.tpl": &_bintree_t{layoutemail_tpl, map[string]*_bintree_t{
|
||||
}},
|
||||
"login.tpl": &_bintree_t{login_tpl, map[string]*_bintree_t{
|
||||
}},
|
||||
"recover-complete.tpl": &_bintree_t{recover_complete_tpl, map[string]*_bintree_t{
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/authboss.v0"
|
||||
"gopkg.in/authboss.v0/internal/views"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -63,7 +62,7 @@ func LoadTemplates(layout *template.Template, path string, files ...string) (Tem
|
||||
func (t Templates) Render(ctx *authboss.Context, w http.ResponseWriter, r *http.Request, name string, data authboss.HTMLData) error {
|
||||
tpl, ok := t[name]
|
||||
if !ok {
|
||||
return authboss.RenderErr{tpl.Name(), data, views.ErrTemplateNotFound}
|
||||
return authboss.RenderErr{tpl.Name(), data, ErrTemplateNotFound}
|
||||
}
|
||||
|
||||
data.MergeKV("xsrfName", template.HTML(authboss.Cfg.XSRFName), "xsrfToken", template.HTML(authboss.Cfg.XSRFMaker(w, r)))
|
||||
|
@ -1,44 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet" />
|
||||
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" />
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
{{if .FlashSuccess}}
|
||||
<div class="row">
|
||||
<div class="col-xs-offset-3 col-md-6">
|
||||
<div class="alert alert-success alert-dismissable" style="margin-top: 75px;">
|
||||
<button type="button" class="close" data-dismiss="alert"><span>×</span></button>
|
||||
{{print .FlashSuccess}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .FlashError}}
|
||||
<div class="row">
|
||||
<div class="col-xs-offset-3 col-md-6">
|
||||
<div class="alert alert-danger alert-dismissable" style="margin-top: 75px;">
|
||||
<button type="button" class="close" data-dismiss="alert"><span>×</span></button>
|
||||
{{print .FlashError}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="row" style="margin-top: 25px;">
|
||||
<div class="col-md-offset-4 col-md-4">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"></div>
|
||||
<div class="panel-body">
|
||||
{{template "authboss" .}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
<em>{{template "authboss" .}}</em>
|
@ -1,27 +1,10 @@
|
||||
<form action="/login" method="POST">
|
||||
<div class="form-group{{if .Error}} has-error{{end}}">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-user"></i></span>
|
||||
<input type="text" class="form-control" name="username" placeholder="Username" value="{{.Username}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group{{if .Error}} has-error{{end}}">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-lock"></i></span>
|
||||
<input type="password" class="form-control" name="password" placeholder="Password">
|
||||
</div>
|
||||
<span class="help-block">{{.Error}}</span>
|
||||
</div>
|
||||
{{if .ShowRemember}}
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="rm" value="true"> Remember Me
|
||||
</label>
|
||||
</div>
|
||||
{{end}}
|
||||
<button class="btn btn-primary btn-block" type="submit">Login</button>
|
||||
{{if .ShowRecover}}
|
||||
<a class="btn btn-link btn-block" type="submit" href="/recover">Recover Account</a>
|
||||
{{end}}
|
||||
<input type="hidden" name="{{.XSRFName}}" value="{{.XSRFToken}}" />
|
||||
{{if .error}}{{.error}}<br />{{end}}
|
||||
<input type="text" class="form-control" name="username" placeholder="Username" value="{{.username}}">
|
||||
<input type="password" class="form-control" name="password" placeholder="Password">
|
||||
<input type="hidden" name="{{.xsrfName}}" value="{{.xsrfToken}}" />
|
||||
{{if .showRemember}}<input type="checkbox" name="rm" value="true"> Remember Me{{end}}
|
||||
<br />
|
||||
<button type="submit">Login</button>
|
||||
{{if .showRecover}}<a href="/recover">Recover Account</a>{{end}}
|
||||
</form>
|
Loading…
Reference in New Issue
Block a user