app/auth/api_auth.go

116 lines
2.6 KiB
Go

package auth
import (
"encoding/base64"
"net/http"
"time"
"github.com/gin-gonic/gin"
"kumoly.io/kumoly/app/errors"
"kumoly.io/kumoly/app/history"
"kumoly.io/kumoly/app/server"
)
type apiLoginReq struct {
Name string `json:"username" example:"user" binding:"required"`
// Email string `json:"email" example:"user@example.com" binding:"required,email"`
PwdB64 string `json:"password" example:"YWRtaW4=" binding:"required,base64"`
}
func ApiLogin(c *gin.Context) {
var data apiLoginReq
if err := c.ShouldBindJSON(&data); err != nil {
panic(err)
}
pwd, err := base64.URLEncoding.DecodeString(data.PwdB64)
if err != nil {
panic(err)
}
// l.Trace().Str("mod", "auth").
// Str("username", data.Name).Str("password", string(pwd)).
// Msg("user login")
usr := &User{}
// system developer login
if data.Name == sys_user && string(pwd) == sys_pwd {
usr = GetSysUser()
err = SetClaims(c, &Claims{
Uid: usr.ID,
User: usr.Username,
Groups: []string{SYSTEM},
})
if err != nil {
panic(err)
}
server.OK(c, usr)
return
}
err = DB.Preload("Profile").Preload("Groups").Where("username = ?", data.Name).First(usr).Error
if err != nil {
panic(ErrorLoginFailed)
}
err = usr.ValidatePassword(string(pwd))
if err != nil {
l.Error().Str("mod", "auth").Err(err).Msg("wrong password")
usr.LoginFailed += 1
DB.Model(&usr).Update("login_failed", usr.LoginFailed)
panic(ErrorLoginFailed)
}
if usr.SSOEnabled {
panic(ErrorUserIsSSO)
}
if !usr.Activated {
l.Error().Str("mod", "auth").
Err(ErrorUserNotActivated).
Str("user", usr.Username).Str("uid", usr.ID).
Msg("not activated")
panic(ErrorUserNotActivated)
}
grps := make([]string, len(usr.Groups))
for i, g := range usr.Groups {
grps[i] = g.Name
}
err = SetClaims(c, &Claims{
Uid: usr.ID,
User: usr.Username,
Groups: grps,
})
if err != nil {
panic(err)
}
usr.LastLogin = time.Now()
usr.LastLoginIP = c.ClientIP()
usr.LoginFailed = 0
DB.Model(&usr).Updates(map[string]interface{}{
"last_login": usr.LastLogin,
"login_failed": usr.LoginFailed,
"last_login_ip": usr.LastLoginIP,
})
// send to history
history.Send(history.Info().Iss(usr.Username).Nm("Login").
Msgf("user login from %v", usr.LastLoginIP).
Bd(usr.LastLoginIP))
server.Res(c, &server.Response{
Status: 200,
Data: usr,
})
}
func ApiLogout(c *gin.Context) {
ClearToken(c)
server.Res(c, &server.Response{Data: "ok"})
}
func ApiMe(c *gin.Context) {
usr, err := GetUser(c)
if err != nil {
ClearToken(c)
panic(errors.NewError(http.StatusUnauthorized, err))
}
server.Res(c, &server.Response{Data: usr})
}