webdav: allow to disable the WWW-Authenticate header

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2022-08-02 19:06:49 +02:00
parent fdc10aa6c7
commit 6bfdf941bc
No known key found for this signature in database
GPG key ID: 2F1FB59433D5A8CB
6 changed files with 42 additions and 23 deletions

View file

@ -182,6 +182,7 @@ The configuration file contains the following sections:
- `proxy_allowed`, list of IP addresses and IP ranges allowed to set client IP proxy header such as `X-Forwarded-For`. Any client IP proxy headers, if set on requests from a connection address not in this list, will be silently ignored. Default: empty.
- `client_ip_proxy_header`, string. Defines the allowed client IP proxy header such as `X-Forwarded-For`, `X-Real-IP` etc. Default: empty
- `client_ip_header_depth`, integer. Some client IP headers such as `X-Forwarded-For` can contain multiple IP address, this setting define the position to trust starting from the right. For example if we have: `10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1` and the depth is `0`, SFTPGo will use `13.0.0.1` as client IP, if depth is `1`, `12.0.0.1` will be used and so on. Default: `0`.
- `disable_www_auth_header`, boolean. Set to `true` to not add the WWW-Authenticate header after an authentication failure, only the `401` status code will be sent. Default: `false`.
- `certificate_file`, string. Certificate for WebDAV over HTTPS. This can be an absolute path or a path relative to the config dir.
- `certificate_key_file`, string. Private key matching the above certificate. This can be an absolute path or a path relative to the config dir. A certificate and a private key are required to enable HTTPS connections. Certificate and key files can be reloaded on demand sending a `SIGHUP` signal on Unix based systems and a `paramchange` request to the running service on Windows.
- `ca_certificates`, list of strings. Set of root certificate authorities to be used to verify client certificates.

View file

