package main import ( "encoding/base64" "net/http" "strings" "time" "unicode" "github.com/gin-gonic/gin" ) var LocalAuthFunc = checkAuthKrb5 var allowLocalAuth bool var localAuthUsers arrayFlags var mainBanner string type loginForm struct { Login string `json:"username"` Password string `json:"password"` } func declareAPIAuthRoutes(router *gin.RouterGroup) { router.GET("/auth", validateAuthToken) router.POST("/auth", func(c *gin.Context) { LocalAuthFunc(c) }) router.POST("/auth/logout", logout) } func declareAPIAdminAuthRoutes(router *gin.RouterGroup) { router.POST("/auth/impersonate", func(c *gin.Context) { session := c.MustGet("Session").(*Session) var u *User if err := c.ShouldBindJSON(&u); err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } newuser, err := getUser(int(u.Id)) if err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } session.IdUser = &newuser.Id session.Update() c.JSON(http.StatusOK, authToken{ User: newuser, CurrentPromo: currentPromo, MessageBanner: mainBanner, }) }) } type authToken struct { *User CurrentPromo uint `json:"current_promo"` Groups []string `json:"groups"` MessageBanner string `json:"banner,omitempty"` } func validateAuthToken(c *gin.Context) { if u, ok := c.Get("LoggedUser"); !ok || u.(*User) == nil { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": "Not connected"}) return } else { t := authToken{User: u.(*User), CurrentPromo: currentPromo, MessageBanner: mainBanner} t.Groups = strings.Split(strings.TrimFunc(t.User.Groups, func(r rune) bool { return !unicode.IsLetter(r) }), ",") c.JSON(http.StatusOK, t) } } func logout(c *gin.Context) { eraseCookie(c) c.JSON(http.StatusOK, true) } func completeAuth(c *gin.Context, username string, email string, firstname string, lastname string, promo uint, groups string, session *Session) (usr *User, err error) { if !userExists(username) { if promo == 0 { promo = currentPromo } if usr, err = NewUser(username, email, firstname, lastname, promo, groups); err != nil { return } } else if usr, err = getUserByLogin(username); err != nil { return } upd_user := false // Update user's promo if it has changed if promo != 0 && promo != usr.Promo { usr.Promo = promo upd_user = true } // Update user's group if they have been modified if len(groups) > 0 { if len(groups) > 255 { groups = groups[:255] } if usr.Groups != groups { usr.Groups = groups upd_user = true } } if upd_user { usr.Update() } if session == nil { session, err = usr.NewSession() } else { _, err = session.SetUser(usr) } if err != nil { return } http.SetCookie(c.Writer, &http.Cookie{ Name: "auth", Value: base64.StdEncoding.EncodeToString(session.Id), Path: baseURL + "/", Expires: time.Now().Add(30 * 24 * time.Hour), HttpOnly: true, SameSite: http.SameSiteStrictMode, Secure: true, }) return } func eraseCookie(c *gin.Context) { http.SetCookie(c.Writer, &http.Cookie{ Name: "auth", Value: "", Path: baseURL + "/", Expires: time.Unix(0, 0), HttpOnly: true, SameSite: http.SameSiteStrictMode, }) } func dummyAuth(c *gin.Context) { var lf map[string]string if err := c.ShouldBindJSON(&lf); err != nil { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()}) return } if usr, err := completeAuth(c, lf["username"], lf["email"], lf["firstname"], lf["lastname"], currentPromo, "", nil); err != nil { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": err.Error()}) return } else { c.JSON(http.StatusOK, authToken{User: usr, CurrentPromo: currentPromo, MessageBanner: mainBanner}) } }