1
0
mirror of https://github.com/volatiletech/authboss.git synced 2025-01-24 05:17:10 +02:00
authboss/auth/auth.go

170 lines
4.2 KiB
Go
Raw Normal View History

// Package auth implements password based user logins.
package auth
import (
2015-02-23 15:51:42 -08:00
"errors"
"fmt"
"net/http"
2015-01-12 23:51:25 -08:00
"golang.org/x/crypto/bcrypt"
2015-01-09 22:51:02 -08:00
"gopkg.in/authboss.v0"
"gopkg.in/authboss.v0/internal/response"
)
const (
methodGET = "GET"
methodPOST = "POST"
tplLogin = "login.html.tpl"
2015-01-12 21:08:52 -08:00
)
2015-01-10 22:49:06 -08:00
func init() {
authboss.RegisterModule("auth", &Auth{})
}
2015-03-16 14:42:45 -07:00
// Auth module
2015-02-23 15:51:42 -08:00
type Auth struct {
2015-03-31 15:27:47 -07:00
*authboss.Authboss
templates response.Templates
}
2015-03-16 14:42:45 -07:00
// Initialize module
2015-03-31 15:27:47 -07:00
func (a *Auth) Initialize(ab *authboss.Authboss) (err error) {
a.Authboss = ab
if a.Storer == nil {
2015-03-16 14:42:45 -07:00
return errors.New("auth: Need a Storer")
2015-02-23 15:51:42 -08:00
}
2015-03-31 15:27:47 -07:00
if len(a.XSRFName) == 0 {
2015-02-24 15:01:56 -08:00
return errors.New("auth: XSRFName must be set")
}
2015-03-31 15:27:47 -07:00
if a.XSRFMaker == nil {
2015-02-24 15:01:56 -08:00
return errors.New("auth: XSRFMaker must be defined")
}
2015-03-31 15:27:47 -07:00
a.templates, err = response.LoadTemplates(a.Authboss, a.Layout, a.ViewsPath, tplLogin)
2015-02-20 23:33:35 -08:00
if err != nil {
2015-01-18 14:24:20 -08:00
return err
}
return nil
}
2015-03-16 14:42:45 -07:00
// Routes for the module
2015-02-23 15:51:42 -08:00
func (a *Auth) Routes() authboss.RouteTable {
2015-02-20 23:33:35 -08:00
return authboss.RouteTable{
"/login": a.loginHandlerFunc,
"/logout": a.logoutHandlerFunc,
2015-02-20 23:33:35 -08:00
}
}
2015-03-16 14:42:45 -07:00
// Storage requirements
2015-02-23 15:51:42 -08:00
func (a *Auth) Storage() authboss.StorageOptions {
2015-02-20 23:33:35 -08:00
return authboss.StorageOptions{
2015-03-31 15:27:47 -07:00
a.PrimaryID: authboss.String,
2015-02-22 13:16:11 -08:00
authboss.StorePassword: authboss.String,
2015-02-20 23:33:35 -08:00
}
}
2015-02-23 15:51:42 -08:00
func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
switch r.Method {
case methodGET:
if _, ok := ctx.SessionStorer.Get(authboss.SessionKey); ok {
2015-02-22 13:16:11 -08:00
if halfAuthed, ok := ctx.SessionStorer.Get(authboss.SessionHalfAuthKey); !ok || halfAuthed == "false" {
2015-03-31 15:27:47 -07:00
//http.Redirect(w, r, a.AuthLoginOKPath, http.StatusFound, true)
response.Redirect(ctx, w, r, a.AuthLoginOKPath, "", "", true)
2015-02-24 15:01:56 -08:00
return nil
}
}
2015-02-23 15:51:42 -08:00
data := authboss.NewHTMLData(
2015-03-31 15:27:47 -07:00
"showRemember", a.IsLoaded("remember"),
"showRecover", a.IsLoaded("recover"),
"primaryID", a.PrimaryID,
2015-02-23 15:51:42 -08:00
"primaryIDValue", "",
)
2015-02-20 23:33:35 -08:00
return a.templates.Render(ctx, w, r, tplLogin, data)
case methodPOST:
2015-03-31 15:27:47 -07:00
key, _ := ctx.FirstPostFormValue(a.PrimaryID)
2015-02-20 23:33:35 -08:00
password, _ := ctx.FirstPostFormValue("password")
2015-01-15 14:01:01 -08:00
2015-02-20 23:33:35 -08:00
errData := authboss.NewHTMLData(
2015-03-31 15:27:47 -07:00
"error", fmt.Sprintf("invalid %s and/or password", a.PrimaryID),
"primaryID", a.PrimaryID,
2015-02-23 15:51:42 -08:00
"primaryIDValue", key,
2015-03-31 15:27:47 -07:00
"showRemember", a.IsLoaded("remember"),
"showRecover", a.IsLoaded("recover"),
2015-02-20 23:33:35 -08:00
)
2015-03-31 15:27:47 -07:00
policies := authboss.FilterValidators(a.Policies, a.PrimaryID, authboss.StorePassword)
2015-02-24 10:12:23 -08:00
if validationErrs := ctx.Validate(policies); len(validationErrs) > 0 {
2015-02-20 23:33:35 -08:00
return a.templates.Render(ctx, w, r, tplLogin, errData)
2015-01-15 14:01:01 -08:00
}
2015-01-12 21:08:52 -08:00
2015-02-22 13:16:11 -08:00
if err := validateCredentials(ctx, key, password); err != nil {
2015-02-20 23:33:35 -08:00
return a.templates.Render(ctx, w, r, tplLogin, errData)
2015-01-10 23:12:40 -08:00
}
2015-03-31 15:27:47 -07:00
interrupted, err := a.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."
}
2015-03-31 15:27:47 -07:00
response.Redirect(ctx, w, r, a.AuthLoginFailPath, "", reason, false)
return nil
}
ctx.SessionStorer.Put(authboss.SessionKey, key)
ctx.SessionStorer.Del(authboss.SessionHalfAuthKey)
2015-03-31 15:27:47 -07:00
if err := a.Callbacks.FireAfter(authboss.EventAuth, ctx); err != nil {
2015-02-25 23:20:02 -08:00
return err
}
2015-03-31 15:27:47 -07:00
response.Redirect(ctx, w, r, a.AuthLoginOKPath, "", "", true)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
2015-02-20 23:33:35 -08:00
return nil
}
2015-02-22 13:16:11 -08:00
func validateCredentials(ctx *authboss.Context, key, password string) error {
if err := ctx.LoadUser(key); err != nil {
2015-01-12 21:08:52 -08:00
return err
}
2015-02-22 13:16:11 -08:00
actualPassword, err := ctx.User.StringErr(authboss.StorePassword)
2015-02-20 23:33:35 -08:00
if err != nil {
return err
}
2015-02-20 23:33:35 -08:00
if err := bcrypt.CompareHashAndPassword([]byte(actualPassword), []byte(password)); err != nil {
return err
2015-01-10 22:49:06 -08:00
}
return nil
}
2015-02-23 15:51:42 -08:00
func (a *Auth) logoutHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
switch r.Method {
case methodGET:
ctx.SessionStorer.Del(authboss.SessionKey)
ctx.CookieStorer.Del(authboss.CookieRemember)
ctx.SessionStorer.Del(authboss.SessionLastAction)
2015-03-31 15:27:47 -07:00
response.Redirect(ctx, w, r, a.AuthLogoutOKPath, "You have logged out", "", true)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
2015-02-20 23:33:35 -08:00
return nil
}