mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-06 14:20:55 +03:00
webdav: fix caching with external auth/plugins
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
@@ -1694,3 +1694,10 @@ func TestConfigsFromProvider(t *testing.T) {
|
||||
err = dataprovider.UpdateConfigs(nil, "", "", "")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGetCacheExpirationTime(t *testing.T) {
|
||||
c := UsersCacheConfig{}
|
||||
assert.True(t, c.getExpirationTime().IsZero())
|
||||
c.ExpirationTime = 1
|
||||
assert.False(t, c.getExpirationTime().IsZero())
|
||||
}
|
||||
|
||||
@@ -299,8 +299,20 @@ func (s *webDavServer) authenticate(r *http.Request, ip string) (dataprovider.Us
|
||||
tlsCert = nil
|
||||
loginMethod = dataprovider.LoginMethodPassword
|
||||
}
|
||||
if err := dataprovider.CheckCachedUserCredentials(cachedUser, password, loginMethod, common.ProtocolWebDAV, tlsCert); err == nil {
|
||||
return cachedUser.User, true, cachedUser.LockSystem, loginMethod, nil
|
||||
cu, u, err := dataprovider.CheckCachedUserCredentials(cachedUser, password, ip, loginMethod, common.ProtocolWebDAV, tlsCert)
|
||||
if err == nil {
|
||||
if cu != nil {
|
||||
return cu.User, true, cu.LockSystem, loginMethod, nil
|
||||
}
|
||||
lockSystem := webdav.NewMemLS()
|
||||
cachedUser = &dataprovider.CachedUser{
|
||||
User: *u,
|
||||
Password: password,
|
||||
LockSystem: lockSystem,
|
||||
Expiration: s.config.Cache.Users.getExpirationTime(),
|
||||
}
|
||||
dataprovider.CacheWebDAVUser(cachedUser)
|
||||
return cachedUser.User, false, cachedUser.LockSystem, loginMethod, nil
|
||||
}
|
||||
updateLoginMetrics(&cachedUser.User, ip, loginMethod, dataprovider.ErrInvalidCredentials)
|
||||
return user, false, nil, loginMethod, dataprovider.ErrInvalidCredentials
|
||||
@@ -318,9 +330,7 @@ func (s *webDavServer) authenticate(r *http.Request, ip string) (dataprovider.Us
|
||||
User: user,
|
||||
Password: password,
|
||||
LockSystem: lockSystem,
|
||||
}
|
||||
if s.config.Cache.Users.ExpirationTime > 0 {
|
||||
cachedUser.Expiration = time.Now().Add(time.Duration(s.config.Cache.Users.ExpirationTime) * time.Minute)
|
||||
Expiration: s.config.Cache.Users.getExpirationTime(),
|
||||
}
|
||||
dataprovider.CacheWebDAVUser(cachedUser)
|
||||
return user, false, lockSystem, loginMethod, nil
|
||||
|
||||
@@ -85,6 +85,13 @@ type UsersCacheConfig struct {
|
||||
MaxSize int `json:"max_size" mapstructure:"max_size"`
|
||||
}
|
||||
|
||||
func (c *UsersCacheConfig) getExpirationTime() time.Time {
|
||||
if c.ExpirationTime > 0 {
|
||||
return time.Now().Add(time.Duration(c.ExpirationTime) * time.Minute)
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// MimeCacheConfig defines the cache configuration for mime types
|
||||
type MimeCacheConfig struct {
|
||||
Enabled bool `json:"enabled" mapstructure:"enabled"`
|
||||
|
||||
@@ -1186,7 +1186,7 @@ func TestLoginExternalAuth(t *testing.T) {
|
||||
err = config.LoadConfig(configDir, "")
|
||||
assert.NoError(t, err)
|
||||
providerConf := config.GetProviderConf()
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u, ""), os.ModePerm)
|
||||
assert.NoError(t, err)
|
||||
providerConf.ExternalAuthHook = extAuthPath
|
||||
providerConf.ExternalAuthScope = 0
|
||||
@@ -1215,6 +1215,56 @@ func TestLoginExternalAuth(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestExternalAuthPasswordChange(t *testing.T) {
|
||||
if runtime.GOOS == osWindows {
|
||||
t.Skip("this test is not available on Windows")
|
||||
}
|
||||
u := getTestUser()
|
||||
err := dataprovider.Close()
|
||||
assert.NoError(t, err)
|
||||
err = config.LoadConfig(configDir, "")
|
||||
assert.NoError(t, err)
|
||||
providerConf := config.GetProviderConf()
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u, defaultPassword), os.ModePerm)
|
||||
assert.NoError(t, err)
|
||||
providerConf.ExternalAuthHook = extAuthPath
|
||||
providerConf.ExternalAuthScope = 0
|
||||
err = dataprovider.Initialize(providerConf, configDir, true)
|
||||
assert.NoError(t, err)
|
||||
client := getWebDavClient(u, false, nil)
|
||||
assert.NoError(t, checkBasicFunc(client))
|
||||
u.Username = defaultUsername + "1"
|
||||
client = getWebDavClient(u, false, nil)
|
||||
assert.Error(t, checkBasicFunc(client))
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u, defaultPassword+"1"), os.ModePerm)
|
||||
assert.NoError(t, err)
|
||||
client = getWebDavClient(u, false, nil)
|
||||
assert.Error(t, checkBasicFunc(client))
|
||||
u.Password = defaultPassword + "1"
|
||||
client = getWebDavClient(u, false, nil)
|
||||
assert.NoError(t, checkBasicFunc(client))
|
||||
user, _, err := httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, defaultUsername, user.Username)
|
||||
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
err = os.RemoveAll(user.GetHomeDir())
|
||||
assert.NoError(t, err)
|
||||
user, _, err = httpdtest.GetUserByUsername(defaultUsername+"1", http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
_, err = httpdtest.RemoveUser(user, http.StatusOK)
|
||||
assert.NoError(t, err)
|
||||
err = dataprovider.Close()
|
||||
assert.NoError(t, err)
|
||||
err = config.LoadConfig(configDir, "")
|
||||
assert.NoError(t, err)
|
||||
providerConf = config.GetProviderConf()
|
||||
err = dataprovider.Initialize(providerConf, configDir, true)
|
||||
assert.NoError(t, err)
|
||||
err = os.Remove(extAuthPath)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestExternalAuthReturningAnonymousUser(t *testing.T) {
|
||||
if runtime.GOOS == osWindows {
|
||||
t.Skip("this test is not available on Windows")
|
||||
@@ -1228,7 +1278,7 @@ func TestExternalAuthReturningAnonymousUser(t *testing.T) {
|
||||
err = config.LoadConfig(configDir, "")
|
||||
assert.NoError(t, err)
|
||||
providerConf := config.GetProviderConf()
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u, ""), os.ModePerm)
|
||||
assert.NoError(t, err)
|
||||
providerConf.ExternalAuthHook = extAuthPath
|
||||
providerConf.ExternalAuthScope = 0
|
||||
@@ -1320,7 +1370,7 @@ func TestExternalAuthAnonymousGroupInheritance(t *testing.T) {
|
||||
err = config.LoadConfig(configDir, "")
|
||||
assert.NoError(t, err)
|
||||
providerConf := config.GetProviderConf()
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u, ""), os.ModePerm)
|
||||
assert.NoError(t, err)
|
||||
providerConf.ExternalAuthHook = extAuthPath
|
||||
providerConf.ExternalAuthScope = 0
|
||||
@@ -2880,7 +2930,7 @@ func TestExternatAuthWithClientCert(t *testing.T) {
|
||||
err = config.LoadConfig(configDir, "")
|
||||
assert.NoError(t, err)
|
||||
providerConf := config.GetProviderConf()
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
|
||||
err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u, ""), os.ModePerm)
|
||||
assert.NoError(t, err)
|
||||
providerConf.ExternalAuthHook = extAuthPath
|
||||
providerConf.ExternalAuthScope = 0
|
||||
@@ -3371,11 +3421,15 @@ func getEncryptedFileSize(size int64) (int64, error) {
|
||||
return int64(encSize) + 33, err
|
||||
}
|
||||
|
||||
func getExtAuthScriptContent(user dataprovider.User) []byte {
|
||||
func getExtAuthScriptContent(user dataprovider.User, password string) []byte {
|
||||
extAuthContent := []byte("#!/bin/sh\n\n")
|
||||
extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("if test \"$SFTPGO_AUTHD_USERNAME\" = \"%v\"; then\n", user.Username))...)
|
||||
if password != "" {
|
||||
extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("if test \"$SFTPGO_AUTHD_USERNAME\" = \"%s\" -a \"$SFTPGO_AUTHD_PASSWORD\" = \"%s\"; then\n", user.Username, password))...)
|
||||
} else {
|
||||
extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("if test \"$SFTPGO_AUTHD_USERNAME\" = \"%s\"; then\n", user.Username))...)
|
||||
}
|
||||
u, _ := json.Marshal(user)
|
||||
extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
|
||||
extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("echo '%s'\n", string(u)))...)
|
||||
extAuthContent = append(extAuthContent, []byte("else\n")...)
|
||||
extAuthContent = append(extAuthContent, []byte("echo '{\"username\":\"\"}'\n")...)
|
||||
extAuthContent = append(extAuthContent, []byte("fi\n")...)
|
||||
|
||||
Reference in New Issue
Block a user