From 637463a068fb3c02e1fc95c4c21361d113a8f2de Mon Sep 17 00:00:00 2001 From: Mengsk Date: Tue, 25 Feb 2020 16:07:38 +0100 Subject: [PATCH] Rename before_login_program to pre_login_program and some documentation update --- README.md | 14 +++++++------- config/config.go | 2 +- dataprovider/dataprovider.go | 30 +++++++++++++++--------------- sftpd/sftpd_test.go | 24 ++++++++++++------------ sftpgo.json | 2 +- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 86e88815..cc847eb9 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Full featured and highly configurable SFTP server - Keyboard interactive authentication. You can easily setup a customizable multi-factor authentication. - Per user authentication methods. You can, for example, deny one or more authentication methods to one or more users. - Custom authentication via external programs is supported. -- Dynamic users modifications before login via external programs are supported. +- Dynamic user modification before login via external programs is supported. - Quota support: accounts can have individual quota expressed as max total size and/or max number of files. - Bandwidth throttling is supported, with distinct settings for upload and download. - Per user maximum concurrent sessions. @@ -183,7 +183,7 @@ The `sftpgo` configuration file contains the following sections: - `external_auth_program`, string. Absolute path to an external program to use for users authentication. See the "External Authentication" paragraph for more details. Leave empty to disable. - `external_auth_scope`, integer. 0 means all supported authetication scopes (passwords, public keys and keyboard interactive). 1 means passwords only. 2 means public keys only. 4 means key keyboard interactive only. The flags can be combined, for example 6 means public keys and keyboard interactive - `credentials_path`, string. It defines the directory for storing user provided credential files such as Google Cloud Storage credentials. This can be an absolute path or a path relative to the config dir - - `before_login_program`, string. Absolute path to an external program to use to modify user details just before the login. See the "Dynamic users modifications" paragraph for more details. Leave empty to disable. + - `pre_login_program`, string. Absolute path to an external program to use to modify user details just before the login. See the "Dynamic user modification" paragraph for more details. Leave empty to disable. - **"httpd"**, the configuration for the HTTP server used to serve REST API - `bind_port`, integer. The port used for serving HTTP requests. Set to 0 to disable HTTP server. Default: 8080 - `bind_address`, string. Leave blank to listen on all available network interfaces. Default: "127.0.0.1" @@ -243,7 +243,7 @@ Here is a full example showing the default config in JSON format: "external_auth_program": "", "external_auth_scope": 0, "credentials_path": "credentials", - "before_login_program": "" + "pre_login_program": "" }, "httpd": { "bind_port": 8080, @@ -400,10 +400,10 @@ fi If you have an external authentication program that could be useful for others too, please let us know and/or send a pull request. -## Dynamic users modifications +## Dynamic user modification -Dynamic users modifications are supported via an external program that can be executed just before the user login. -To enable dynamic users modifications you must set the absolute path of your program using the `before_login_program` key in your configuration file. +Dynamic user modification is supported via an external program that can be executed just before the user login. +To enable dynamic user modification you must set the absolute path of your program using the `pre_login_program` key in your configuration file. The external program can read the following environment variables to get info about the user trying to login: @@ -418,7 +418,7 @@ The JSON response can include only the fields that need to the updated instead o ``` The external program must finish within 60 seconds. -If an error happens while executing your program then login will be denied. "Dynamic users modifications" and "External Authentication" are mutally exclusive. +If an error happens while executing your program then login will be denied. "Dynamic user modification" and "External Authentication" are mutally exclusive. Let's see a very basic example. Our sample program will grant access to the user `test_user` only in the time range 10:00-18:00. Other users will not be modified since the program will terminate with no output. diff --git a/config/config.go b/config/config.go index 0c14bb91..08a09b37 100644 --- a/config/config.go +++ b/config/config.go @@ -85,7 +85,7 @@ func init() { ExternalAuthProgram: "", ExternalAuthScope: 0, CredentialsPath: "credentials", - BeforeLoginProgram: "", + PreLoginProgram: "", }, HTTPDConfig: httpd.Conf{ BindPort: 8080, diff --git a/dataprovider/dataprovider.go b/dataprovider/dataprovider.go index e10a5233..b6c2d4b6 100644 --- a/dataprovider/dataprovider.go +++ b/dataprovider/dataprovider.go @@ -214,10 +214,10 @@ type Config struct { // // The external program must finish within 60 seconds. // - // If an error happen while executing the "BeforeLoginProgram" then login will be denied. - // BeforeLoginProgram and ExternalAuthProgram are mutally exclusive. + // If an error happens while executing the "PreLoginProgram" then login will be denied. + // PreLoginProgram and ExternalAuthProgram are mutally exclusive. // Leave empty to disable. - BeforeLoginProgram string `json:"before_login_program" mapstructure:"before_login_program"` + PreLoginProgram string `json:"pre_login_program" mapstructure:"pre_login_program"` } // BackupData defines the structure for the backup/restore files @@ -316,11 +316,11 @@ func Initialize(cnf Config, basePath string) error { return err } } - if len(config.BeforeLoginProgram) > 0 { - if !filepath.IsAbs(config.BeforeLoginProgram) { - return fmt.Errorf("invalid pre login program: %#v must be an absolute path", config.BeforeLoginProgram) + if len(config.PreLoginProgram) > 0 { + if !filepath.IsAbs(config.PreLoginProgram) { + return fmt.Errorf("invalid pre login program: %#v must be an absolute path", config.PreLoginProgram) } - _, err := os.Stat(config.BeforeLoginProgram) + _, err := os.Stat(config.PreLoginProgram) if err != nil { providerLog(logger.LevelWarn, "invalid pre login program: %v", err) return err @@ -366,8 +366,8 @@ func CheckUserAndPass(p Provider, username string, password string) (User, error } return checkUserAndPass(user, password) } - if len(config.BeforeLoginProgram) > 0 { - user, err := executeBeforeLoginProgram(username, SSHLoginMethodPassword) + if len(config.PreLoginProgram) > 0 { + user, err := executePreLoginProgram(username, SSHLoginMethodPassword) if err != nil { return user, err } @@ -385,8 +385,8 @@ func CheckUserAndPubKey(p Provider, username string, pubKey string) (User, strin } return checkUserAndPubKey(user, pubKey) } - if len(config.BeforeLoginProgram) > 0 { - user, err := executeBeforeLoginProgram(username, SSHLoginMethodPublicKey) + if len(config.PreLoginProgram) > 0 { + user, err := executePreLoginProgram(username, SSHLoginMethodPublicKey) if err != nil { return user, "", err } @@ -402,8 +402,8 @@ func CheckKeyboardInteractiveAuth(p Provider, username, authProgram string, clie var err error if len(config.ExternalAuthProgram) > 0 && (config.ExternalAuthScope == 0 || config.ExternalAuthScope&4 != 0) { user, err = doExternalAuth(username, "", "", "1") - } else if len(config.BeforeLoginProgram) > 0 { - user, err = executeBeforeLoginProgram(username, SSHLoginMethodKeyboardInteractive) + } else if len(config.PreLoginProgram) > 0 { + user, err = executePreLoginProgram(username, SSHLoginMethodKeyboardInteractive) } else { user, err = p.userExists(username) } @@ -1143,7 +1143,7 @@ func doKeyboardInteractiveAuth(user User, authProgram string, client ssh.Keyboar return user, nil } -func executeBeforeLoginProgram(username, loginMethod string) (User, error) { +func executePreLoginProgram(username, loginMethod string) (User, error) { u, err := provider.userExists(username) if err != nil { return u, err @@ -1155,7 +1155,7 @@ func executeBeforeLoginProgram(username, loginMethod string) (User, error) { ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() - cmd := exec.CommandContext(ctx, config.BeforeLoginProgram) + cmd := exec.CommandContext(ctx, config.PreLoginProgram) cmd.Env = append(os.Environ(), fmt.Sprintf("SFTPGO_LOGIND_USER=%v", string(userAsJSON)), fmt.Sprintf("SFTPGO_LOGIND_METHOD=%v", loginMethod)) diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index e081900d..d5fd50df 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -99,7 +99,7 @@ var ( gitWrapPath string extAuthPath string keyIntAuthPath string - beforeLoginPath string + preLoginPath string logFilePath string ) @@ -172,7 +172,7 @@ func TestMain(m *testing.M) { privateKeyPath = filepath.Join(homeBasePath, "ssh_key") gitWrapPath = filepath.Join(homeBasePath, "gitwrap.sh") extAuthPath = filepath.Join(homeBasePath, "extauth.sh") - beforeLoginPath = filepath.Join(homeBasePath, "beforelogin.sh") + preLoginPath = filepath.Join(homeBasePath, "prelogin.sh") err = ioutil.WriteFile(pubKeyPath, []byte(testPubKey+"\n"), 0600) if err != nil { logger.WarnToConsole("unable to save public key to file: %v", err) @@ -212,7 +212,7 @@ func TestMain(m *testing.M) { os.Remove(privateKeyPath) os.Remove(gitWrapPath) os.Remove(extAuthPath) - os.Remove(beforeLoginPath) + os.Remove(preLoginPath) os.Remove(keyIntAuthPath) os.Exit(exitCode) } @@ -1305,7 +1305,7 @@ func TestLoginKeyboardInteractiveAuth(t *testing.T) { os.RemoveAll(user.GetHomeDir()) } -func TestBeforeLoginScript(t *testing.T) { +func TestPreLoginScript(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("this test is not available on Windows") } @@ -1315,8 +1315,8 @@ func TestBeforeLoginScript(t *testing.T) { dataprovider.Close(dataProvider) config.LoadConfig(configDir, "") providerConf := config.GetProviderConf() - ioutil.WriteFile(beforeLoginPath, getBeforeLoginScriptContent(u, false), 0755) - providerConf.BeforeLoginProgram = beforeLoginPath + ioutil.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), 0755) + providerConf.PreLoginProgram = preLoginPath err := dataprovider.Initialize(providerConf, configDir) if err != nil { t.Errorf("error initializing data provider") @@ -1338,16 +1338,16 @@ func TestBeforeLoginScript(t *testing.T) { t.Errorf("unable to get working dir: %v", err) } } - ioutil.WriteFile(beforeLoginPath, getBeforeLoginScriptContent(user, true), 0755) + ioutil.WriteFile(preLoginPath, getPreLoginScriptContent(user, true), 0755) _, err = getSftpClient(u, usePubKey) if err == nil { - t.Error("before login script returned a non json response, login must fail") + t.Error("pre login script returned a non json response, login must fail") } user.Status = 0 - ioutil.WriteFile(beforeLoginPath, getBeforeLoginScriptContent(user, false), 0755) + ioutil.WriteFile(preLoginPath, getPreLoginScriptContent(user, false), 0755) _, err = getSftpClient(u, usePubKey) if err == nil { - t.Error("before login script returned a disabled user, login must fail") + t.Error("pre login script returned a disabled user, login must fail") } _, err = httpd.RemoveUser(user, http.StatusOK) if err != nil { @@ -1364,7 +1364,7 @@ func TestBeforeLoginScript(t *testing.T) { } httpd.SetDataProvider(dataprovider.GetProvider()) sftpd.SetDataProvider(dataprovider.GetProvider()) - os.Remove(beforeLoginPath) + os.Remove(preLoginPath) } func TestLoginExternalAuthPwdAndPubKey(t *testing.T) { @@ -5042,7 +5042,7 @@ func getExtAuthScriptContent(user dataprovider.User, sleepTime int, nonJsonRespo return extAuthContent } -func getBeforeLoginScriptContent(user dataprovider.User, nonJsonResponse bool) []byte { +func getPreLoginScriptContent(user dataprovider.User, nonJsonResponse bool) []byte { content := []byte("#!/bin/sh\n\n") if nonJsonResponse { content = append(content, []byte("echo 'text response'\n")...) diff --git a/sftpgo.json b/sftpgo.json index 1664ce1d..3d84e911 100644 --- a/sftpgo.json +++ b/sftpgo.json @@ -44,7 +44,7 @@ "external_auth_program": "", "external_auth_scope": 0, "credentials_path": "credentials", - "before_login_program": "" + "pre_login_program": "" }, "httpd": { "bind_port": 8080,