123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- 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
- }
|