diff --git a/docs/external-auth.md b/docs/external-auth.md index 022f21b4..9fb1eb02 100644 --- a/docs/external-auth.md +++ b/docs/external-auth.md @@ -21,6 +21,8 @@ The program must write, on its standard output: - an empty string, or no response at all, if authentication succeeds and the existing SFTPGo user does not need to be updated. This means that the credentials already stored in SFTPGo must match those used for the current authentication. - a user with an empty username if the authentication fails +Any output of the program on its standard error will be recorded in the sftpgo logs with sender `external_auth_hook`. + If the hook is an HTTP URL then it will be invoked as HTTP POST. The request body will contain a JSON serialized struct with the following fields: - `username` diff --git a/internal/dataprovider/dataprovider.go b/internal/dataprovider/dataprovider.go index fabb3a60..b35cf8c8 100644 --- a/internal/dataprovider/dataprovider.go +++ b/internal/dataprovider/dataprovider.go @@ -3979,7 +3979,26 @@ func getExternalAuthResponse(username, password, pkey, keyboardInteractive, ip, fmt.Sprintf("SFTPGO_AUTHD_PROTOCOL=%v", protocol), fmt.Sprintf("SFTPGO_AUTHD_TLS_CERT=%v", strings.ReplaceAll(tlsCert, "\n", "\\n")), fmt.Sprintf("SFTPGO_AUTHD_KEYBOARD_INTERACTIVE=%v", keyboardInteractive)) - return cmd.Output() + + var stdout bytes.Buffer + cmd.Stdout = &stdout + + stderr, err := cmd.StderrPipe() + if err != nil { + return nil, err + } + + err = cmd.Start() + if err != nil { + return nil, err + } + + in := bufio.NewScanner(stderr) + for in.Scan() { + logger.Log(logger.LevelWarn, "external_auth_hook", "", "%s", in.Text()) + } + + return stdout.Bytes(), cmd.Wait() } func updateUserFromExtAuthResponse(user *User, password, pkey string) {