package server import ( "net/http" "strings" "github.com/pkg/errors" "github.com/gin-gonic/gin" "github.com/h44z/wg-portal/internal/authentication" "github.com/h44z/wg-portal/internal/users" "github.com/sirupsen/logrus" csrf "github.com/utrack/gin-csrf" ) func (s *Server) GetLogin(c *gin.Context) { currentSession := GetSessionData(c) if currentSession.LoggedIn { c.Redirect(http.StatusSeeOther, "/") // already logged in } authError := c.DefaultQuery("err", "") errMsg := "Unknown error occurred, try again!" switch authError { case "missingdata": errMsg = "Invalid login data retrieved, please fill out all fields and try again!" case "authfail": errMsg = "Authentication failed!" case "loginreq": errMsg = "Login required!" } c.HTML(http.StatusOK, "login.html", gin.H{ "error": authError != "", "message": errMsg, "static": s.getStaticData(), "Csrf": csrf.GetToken(c), }) } func (s *Server) PostLogin(c *gin.Context) { currentSession := GetSessionData(c) if currentSession.LoggedIn { // already logged in c.Redirect(http.StatusSeeOther, "/") return } username := strings.ToLower(c.PostForm("username")) password := c.PostForm("password") // Validate form input if strings.Trim(username, " ") == "" || strings.Trim(password, " ") == "" { c.Redirect(http.StatusSeeOther, "/auth/login?err=missingdata") return } // Check all available auth backends user, err := s.checkAuthentication(username, password) if err != nil { s.GetHandleError(c, http.StatusInternalServerError, "login error", err.Error()) return } // Check if user is authenticated if user == nil { c.Redirect(http.StatusSeeOther, "/auth/login?err=authfail") return } // Set authenticated session sessionData := GetSessionData(c) sessionData.LoggedIn = true sessionData.IsAdmin = user.IsAdmin sessionData.Email = user.Email sessionData.Firstname = user.Firstname sessionData.Lastname = user.Lastname sessionData.DeviceName = s.wg.Cfg.DeviceNames[0] // Check if user already has a peer setup, if not create one if err := s.CreateUserDefaultPeer(user.Email, s.wg.Cfg.GetDefaultDeviceName()); err != nil { // Not a fatal error, just log it... logrus.Errorf("failed to automatically create vpn peer for %s: %v", sessionData.Email, err) } if err := UpdateSessionData(c, sessionData); err != nil { s.GetHandleError(c, http.StatusInternalServerError, "login error", "failed to save session") return } c.Redirect(http.StatusSeeOther, "/") } func (s *Server) GetLogout(c *gin.Context) { currentSession := GetSessionData(c) if !currentSession.LoggedIn { // Not logged in c.Redirect(http.StatusSeeOther, "/") return } if err := DestroySessionData(c); err != nil { s.GetHandleError(c, http.StatusInternalServerError, "logout error", "failed to destroy session") return } c.Redirect(http.StatusSeeOther, "/") } func (s *Server) checkAuthentication(username, password string) (*users.User, error) { var user *users.User // Check all available auth backends for _, provider := range s.auth.GetProvidersForType(authentication.AuthProviderTypePassword) { // try to log in to the given provider authEmail, err := provider.Login(&authentication.AuthContext{ Username: username, Password: password, }) if err != nil { continue } // Login succeeded user = s.users.GetUser(authEmail) if user != nil { break // user exists, nothing more to do... } // create new user in the database (or reactivate him) userData, err := provider.GetUserModel(&authentication.AuthContext{ Username: username, }) if err != nil { return nil, errors.Wrap(err, "failed to get user model") } if err := s.CreateUser(users.User{ Email: userData.Email, Source: users.UserSource(provider.GetName()), IsAdmin: userData.IsAdmin, Firstname: userData.Firstname, Lastname: userData.Lastname, Phone: userData.Phone, }, s.wg.Cfg.GetDefaultDeviceName()); err != nil { return nil, errors.Wrap(err, "failed to update user data") } user = s.users.GetUser(authEmail) break } return user, nil }