mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-07 14:50:55 +03:00
webdav: allow to disable the WWW-Authenticate header
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
@@ -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.
|
- `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_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`.
|
- `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_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.
|
- `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.
|
- `ca_certificates`, list of strings. Set of root certificate authorities to be used to verify client certificates.
|
||||||
|
|||||||
@@ -81,18 +81,19 @@ var (
|
|||||||
Debug: false,
|
Debug: false,
|
||||||
}
|
}
|
||||||
defaultWebDAVDBinding = webdavd.Binding{
|
defaultWebDAVDBinding = webdavd.Binding{
|
||||||
Address: "",
|
Address: "",
|
||||||
Port: 0,
|
Port: 0,
|
||||||
EnableHTTPS: false,
|
EnableHTTPS: false,
|
||||||
CertificateFile: "",
|
CertificateFile: "",
|
||||||
CertificateKeyFile: "",
|
CertificateKeyFile: "",
|
||||||
MinTLSVersion: 12,
|
MinTLSVersion: 12,
|
||||||
ClientAuthType: 0,
|
ClientAuthType: 0,
|
||||||
TLSCipherSuites: nil,
|
TLSCipherSuites: nil,
|
||||||
Prefix: "",
|
Prefix: "",
|
||||||
ProxyAllowed: nil,
|
ProxyAllowed: nil,
|
||||||
ClientIPProxyHeader: "",
|
ClientIPProxyHeader: "",
|
||||||
ClientIPHeaderDepth: 0,
|
ClientIPHeaderDepth: 0,
|
||||||
|
DisableWWWAuthHeader: false,
|
||||||
}
|
}
|
||||||
defaultHTTPDBinding = httpd.Binding{
|
defaultHTTPDBinding = httpd.Binding{
|
||||||
Address: "",
|
Address: "",
|
||||||
@@ -1193,6 +1194,12 @@ func getWebDAVDBindingFromEnv(idx int) {
|
|||||||
isSet = true
|
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))
|
certificateFile, ok := os.LookupEnv(fmt.Sprintf("SFTPGO_WEBDAVD__BINDINGS__%v__CERTIFICATE_FILE", idx))
|
||||||
if ok {
|
if ok {
|
||||||
binding.CertificateFile = certificateFile
|
binding.CertificateFile = certificateFile
|
||||||
@@ -1205,12 +1212,6 @@ func getWebDAVDBindingFromEnv(idx int) {
|
|||||||
isSet = true
|
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))
|
tlsVer, ok := lookupIntFromEnv(fmt.Sprintf("SFTPGO_WEBDAVD__BINDINGS__%v__MIN_TLS_VERSION", idx))
|
||||||
if ok {
|
if ok {
|
||||||
binding.MinTLSVersion = int(tlsVer)
|
binding.MinTLSVersion = int(tlsVer)
|
||||||
@@ -1229,13 +1230,19 @@ func getWebDAVDBindingFromEnv(idx int) {
|
|||||||
isSet = true
|
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) {
|
if getWebDAVDBindingProxyConfigsFromEnv(idx, &binding) {
|
||||||
isSet = true
|
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 {
|
if ok {
|
||||||
binding.Prefix = prefix
|
binding.DisableWWWAuthHeader = disableWWWAuth
|
||||||
isSet = true
|
isSet = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -943,6 +943,7 @@ func TestWebDAVBindingsFromEnv(t *testing.T) {
|
|||||||
os.Setenv("SFTPGO_WEBDAVD__BINDINGS__2__PREFIX", "/dav2")
|
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_FILE", "webdav.crt")
|
||||||
os.Setenv("SFTPGO_WEBDAVD__BINDINGS__2__CERTIFICATE_KEY_FILE", "webdav.key")
|
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() {
|
t.Cleanup(func() {
|
||||||
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__1__ADDRESS")
|
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__PREFIX")
|
||||||
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__2__CERTIFICATE_FILE")
|
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__2__CERTIFICATE_FILE")
|
||||||
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__2__CERTIFICATE_KEY_FILE")
|
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__2__CERTIFICATE_KEY_FILE")
|
||||||
|
os.Unsetenv("SFTPGO_WEBDAVD__BINDINGS__2__DISABLE_WWW_AUTH_HEADER")
|
||||||
})
|
})
|
||||||
|
|
||||||
err := config.LoadConfig(configDir, "")
|
err := config.LoadConfig(configDir, "")
|
||||||
@@ -973,6 +975,7 @@ func TestWebDAVBindingsFromEnv(t *testing.T) {
|
|||||||
require.Len(t, bindings[0].TLSCipherSuites, 0)
|
require.Len(t, bindings[0].TLSCipherSuites, 0)
|
||||||
require.Empty(t, bindings[0].Prefix)
|
require.Empty(t, bindings[0].Prefix)
|
||||||
require.Equal(t, 0, bindings[0].ClientIPHeaderDepth)
|
require.Equal(t, 0, bindings[0].ClientIPHeaderDepth)
|
||||||
|
require.False(t, bindings[0].DisableWWWAuthHeader)
|
||||||
require.Equal(t, 8000, bindings[1].Port)
|
require.Equal(t, 8000, bindings[1].Port)
|
||||||
require.Equal(t, "127.0.0.1", bindings[1].Address)
|
require.Equal(t, "127.0.0.1", bindings[1].Address)
|
||||||
require.False(t, bindings[1].EnableHTTPS)
|
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, "X-Forwarded-For", bindings[1].ClientIPProxyHeader)
|
||||||
require.Equal(t, 2, bindings[1].ClientIPHeaderDepth)
|
require.Equal(t, 2, bindings[1].ClientIPHeaderDepth)
|
||||||
require.Empty(t, bindings[1].Prefix)
|
require.Empty(t, bindings[1].Prefix)
|
||||||
|
require.False(t, bindings[1].DisableWWWAuthHeader)
|
||||||
require.Equal(t, 9000, bindings[2].Port)
|
require.Equal(t, 9000, bindings[2].Port)
|
||||||
require.Equal(t, "127.0.1.1", bindings[2].Address)
|
require.Equal(t, "127.0.1.1", bindings[2].Address)
|
||||||
require.True(t, bindings[2].EnableHTTPS)
|
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.crt", bindings[2].CertificateFile)
|
||||||
require.Equal(t, "webdav.key", bindings[2].CertificateKeyFile)
|
require.Equal(t, "webdav.key", bindings[2].CertificateKeyFile)
|
||||||
require.Equal(t, 0, bindings[2].ClientIPHeaderDepth)
|
require.Equal(t, 0, bindings[2].ClientIPHeaderDepth)
|
||||||
|
require.True(t, bindings[2].DisableWWWAuthHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHTTPDBindingsFromEnv(t *testing.T) {
|
func TestHTTPDBindingsFromEnv(t *testing.T) {
|
||||||
|
|||||||
@@ -189,7 +189,9 @@ func (s *webDavServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
user, isCached, lockSystem, loginMethod, err := s.authenticate(r, ipAddr)
|
user, isCached, lockSystem, loginMethod, err := s.authenticate(r, ipAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
updateLoginMetrics(&user, ipAddr, loginMethod, err)
|
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)
|
http.Error(w, fmt.Sprintf("Authentication error: %v", err), http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
// "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
|
// 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"`
|
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 {
|
func (b *Binding) parseAllowedProxy() error {
|
||||||
|
|||||||
@@ -151,7 +151,8 @@
|
|||||||
"prefix": "",
|
"prefix": "",
|
||||||
"proxy_allowed": [],
|
"proxy_allowed": [],
|
||||||
"client_ip_proxy_header": "",
|
"client_ip_proxy_header": "",
|
||||||
"client_ip_header_depth": 0
|
"client_ip_header_depth": 0,
|
||||||
|
"disable_www_auth_header": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"certificate_file": "",
|
"certificate_file": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user