1
0

sso.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package sso
  2. import (
  3. "embed"
  4. "net/http"
  5. "github.com/gorilla/sessions"
  6. "imuslab.com/zoraxy/mod/database"
  7. "imuslab.com/zoraxy/mod/info/logger"
  8. )
  9. /*
  10. sso.go
  11. This file contains the main SSO handler and the SSO configuration
  12. structure. It also contains the main SSO handler functions.
  13. SSO web interface are stored in the static folder, which is embedded
  14. into the binary.
  15. */
  16. //go:embed static/*
  17. var staticFiles embed.FS //Static files for the SSO portal
  18. type SSOConfig struct {
  19. SystemUUID string //System UUID, should be passed in from main scope
  20. AuthURL string //Authentication subdomain URL, e.g. auth.example.com
  21. PortalServerPort int //SSO portal server port
  22. Database *database.Database //System master key-value database
  23. Logger *logger.Logger
  24. }
  25. // SSOHandler is the main SSO handler structure
  26. type SSOHandler struct {
  27. cookieStore *sessions.CookieStore
  28. ssoPortalServer *http.Server
  29. ssoPortalMux *http.ServeMux
  30. Oauth2Server *OAuth2Server
  31. Config *SSOConfig
  32. Apps map[string]RegisteredUpstreamApp
  33. }
  34. // Create a new Zoraxy SSO handler
  35. func NewSSOHandler(config *SSOConfig) (*SSOHandler, error) {
  36. //Create a cookie store for the SSO handler
  37. cookieStore := sessions.NewCookieStore([]byte(config.SystemUUID))
  38. cookieStore.Options = &sessions.Options{
  39. Path: "",
  40. Domain: "",
  41. MaxAge: 0,
  42. Secure: false,
  43. HttpOnly: false,
  44. SameSite: 0,
  45. }
  46. //Create a table for the new sso user management system
  47. err := config.Database.NewTable("sso_users")
  48. if err != nil {
  49. return nil, err
  50. }
  51. //Create the SSO Handler
  52. thisHandler := SSOHandler{
  53. cookieStore: cookieStore,
  54. Config: config,
  55. }
  56. //Create an oauth2 server
  57. oauth2Server, err := NewOAuth2Server(config, &thisHandler)
  58. if err != nil {
  59. return nil, err
  60. }
  61. //Register endpoints
  62. thisHandler.Oauth2Server = oauth2Server
  63. thisHandler.InitSSOPortal(config.PortalServerPort)
  64. return &thisHandler, nil
  65. }
  66. func (h *SSOHandler) RestorePreviousRunningState() {
  67. ssoEnabled := false
  68. ssoPort := 5488
  69. ssoAuthURL := ""
  70. h.Config.Database.Read("sso_conf", "enabled", &ssoEnabled)
  71. h.Config.Database.Read("sso_conf", "port", &ssoPort)
  72. h.Config.Database.Read("sso_conf", "authurl", &ssoAuthURL)
  73. if ssoAuthURL == "" {
  74. //Cannot enable SSO without auth URL
  75. ssoEnabled = false
  76. }
  77. h.Config.PortalServerPort = ssoPort
  78. h.Config.AuthURL = ssoAuthURL
  79. if ssoEnabled {
  80. go h.StartSSOPortal()
  81. }
  82. }
  83. // ServeForwardAuth handle the SSO request by forwarding auth to the authelia server
  84. // return false if the request is not authorized and shall not be proceed
  85. // Note that only accounts that have SSO enabled will be handled by this handler
  86. func (h *SSOHandler) ServeForwardAuth(w http.ResponseWriter, r *http.Request) bool {
  87. //Get the current uri for appending to the auth subdomain
  88. originalRequestURL := r.RequestURI
  89. //Check if the user have the cookie "Zoraxy-SSO" set
  90. session, err := h.cookieStore.Get(r, "Zoraxy-SSO")
  91. if err != nil {
  92. //Redirect to auth subdomain
  93. http.Redirect(w, r, h.Config.AuthURL+"?m=new&t="+originalRequestURL, http.StatusFound)
  94. return false
  95. }
  96. //Check if the user is logged in
  97. if session.Values["username"] != true {
  98. //Redirect to auth subdomain
  99. http.Redirect(w, r, h.Config.AuthURL+"?m=expired&t="+originalRequestURL, http.StatusFound)
  100. return false
  101. }
  102. //Check if the current request subdomain is allowed
  103. userName := session.Values["username"].(string)
  104. user, err := h.SSO_GetUser(userName)
  105. if err != nil {
  106. //User might have been removed from SSO. Redirect to auth subdomain
  107. http.Redirect(w, r, h.Config.AuthURL, http.StatusFound)
  108. return false
  109. }
  110. //Check if the user have access to the current subdomain
  111. if !user.Subdomains[r.Host].AllowAccess {
  112. //User is not allowed to access the current subdomain. Sent 403
  113. http.Error(w, "Forbidden", http.StatusForbidden)
  114. //TODO: Use better looking template if exists
  115. return false
  116. }
  117. //User is logged in, continue to the next handler
  118. return true
  119. }
  120. // Log a message with the SSO module tag
  121. func (h *SSOHandler) Log(message string, err error) {
  122. h.Config.Logger.PrintAndLog("SSO", message, err)
  123. }