123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- package sso
- /*
- handlers.go
- This file contains the handlers for the SSO module.
- If you are looking for handlers for SSO user management,
- please refer to userHandlers.go.
- */
- import (
- "encoding/json"
- "net/http"
- "strings"
- "github.com/gofrs/uuid"
- "imuslab.com/zoraxy/mod/utils"
- )
- // HandleSSOStatus handle the request to get the status of the SSO portal server
- func (s *SSOHandler) HandleSSOStatus(w http.ResponseWriter, r *http.Request) {
- type SSOStatus struct {
- Enabled bool
- SSOInterceptEnabled bool
- ListeningPort int
- AuthURL string
- }
- status := SSOStatus{
- Enabled: s.ssoPortalServer != nil,
- //SSOInterceptEnabled: s.ssoInterceptEnabled,
- ListeningPort: s.Config.PortalServerPort,
- AuthURL: s.Config.AuthURL,
- }
- js, _ := json.Marshal(status)
- utils.SendJSONResponse(w, string(js))
- }
- // Wrapper for starting and stopping the SSO portal server
- // require POST request with key "enable" and value "true" or "false"
- func (s *SSOHandler) HandleSSOEnable(w http.ResponseWriter, r *http.Request) {
- enable, err := utils.PostBool(r, "enable")
- if err != nil {
- utils.SendErrorResponse(w, "invalid enable value")
- return
- }
- if enable {
- s.HandleStartSSOPortal(w, r)
- } else {
- s.HandleStopSSOPortal(w, r)
- }
- }
- // HandleStartSSOPortal handle the request to start the SSO portal server
- func (s *SSOHandler) HandleStartSSOPortal(w http.ResponseWriter, r *http.Request) {
- if s.ssoPortalServer != nil {
- //Already enabled. Do restart instead.
- err := s.RestartSSOServer()
- if err != nil {
- utils.SendErrorResponse(w, "failed to start SSO server")
- return
- }
- utils.SendOK(w)
- return
- }
- //Check if the authURL is set correctly. If not, return error
- if s.Config.AuthURL == "" {
- utils.SendErrorResponse(w, "auth URL not set")
- return
- }
- //Start the SSO portal server in go routine
- go s.StartSSOPortal()
- //Write current state to database
- err := s.Config.Database.Write("sso_conf", "enabled", true)
- if err != nil {
- utils.SendErrorResponse(w, "failed to update SSO state")
- return
- }
- utils.SendOK(w)
- }
- // HandleStopSSOPortal handle the request to stop the SSO portal server
- func (s *SSOHandler) HandleStopSSOPortal(w http.ResponseWriter, r *http.Request) {
- if s.ssoPortalServer == nil {
- //Already disabled
- utils.SendOK(w)
- return
- }
- err := s.ssoPortalServer.Close()
- if err != nil {
- s.Log("Failed to stop SSO portal server", err)
- utils.SendErrorResponse(w, "failed to stop SSO portal server")
- return
- }
- s.ssoPortalServer = nil
- //Write current state to database
- err = s.Config.Database.Write("sso_conf", "enabled", false)
- if err != nil {
- utils.SendErrorResponse(w, "failed to update SSO state")
- return
- }
- utils.SendOK(w)
- }
- // HandlePortChange handle the request to change the SSO portal server port
- func (s *SSOHandler) HandlePortChange(w http.ResponseWriter, r *http.Request) {
- if r.Method == http.MethodGet {
- //Return the current port
- js, _ := json.Marshal(s.Config.PortalServerPort)
- utils.SendJSONResponse(w, string(js))
- return
- }
- port, err := utils.PostInt(r, "port")
- if err != nil {
- utils.SendErrorResponse(w, "invalid port given")
- return
- }
- s.Config.PortalServerPort = port
- //Write to the database
- err = s.Config.Database.Write("sso_conf", "port", port)
- if err != nil {
- utils.SendErrorResponse(w, "failed to update port")
- return
- }
- if s.IsRunning() {
- //Restart the server if it is running
- err = s.RestartSSOServer()
- if err != nil {
- utils.SendErrorResponse(w, "failed to restart SSO server")
- return
- }
- }
- utils.SendOK(w)
- }
- // HandleSetAuthURL handle the request to change the SSO auth URL
- // This is the URL that the SSO portal server will redirect to for authentication
- // e.g. auth.yourdomain.com
- func (s *SSOHandler) HandleSetAuthURL(w http.ResponseWriter, r *http.Request) {
- if r.Method == http.MethodGet {
- //Return the current auth URL
- js, _ := json.Marshal(s.Config.AuthURL)
- utils.SendJSONResponse(w, string(js))
- return
- }
- //Get the auth URL
- authURL, err := utils.PostPara(r, "auth_url")
- if err != nil {
- utils.SendErrorResponse(w, "invalid auth URL given")
- return
- }
- s.Config.AuthURL = authURL
- //Write to the database
- err = s.Config.Database.Write("sso_conf", "authurl", authURL)
- if err != nil {
- utils.SendErrorResponse(w, "failed to update auth URL")
- return
- }
- //Clear the cookie store and restart the server
- err = s.RestartSSOServer()
- if err != nil {
- utils.SendErrorResponse(w, "failed to restart SSO server")
- return
- }
- utils.SendOK(w)
- }
- // HandleRegisterApp handle the request to register a new app to the SSO portal
- func (s *SSOHandler) HandleRegisterApp(w http.ResponseWriter, r *http.Request) {
- appName, err := utils.PostPara(r, "app_name")
- if err != nil {
- utils.SendErrorResponse(w, "invalid app name given")
- return
- }
- id, err := utils.PostPara(r, "app_id")
- if err != nil {
- //If id is not given, use the app name with a random UUID
- newID, err := uuid.NewV4()
- if err != nil {
- utils.SendErrorResponse(w, "failed to generate new app ID")
- return
- }
- id = strings.ReplaceAll(appName, " ", "") + "-" + newID.String()
- }
- //Check if the given appid is already in use
- if _, ok := s.Apps[id]; ok {
- utils.SendErrorResponse(w, "app ID already in use")
- return
- }
- /*
- Process the app domain
- An app can have multiple domains, separated by commas
- Usually the app domain is the proxy rule that points to the app
- For example, if the app is hosted at app.yourdomain.com, the app domain is app.yourdomain.com
- */
- appDomain, err := utils.PostPara(r, "app_domain")
- if err != nil {
- utils.SendErrorResponse(w, "invalid app URL given")
- return
- }
- appURLs := strings.Split(appDomain, ",")
- //Remove padding and trailing spaces in each URL
- for i := range appURLs {
- appURLs[i] = strings.TrimSpace(appURLs[i])
- }
- //Create a new app entry
- thisAppEntry := RegisteredUpstreamApp{
- ID: id,
- Secret: "",
- Domain: appURLs,
- Scopes: []string{},
- SessionDuration: 3600,
- }
- js, _ := json.Marshal(thisAppEntry)
- //Create a new app in the database
- err = s.Config.Database.Write("sso_apps", appName, string(js))
- if err != nil {
- utils.SendErrorResponse(w, "failed to create new app")
- return
- }
- //Also add the app to runtime config
- s.Apps[appName] = thisAppEntry
- utils.SendOK(w)
- }
- // HandleAppRemove handle the request to remove an app from the SSO portal
- func (s *SSOHandler) HandleAppRemove(w http.ResponseWriter, r *http.Request) {
- appID, err := utils.PostPara(r, "app_id")
- if err != nil {
- utils.SendErrorResponse(w, "invalid app ID given")
- return
- }
- //Check if the app actually exists
- if _, ok := s.Apps[appID]; !ok {
- utils.SendErrorResponse(w, "app not found")
- return
- }
- delete(s.Apps, appID)
- //Also remove it from the database
- err = s.Config.Database.Delete("sso_apps", appID)
- if err != nil {
- s.Log("Failed to remove app from database", err)
- }
- }
|