authProviders.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package dynamicproxy
  2. import (
  3. "errors"
  4. "net/http"
  5. "strings"
  6. "imuslab.com/zoraxy/mod/auth"
  7. )
  8. /*
  9. authProviders.go
  10. This script handle authentication providers
  11. */
  12. /*
  13. Central Authentication Provider Router
  14. This function will route the request to the correct authentication provider
  15. if the return value is true, do not continue to the next handler
  16. handleAuthProviderRouting takes in 4 parameters:
  17. - sep: the ProxyEndpoint object
  18. - w: the http.ResponseWriter object
  19. - r: the http.Request object
  20. - h: the ProxyHandler object
  21. and return a boolean indicate if the request is written to http.ResponseWriter
  22. - true: the request is handled, do not write to http.ResponseWriter
  23. - false: the request is not handled (usually means auth ok), continue to the next handler
  24. */
  25. func handleAuthProviderRouting(sep *ProxyEndpoint, w http.ResponseWriter, r *http.Request, h *ProxyHandler) bool {
  26. if sep.AuthenticationProvider.AuthMethod == AuthMethodBasic {
  27. err := h.handleBasicAuthRouting(w, r, sep)
  28. if err != nil {
  29. h.Parent.Option.Logger.LogHTTPRequest(r, "host", 401)
  30. return true
  31. }
  32. } else if sep.AuthenticationProvider.AuthMethod == AuthMethodAuthelia {
  33. err := h.handleAutheliaAuth(w, r)
  34. if err != nil {
  35. h.Parent.Option.Logger.LogHTTPRequest(r, "host", 401)
  36. return true
  37. }
  38. }
  39. //No authentication provider, do not need to handle
  40. return false
  41. }
  42. /* Basic Auth */
  43. func (h *ProxyHandler) handleBasicAuthRouting(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
  44. err := handleBasicAuth(w, r, pe)
  45. if err != nil {
  46. h.Parent.logRequest(r, false, 401, "host", r.URL.Hostname())
  47. }
  48. return err
  49. }
  50. // Handle basic auth logic
  51. // do not write to http.ResponseWriter if err return is not nil (already handled by this function)
  52. func handleBasicAuth(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint) error {
  53. if len(pe.AuthenticationProvider.BasicAuthExceptionRules) > 0 {
  54. //Check if the current path matches the exception rules
  55. for _, exceptionRule := range pe.AuthenticationProvider.BasicAuthExceptionRules {
  56. if strings.HasPrefix(r.RequestURI, exceptionRule.PathPrefix) {
  57. //This path is excluded from basic auth
  58. return nil
  59. }
  60. }
  61. }
  62. u, p, ok := r.BasicAuth()
  63. if !ok {
  64. w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
  65. w.WriteHeader(401)
  66. return errors.New("unauthorized")
  67. }
  68. //Check for the credentials to see if there is one matching
  69. hashedPassword := auth.Hash(p)
  70. matchingFound := false
  71. for _, cred := range pe.AuthenticationProvider.BasicAuthCredentials {
  72. if u == cred.Username && hashedPassword == cred.PasswordHash {
  73. matchingFound = true
  74. //Set the X-Remote-User header
  75. r.Header.Set("X-Remote-User", u)
  76. break
  77. }
  78. }
  79. if !matchingFound {
  80. w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
  81. w.WriteHeader(401)
  82. return errors.New("unauthorized")
  83. }
  84. return nil
  85. }
  86. /* Authelia */
  87. // Handle authelia auth routing
  88. func (h *ProxyHandler) handleAutheliaAuth(w http.ResponseWriter, r *http.Request) error {
  89. return h.Parent.Option.AutheliaRouter.HandleAutheliaAuth(w, r)
  90. }