package auth import ( "encoding/base64" "net/http" "time" "github.com/gin-gonic/gin" "github.com/rs/zerolog/log" "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) } // log.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 { log.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 { log.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}) }