mirror of https://github.com/shunfei/cronsun
201 lines
4.9 KiB
Go
201 lines
4.9 KiB
Go
package web
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
"github.com/shunfei/cronsun"
|
|
"github.com/shunfei/cronsun/conf"
|
|
"github.com/shunfei/cronsun/log"
|
|
"github.com/shunfei/cronsun/utils"
|
|
"gopkg.in/mgo.v2"
|
|
"gopkg.in/mgo.v2/bson"
|
|
)
|
|
|
|
func checkAuthBasicData() error {
|
|
if conf.Config.Web.Auth.Enabled {
|
|
log.Infof("Authentication enabled.")
|
|
|
|
list, err := cronsun.GetAccounts(bson.M{"role": cronsun.Administrator, "status": cronsun.UserActived})
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to check available Administrators: %s.", err.Error())
|
|
}
|
|
|
|
if len(list) == 0 {
|
|
// create a default administrator with admin@admin.com/admin
|
|
// the email and password can be change from the user profile page.
|
|
salt := genSalt()
|
|
err = cronsun.CreateAccount(&cronsun.Account{
|
|
Role: cronsun.Administrator,
|
|
Email: "admin@admin.com",
|
|
Salt: salt,
|
|
Password: encryptPassword("admin", salt),
|
|
Status: cronsun.UserActived,
|
|
Unchangeable: true,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("Failed to create default Administrators: %s.", err.Error())
|
|
}
|
|
}
|
|
|
|
if err = cronsun.EnsureAccountIndex(); err != nil {
|
|
log.Warnf("Failed to make db index on the `user` collection: %s.", err.Error())
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func encryptPassword(pwd, salt string) string {
|
|
m := md5.Sum([]byte(pwd + salt))
|
|
m = md5.Sum(m[:])
|
|
return hex.EncodeToString(m[:])
|
|
}
|
|
|
|
func genSalt() string {
|
|
return utils.RandString(8)
|
|
}
|
|
|
|
type Authentication struct{}
|
|
|
|
func (this *Authentication) GetAuthSession(ctx *Context) {
|
|
var authInfo = &struct {
|
|
Role cronsun.Role `json:"role,omitempty"`
|
|
Email string `json:"email,omitempty"`
|
|
EnabledAuth bool `json:"enabledAuth"`
|
|
}{}
|
|
|
|
if !conf.Config.Web.Auth.Enabled {
|
|
outJSONWithCode(ctx.W, http.StatusOK, authInfo)
|
|
return
|
|
}
|
|
|
|
authInfo.EnabledAuth = true
|
|
|
|
if ctx.Session.Email != "" {
|
|
authInfo.Email = ctx.Session.Email
|
|
authInfo.Role = ctx.Session.Data["role"].(cronsun.Role)
|
|
outJSONWithCode(ctx.W, http.StatusOK, authInfo)
|
|
return
|
|
}
|
|
|
|
if len(getStringVal("check", ctx.R)) > 0 {
|
|
outJSONWithCode(ctx.W, http.StatusUnauthorized, nil)
|
|
return
|
|
}
|
|
|
|
email := getStringVal("email", ctx.R)
|
|
password := getStringVal("password", ctx.R)
|
|
remember := getStringVal("remember", ctx.R) == "on"
|
|
|
|
u, err := cronsun.GetAccountByEmail(email)
|
|
if err != nil {
|
|
if err == mgo.ErrNotFound {
|
|
outJSONWithCode(ctx.W, http.StatusNotFound, "User ["+email+"] not found.")
|
|
} else {
|
|
outJSONWithCode(ctx.W, http.StatusInternalServerError, err.Error())
|
|
}
|
|
return
|
|
}
|
|
|
|
if u.Password != encryptPassword(password, u.Salt) {
|
|
outJSONWithCode(ctx.W, http.StatusBadRequest, "Incorrect password.")
|
|
return
|
|
}
|
|
|
|
if u.Status != cronsun.UserActived {
|
|
outJSONWithCode(ctx.W, http.StatusForbidden, "Access deny.")
|
|
return
|
|
}
|
|
|
|
if !remember {
|
|
if c, err := ctx.R.Cookie(conf.Config.Web.Session.CookieName); err == nil {
|
|
c.MaxAge = 0
|
|
c.Path = "/"
|
|
http.SetCookie(ctx.W, c)
|
|
}
|
|
}
|
|
|
|
ctx.Session.Email = u.Email
|
|
ctx.Session.Data["role"] = u.Role
|
|
ctx.Session.Store()
|
|
|
|
authInfo.Role = u.Role
|
|
authInfo.Email = u.Email
|
|
|
|
err = cronsun.UpdateAccount(bson.M{"email": email}, bson.M{"session": ctx.Session.ID()})
|
|
outJSONWithCode(ctx.W, http.StatusOK, authInfo)
|
|
}
|
|
|
|
func (this *Authentication) DeleteAuthSession(ctx *Context) {
|
|
ctx.Session.Email = ""
|
|
delete(ctx.Session.Data, "role")
|
|
ctx.Session.Store()
|
|
|
|
outJSONWithCode(ctx.W, http.StatusOK, nil)
|
|
}
|
|
|
|
func (this *Authentication) SetPassword(ctx *Context) {
|
|
var sp = &struct {
|
|
Password string `json:"password"`
|
|
NewPassword string `json:"newPassword"`
|
|
}{}
|
|
|
|
decoder := json.NewDecoder(ctx.R.Body)
|
|
err := decoder.Decode(&sp)
|
|
if err != nil {
|
|
outJSONWithCode(ctx.W, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
ctx.R.Body.Close()
|
|
|
|
sp.Password = strings.TrimSpace(sp.Password)
|
|
sp.NewPassword = strings.TrimSpace(sp.NewPassword)
|
|
if sp.Password == "" {
|
|
outJSONWithCode(ctx.W, http.StatusBadRequest, "Passowrd is required.")
|
|
return
|
|
}
|
|
if sp.NewPassword == "" {
|
|
outJSONWithCode(ctx.W, http.StatusBadRequest, "New passowrd is required.")
|
|
return
|
|
}
|
|
|
|
var email = ctx.Session.Email
|
|
u, err := cronsun.GetAccountByEmail(email)
|
|
if err != nil {
|
|
if err == mgo.ErrNotFound {
|
|
outJSONWithCode(ctx.W, http.StatusNotFound, "User ["+email+"] not found.")
|
|
} else {
|
|
outJSONWithCode(ctx.W, http.StatusInternalServerError, err.Error())
|
|
}
|
|
return
|
|
}
|
|
|
|
if u.Password != encryptPassword(sp.Password, u.Salt) {
|
|
outJSONWithCode(ctx.W, http.StatusBadRequest, "Incorrect password.")
|
|
return
|
|
}
|
|
|
|
salt := genSalt()
|
|
update := bson.M{
|
|
"salt": salt,
|
|
"password": encryptPassword(sp.NewPassword, salt),
|
|
}
|
|
|
|
if err = cronsun.UpdateAccount(bson.M{"email": email}, update); err != nil {
|
|
if err == mgo.ErrNotFound {
|
|
outJSONWithCode(ctx.W, http.StatusBadRequest, "User ["+email+"] not found.")
|
|
} else {
|
|
outJSONWithCode(ctx.W, http.StatusInternalServerError, err.Error())
|
|
}
|
|
return
|
|
}
|
|
|
|
outJSONWithCode(ctx.W, http.StatusOK, nil)
|
|
}
|