@ -81,18 +81,19 @@ var (
Debug: false,
}
defaultWebDAVDBinding = webdavd.Binding{
Address: "",
Port: 0,
EnableHTTPS: false,
CertificateFile: "",
CertificateKeyFile: "",
MinTLSVersion: 12,
ClientAuthType: 0,
TLSCipherSuites: nil,
Prefix: "",
ProxyAllowed: nil,
ClientIPProxyHeader: "",
ClientIPHeaderDepth: 0,
Address: "",
Port: 0,
EnableHTTPS: false,
CertificateFile: "",
CertificateKeyFile: "",
MinTLSVersion: 12,
ClientAuthType: 0,
TLSCipherSuites: nil,
Prefix: "",
ProxyAllowed: nil,
ClientIPProxyHeader: "",
ClientIPHeaderDepth: 0,
DisableWWWAuthHeader: false,
}
defaultHTTPDBinding = httpd.Binding{
Address: "",
@ -1193,6 +1194,12 @@ func getWebDAVDBindingFromEnv(idx int) {
isSet = true
}
enableHTTPS, ok := lookupBoolFromEnv(fmt.Sprintf("SFTPGO_WEBDAVD__BINDINGS__%v__ENABLE_HTTPS", idx))
if ok {
binding.EnableHTTPS = enableHTTPS
isSet = true
}
certificateFile, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_WEBDAVD__BINDINGS__%v__CERTIFICATE_FILE", idx))
if ok {
binding.CertificateFile = certificateFile
@ -1205,12 +1212,6 @@ func getWebDAVDBindingFromEnv(idx int) {
isSet = true
}
enableHTTPS, ok := lookupBoolFromEnv(fmt.Sprintf("SFTPGO_WEBDAVD__BINDINGS__%v__ENABLE_HTTPS", idx))
if ok {
binding.EnableHTTPS = enableHTTPS
isSet = true
}
tlsVer, ok := lookupIntFromEnv(fmt.Sprintf("SFTPGO_WEBDAVD__BINDINGS__%v__MIN_TLS_VERSION", idx))
if ok {
binding.MinTLSVersion = int(tlsVer)
@ -1229,13 +1230,19 @@ func getWebDAVDBindingFromEnv(idx int) {
isSet = true
}
prefix, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_WEBDAVD__BINDINGS__%v__PREFIX", idx))
if ok {
binding.Prefix = prefix
isSet = true
}
if getWebDAVDBindingProxyConfigsFromEnv(idx, &binding) {
isSet = true
}
prefix, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_WEBDAVD__BINDINGS__%v__PREFIX", idx))
disableWWWAuth, ok := lookupBoolFromEnv(fmt.Sprintf("SFTPGO_WEBDAVD__BINDINGS__%v__DISABLE_WWW_AUTH_HEADER", idx))
if ok {
binding.Prefix = prefix
binding.DisableWWWAuthHeader = disableWWWAuth
isSet = true
}

View file

@ -943,6 +943,7 @@ func TestWebDAVBindingsFromEnv(t *testing.T) {
os.Setenv("SFTPGO_WEBDAVD__BINDINGS__2__PREFIX", "/dav2")
os.Setenv("SFTPGO_WEBDAVD__BINDINGS__2__CERTIFICATE_FILE", "webdav.crt")
os.Setenv("SFTPGO_WEBDAVD__BINDINGS__2__CERTIFICATE_KEY_FILE", "webdav.key")
os.Setenv("SFTPGO_WEBDAVD__BINDINGS__2__DISABLE_WWW_AUTH_HEADER", "1")
t.Cleanup(func() {
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__1__ADDRESS")
@ -960,6 +961,7 @@ func TestWebDAVBindingsFromEnv(t *testing.T) {
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__2__PREFIX")
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__2__CERTIFICATE_FILE")
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__2__CERTIFICATE_KEY_FILE")
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__2__DISABLE_WWW_AUTH_HEADER")
})
err := config.LoadConfig(configDir, "")
@ -973,6 +975,7 @@ func TestWebDAVBindingsFromEnv(t *testing.T) {
require.Len(t, bindings[0].TLSCipherSuites, 0)
require.Empty(t, bindings[0].Prefix)
require.Equal(t, 0, bindings[0].ClientIPHeaderDepth)
require.False(t, bindings[0].DisableWWWAuthHeader)
require.Equal(t, 8000, bindings[1].Port)
require.Equal(t, "127.0.0.1", bindings[1].Address)
require.False(t, bindings[1].EnableHTTPS)
@ -984,6 +987,7 @@ func TestWebDAVBindingsFromEnv(t *testing.T) {
require.Equal(t, "X-Forwarded-For", bindings[1].ClientIPProxyHeader)
require.Equal(t, 2, bindings[1].ClientIPHeaderDepth)
require.Empty(t, bindings[1].Prefix)
require.False(t, bindings[1].DisableWWWAuthHeader)
require.Equal(t, 9000, bindings[2].Port)
require.Equal(t, "127.0.1.1", bindings[2].Address)
require.True(t, bindings[2].EnableHTTPS)
@ -994,6 +998,7 @@ func TestWebDAVBindingsFromEnv(t *testing.T) {
require.Equal(t, "webdav.crt", bindings[2].CertificateFile)
require.Equal(t, "webdav.key", bindings[2].CertificateKeyFile)
require.Equal(t, 0, bindings[2].ClientIPHeaderDepth)
require.True(t, bindings[2].DisableWWWAuthHeader)
}
func TestHTTPDBindingsFromEnv(t *testing.T) {

View file

@ -189,7 +189,9 @@ func (s *webDavServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
user, isCached, lockSystem, loginMethod, err := s.authenticate(r, ipAddr)
if err != nil {
updateLoginMetrics(&user, ipAddr, loginMethod, err)
w.Header().Set("WWW-Authenticate", "Basic realm=\"SFTPGo WebDAV\"")
if !s.binding.DisableWWWAuthHeader {
w.Header().Set("WWW-Authenticate", "Basic realm=\"SFTPGo WebDAV\"")
}
http.Error(w, fmt.Sprintf("Authentication error: %v", err), http.StatusUnauthorized)
return
}

View file

@ -122,7 +122,10 @@ type Binding struct {
// "10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1" and the depth is 0, SFTPGo will use "13.0.0.1"
// as client IP, if depth is 1, "12.0.0.1" will be used and so on
ClientIPHeaderDepth int `json:"client_ip_header_depth" mapstructure:"client_ip_header_depth"`
allowHeadersFrom []func(net.IP) bool
// Do not add the WWW-Authenticate header after an authentication error,
// only the 401 status code will be sent
DisableWWWAuthHeader bool `json:"disable_www_auth_header" mapstructure:"disable_www_auth_header"`
allowHeadersFrom []func(net.IP) bool
}
func (b *Binding) parseAllowedProxy() error {

View file

@ -151,7 +151,8 @@
"prefix": "",
"proxy_allowed": [],
"client_ip_proxy_header": "",
"client_ip_header_depth": 0
"client_ip_header_depth": 0,
"disable_www_auth_header": false
}
],
"certificate_file": "",