Auth logout URL, auth proxy
This commit is contained in:
@@ -167,6 +167,7 @@ type Config struct {
|
||||
ProxyForwardedHeader string // The header field to read the real/client IP address from, if BehindProxy is true, defaults to "X-Forwarded-For" (IPv4 and IPv6 supported)
|
||||
ProxyTrustedPrefixes []netip.Prefix // List of trusted proxy networks (IPv4 or IPv6) that will be stripped from the Forwarded header if BehindProxy is true
|
||||
AuthUserHeader string // Header to read the authenticated user from, if BehindProxy is true (e.g. X-Forwarded-User, Remote-User)
|
||||
AuthLogoutURL string // URL to redirect to when logging out in proxy auth mode (e.g. https://auth.example.com/logout)
|
||||
StripeSecretKey string
|
||||
StripeWebhookKey string
|
||||
StripePriceCacheDuration time.Duration
|
||||
@@ -265,6 +266,7 @@ func NewConfig() *Config {
|
||||
BehindProxy: false, // If true, the server will trust the proxy client IP header to determine the client IP address
|
||||
ProxyForwardedHeader: "X-Forwarded-For", // Default header for reverse proxy client IPs
|
||||
AuthUserHeader: "", // Header to read the authenticated user from (requires behind-proxy and auth-file)
|
||||
AuthLogoutURL: "", // URL to redirect to when logging out in proxy auth mode
|
||||
StripeSecretKey: "",
|
||||
StripeWebhookKey: "",
|
||||
StripePriceCacheDuration: DefaultStripePriceCacheDuration,
|
||||
|
||||
@@ -603,13 +603,13 @@ func (s *Server) handleHealth(w http.ResponseWriter, _ *http.Request, _ *visitor
|
||||
return s.writeJSON(w, response)
|
||||
}
|
||||
|
||||
func (s *Server) handleConfig(w http.ResponseWriter, _ *http.Request, _ *visitor) error {
|
||||
func (s *Server) handleConfig(w http.ResponseWriter, _ *http.Request, v *visitor) error {
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
return s.writeJSON(w, s.configResponse())
|
||||
return s.writeJSON(w, s.configResponse(v))
|
||||
}
|
||||
|
||||
func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visitor) error {
|
||||
b, err := json.MarshalIndent(s.configResponse(), "", " ")
|
||||
func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, v *visitor) error {
|
||||
b, err := json.MarshalIndent(s.configResponse(v), "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -619,7 +619,15 @@ func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visi
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) configResponse() *apiConfigResponse {
|
||||
func (s *Server) configResponse(v *visitor) *apiConfigResponse {
|
||||
authMode := ""
|
||||
username := ""
|
||||
if s.config.AuthUserHeader != "" {
|
||||
authMode = "proxy"
|
||||
if v != nil && v.User() != nil {
|
||||
username = v.User().Name
|
||||
}
|
||||
}
|
||||
return &apiConfigResponse{
|
||||
BaseURL: "", // Will translate to window.location.origin
|
||||
AppRoot: s.config.WebRoot,
|
||||
@@ -635,6 +643,9 @@ func (s *Server) configResponse() *apiConfigResponse {
|
||||
WebPushPublicKey: s.config.WebPushPublicKey,
|
||||
DisallowedTopics: s.config.DisallowedTopics,
|
||||
ConfigHash: s.config.Hash(),
|
||||
AuthMode: authMode,
|
||||
AuthLogoutURL: s.config.AuthLogoutURL,
|
||||
Username: username,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,12 @@
|
||||
#
|
||||
# auth-user-header:
|
||||
|
||||
# If auth-user-header is set, this is the URL to redirect users to when they click logout.
|
||||
# This is typically the logout URL of your authentication proxy (e.g. Authelia, Authentik).
|
||||
# If not set, the logout button will be hidden in the web UI when using proxy auth.
|
||||
#
|
||||
# auth-logout-url:
|
||||
|
||||
# If enabled, clients can attach files to notifications as attachments. Minimum settings to enable attachments
|
||||
# are "attachment-cache-dir" and "base-url".
|
||||
#
|
||||
|
||||
@@ -2428,7 +2428,7 @@ func TestServer_AuthUserHeader_UserNotFound(t *testing.T) {
|
||||
require.Equal(t, errHTTPUnauthorized, err)
|
||||
}
|
||||
|
||||
func TestServer_AuthUserHeader_NoHeader_FallbackToStandardAuth(t *testing.T) {
|
||||
func TestServer_AuthUserHeader_NoHeader_ReturnsUnauthorized(t *testing.T) {
|
||||
c := newTestConfigWithAuthFile(t)
|
||||
c.BehindProxy = true
|
||||
c.AuthUserHeader = "X-Forwarded-User"
|
||||
@@ -2436,28 +2436,27 @@ func TestServer_AuthUserHeader_NoHeader_FallbackToStandardAuth(t *testing.T) {
|
||||
|
||||
require.Nil(t, s.userManager.AddUser("phil", "phil", user.RoleUser, false))
|
||||
|
||||
// No X-Forwarded-User header, but with Authorization header
|
||||
// No X-Forwarded-User header, even with Authorization header -> unauthorized
|
||||
// When auth-user-header is configured, the header MUST be present
|
||||
r, _ := http.NewRequest("GET", "/mytopic/json?poll=1", nil)
|
||||
r.RemoteAddr = "1.2.3.4:1234"
|
||||
r.Header.Set("Authorization", util.BasicAuth("phil", "phil"))
|
||||
v, err := s.maybeAuthenticate(r)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, v.User())
|
||||
require.Equal(t, "phil", v.User().Name)
|
||||
_, err := s.maybeAuthenticate(r)
|
||||
require.Equal(t, errHTTPUnauthorized, err)
|
||||
}
|
||||
|
||||
func TestServer_AuthUserHeader_NoHeader_AnonymousAllowed(t *testing.T) {
|
||||
func TestServer_AuthUserHeader_NoHeader_NoAuthReturnsUnauthorized(t *testing.T) {
|
||||
c := newTestConfigWithAuthFile(t)
|
||||
c.BehindProxy = true
|
||||
c.AuthUserHeader = "X-Forwarded-User"
|
||||
s := newTestServer(t, c)
|
||||
|
||||
// No X-Forwarded-User header and no Authorization header -> anonymous
|
||||
// No X-Forwarded-User header and no Authorization header -> unauthorized
|
||||
// When auth-user-header is configured, the header MUST be present
|
||||
r, _ := http.NewRequest("GET", "/mytopic/json?poll=1", nil)
|
||||
r.RemoteAddr = "1.2.3.4:1234"
|
||||
v, err := s.maybeAuthenticate(r)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, v.User())
|
||||
_, err := s.maybeAuthenticate(r)
|
||||
require.Equal(t, errHTTPUnauthorized, err)
|
||||
}
|
||||
|
||||
func TestServer_AuthUserHeader_NotBehindProxy(t *testing.T) {
|
||||
|
||||
@@ -483,6 +483,9 @@ type apiConfigResponse struct {
|
||||
WebPushPublicKey string `json:"web_push_public_key"`
|
||||
DisallowedTopics []string `json:"disallowed_topics"`
|
||||
ConfigHash string `json:"config_hash"`
|
||||
AuthMode string `json:"auth_mode,omitempty"` // "proxy" if auth-user-header is set, empty otherwise
|
||||
AuthLogoutURL string `json:"auth_logout_url,omitempty"` // URL to redirect to on logout (only for proxy auth)
|
||||
Username string `json:"username,omitempty"` // Authenticated username (for proxy auth)
|
||||
}
|
||||
|
||||
type apiAccountBillingPrices struct {
|
||||
|
||||
Reference in New Issue
Block a user