sso.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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. // RegisteredUpstreamApp is a structure that contains the information of an
  26. // upstream app that is registered with the SSO server
  27. type RegisteredUpstreamApp struct {
  28. ID string
  29. Secret string
  30. Domain []string
  31. Scopes []string
  32. SessionDuration int //in seconds, default to 1 hour
  33. }
  34. // SSOHandler is the main SSO handler structure
  35. type SSOHandler struct {
  36. cookieStore *sessions.CookieStore
  37. ssoPortalServer *http.Server
  38. ssoPortalMux *http.ServeMux
  39. Oauth2Server *OAuth2Server
  40. Config *SSOConfig
  41. Apps map[string]RegisteredUpstreamApp
  42. }
  43. // Create a new Zoraxy SSO handler
  44. func NewSSOHandler(config *SSOConfig) (*SSOHandler, error) {
  45. //Create a cookie store for the SSO handler
  46. cookieStore := sessions.NewCookieStore([]byte(config.SystemUUID))
  47. cookieStore.Options = &sessions.Options{
  48. Path: "",
  49. Domain: "",
  50. MaxAge: 0,
  51. Secure: false,
  52. HttpOnly: false,
  53. SameSite: 0,
  54. }
  55. //Create a table for the new sso user management system
  56. err := config.Database.NewTable("sso_users")
  57. if err != nil {
  58. return nil, err
  59. }
  60. //Create the SSO Handler
  61. thisHandler := SSOHandler{
  62. cookieStore: cookieStore,
  63. Config: config,
  64. }
  65. //Create an oauth2 server
  66. oauth2Server, err := NewOAuth2Server(config, &thisHandler)
  67. if err != nil {
  68. return nil, err
  69. }
  70. //Register endpoints
  71. thisHandler.Oauth2Server = oauth2Server
  72. thisHandler.InitSSOPortal(config.PortalServerPort)
  73. return &thisHandler, nil
  74. }
  75. // ServeForwardAuth handle the SSO request by forwarding auth to the authelia server
  76. // return false if the request is not authorized and shall not be proceed
  77. // Note that only accounts that have SSO enabled will be handled by this handler
  78. func (h *SSOHandler) ServeForwardAuth(w http.ResponseWriter, r *http.Request) bool {
  79. //Get the current uri for appending to the auth subdomain
  80. originalRequestURL := r.RequestURI
  81. //Check if the user have the cookie "Zoraxy-SSO" set
  82. session, err := h.cookieStore.Get(r, "Zoraxy-SSO")
  83. if err != nil {
  84. //Redirect to auth subdomain
  85. http.Redirect(w, r, h.Config.AuthURL+"?m=new&t="+originalRequestURL, http.StatusFound)
  86. return false
  87. }
  88. //Check if the user is logged in
  89. if session.Values["username"] != true {
  90. //Redirect to auth subdomain
  91. http.Redirect(w, r, h.Config.AuthURL+"?m=expired&t="+originalRequestURL, http.StatusFound)
  92. return false
  93. }
  94. //Check if the current request subdomain is allowed
  95. userName := session.Values["username"].(string)
  96. user, err := h.SSO_GetUser(userName)
  97. if err != nil {
  98. //User might have been removed from SSO. Redirect to auth subdomain
  99. http.Redirect(w, r, h.Config.AuthURL, http.StatusFound)
  100. return false
  101. }
  102. //Check if the user have access to the current subdomain
  103. if !user.Subdomains[r.Host].AllowAccess {
  104. //User is not allowed to access the current subdomain. Sent 403
  105. http.Error(w, "Forbidden", http.StatusForbidden)
  106. //TODO: Use better looking template if exists
  107. return false
  108. }
  109. //User is logged in, continue to the next handler
  110. return true
  111. }
  112. // Log a message with the SSO module tag
  113. func (h *SSOHandler) Log(message string, err error) {
  114. h.Config.Logger.PrintAndLog("SSO", message, err)
  115. }