package sso /* userHandlers.go Handlers for SSO user management If you are looking for handlers that changes the settings of the SSO portal (e.g. authURL or port), please refer to handlers.go. */ import ( "encoding/json" "errors" "net/http" "github.com/gofrs/uuid" "imuslab.com/zoraxy/mod/auth" "imuslab.com/zoraxy/mod/utils" ) // HandleAddUser handle the request to add a new user to the SSO system func (s *SSOHandler) HandleAddUser(w http.ResponseWriter, r *http.Request) { username, err := utils.PostPara(r, "username") if err != nil { utils.SendErrorResponse(w, "invalid username given") return } password, err := utils.PostPara(r, "password") if err != nil { utils.SendErrorResponse(w, "invalid password given") return } newUserId, err := uuid.NewV4() if err != nil { utils.SendErrorResponse(w, "failed to generate new user ID") return } //Create a new user entry thisUserEntry := UserEntry{ UserID: newUserId.String(), Username: username, PasswordHash: auth.Hash(password), TOTPCode: "", Enable2FA: false, } js, _ := json.Marshal(thisUserEntry) //Create a new user in the database err = s.Config.Database.Write("sso_users", newUserId.String(), string(js)) if err != nil { utils.SendErrorResponse(w, "failed to create new user") return } utils.SendOK(w) } // Edit user information, only accept change of username, password and enabled subdomain filed func (s *SSOHandler) HandleEditUser(w http.ResponseWriter, r *http.Request) { userID, err := utils.PostPara(r, "user_id") if err != nil { utils.SendErrorResponse(w, "invalid user ID given") return } if !(s.SSOUserExists(userID)) { utils.SendErrorResponse(w, "user not found") return } //Load the user entry from database userEntry, err := s.GetSSOUser(userID) if err != nil { utils.SendErrorResponse(w, "failed to load user entry") return } //Update each of the fields if it is provided username, err := utils.PostPara(r, "username") if err == nil { userEntry.Username = username } password, err := utils.PostPara(r, "password") if err == nil { userEntry.PasswordHash = auth.Hash(password) } //Update the user entry in the database js, _ := json.Marshal(userEntry) err = s.Config.Database.Write("sso_users", userID, string(js)) if err != nil { utils.SendErrorResponse(w, "failed to update user entry") return } utils.SendOK(w) } // HandleRemoveUser remove a user from the SSO system func (s *SSOHandler) HandleRemoveUser(w http.ResponseWriter, r *http.Request) { userID, err := utils.PostPara(r, "user_id") if err != nil { utils.SendErrorResponse(w, "invalid user ID given") return } if !(s.SSOUserExists(userID)) { utils.SendErrorResponse(w, "user not found") return } //Remove the user from the database err = s.Config.Database.Delete("sso_users", userID) if err != nil { utils.SendErrorResponse(w, "failed to remove user") return } utils.SendOK(w) } // HandleListUser list all users in the SSO system func (s *SSOHandler) HandleListUser(w http.ResponseWriter, r *http.Request) { ssoUsers, err := s.ListSSOUsers() if err != nil { utils.SendErrorResponse(w, "failed to list users") return } js, _ := json.Marshal(ssoUsers) utils.SendJSONResponse(w, string(js)) } // HandleAddSubdomain add a subdomain to a user func (s *SSOHandler) HandleAddSubdomain(w http.ResponseWriter, r *http.Request) { userid, err := utils.PostPara(r, "user_id") if err != nil { utils.SendErrorResponse(w, "invalid user ID given") return } if !(s.SSOUserExists(userid)) { utils.SendErrorResponse(w, "user not found") return } UserEntry, err := s.GetSSOUser(userid) if err != nil { utils.SendErrorResponse(w, "failed to load user entry") return } subdomain, err := utils.PostPara(r, "subdomain") if err != nil { utils.SendErrorResponse(w, "invalid subdomain given") return } allowAccess, err := utils.PostBool(r, "allow_access") if err != nil { utils.SendErrorResponse(w, "invalid allow access value given") return } UserEntry.Subdomains[subdomain] = &SubdomainAccessRule{ Subdomain: subdomain, AllowAccess: allowAccess, } err = UserEntry.Update() if err != nil { utils.SendErrorResponse(w, "failed to update user entry") return } utils.SendOK(w) } // HandleRemoveSubdomain remove a subdomain from a user func (s *SSOHandler) HandleRemoveSubdomain(w http.ResponseWriter, r *http.Request) { userid, err := utils.PostPara(r, "user_id") if err != nil { utils.SendErrorResponse(w, "invalid user ID given") return } if !(s.SSOUserExists(userid)) { utils.SendErrorResponse(w, "user not found") return } UserEntry, err := s.GetSSOUser(userid) if err != nil { utils.SendErrorResponse(w, "failed to load user entry") return } subdomain, err := utils.PostPara(r, "subdomain") if err != nil { utils.SendErrorResponse(w, "invalid subdomain given") return } delete(UserEntry.Subdomains, subdomain) err = UserEntry.Update() if err != nil { utils.SendErrorResponse(w, "failed to update user entry") return } utils.SendOK(w) } // HandleEnable2FA enable 2FA for a user func (s *SSOHandler) HandleEnable2FA(w http.ResponseWriter, r *http.Request) { userid, err := utils.PostPara(r, "user_id") if err != nil { utils.SendErrorResponse(w, "invalid user ID given") return } if !(s.SSOUserExists(userid)) { utils.SendErrorResponse(w, "user not found") return } UserEntry, err := s.GetSSOUser(userid) if err != nil { utils.SendErrorResponse(w, "failed to load user entry") return } UserEntry.Enable2FA = true provisionUri, err := UserEntry.ResetTotp(UserEntry.UserID, "Zoraxy-SSO") if err != nil { utils.SendErrorResponse(w, "failed to reset TOTP") return } //As the ResetTotp function will update the user entry in the database, no need to call Update here js, _ := json.Marshal(provisionUri) utils.SendJSONResponse(w, string(js)) } // Handle Disable 2FA for a user func (s *SSOHandler) HandleDisable2FA(w http.ResponseWriter, r *http.Request) { userid, err := utils.PostPara(r, "user_id") if err != nil { utils.SendErrorResponse(w, "invalid user ID given") return } if !(s.SSOUserExists(userid)) { utils.SendErrorResponse(w, "user not found") return } UserEntry, err := s.GetSSOUser(userid) if err != nil { utils.SendErrorResponse(w, "failed to load user entry") return } UserEntry.Enable2FA = false UserEntry.TOTPCode = "" err = UserEntry.Update() if err != nil { utils.SendErrorResponse(w, "failed to update user entry") return } utils.SendOK(w) } // HandleVerify2FA verify the 2FA code for a user func (s *SSOHandler) HandleVerify2FA(w http.ResponseWriter, r *http.Request) (bool, error) { userid, err := utils.PostPara(r, "user_id") if err != nil { return false, errors.New("invalid user ID given") } if !(s.SSOUserExists(userid)) { utils.SendErrorResponse(w, "user not found") return false, errors.New("user not found") } UserEntry, err := s.GetSSOUser(userid) if err != nil { utils.SendErrorResponse(w, "failed to load user entry") return false, errors.New("failed to load user entry") } totpCode, _ := utils.PostPara(r, "totp_code") if !UserEntry.Enable2FA { //If 2FA is not enabled, return true return true, nil } if !UserEntry.VerifyTotp(totpCode) { return false, nil } return true, nil }