From 3903ed000c4b031e406493813b628534c656cbac Mon Sep 17 00:00:00 2001 From: Drayton Munster Date: Fri, 25 Mar 2022 15:39:20 -0400 Subject: [PATCH] Add configurable htpasswd location --- README.md | 38 ++++++++++++++++++---------------- changelog/unreleased/issue-187 | 6 ++++++ cmd/rest-server/main.go | 1 + cmd/rest-server/main_test.go | 16 ++++++++++++++ docker/entrypoint.sh | 2 +- handlers.go | 1 + mux.go | 10 ++++++--- 7 files changed, 52 insertions(+), 22 deletions(-) create mode 100644 changelog/unreleased/issue-187 diff --git a/README.md b/README.md index 59c6e51..02fbf8a 100644 --- a/README.md +++ b/README.md @@ -32,23 +32,24 @@ Usage: rest-server [flags] Flags: - --append-only enable append only mode - --cpu-profile string write CPU profile to file - --debug output debug messages - -h, --help help for rest-server - --listen string listen address (default ":8000") - --log string log HTTP requests in the combined log format - --max-size int the maximum size of the repository in bytes - --no-auth disable .htpasswd authentication - --no-verify-upload do not verify the integrity of uploaded data. DO NOT enable unless the rest-server runs on a very low-power device - --path string data directory (default "/tmp/restic") - --private-repos users can only access their private repo - --prometheus enable Prometheus metrics - --prometheus-no-auth disable auth for Prometheus /metrics endpoint - --tls turn on TLS support - --tls-cert string TLS certificate path - --tls-key string TLS key path - -v, --version version for rest-server + --append-only enable append only mode + --cpu-profile string write CPU profile to file + --debug output debug messages + -h, --help help for rest-server + --htpasswd-file string location of .htpasswd file (default: "/.htpasswd") + --listen string listen address (default ":8000") + --log filename write HTTP requests in the combined log format to the specified filename + --max-size int the maximum size of the repository in bytes + --no-auth disable .htpasswd authentication + --no-verify-upload do not verify the integrity of uploaded data. DO NOT enable unless the rest-server runs on a very low-power device + --path string data directory (default "/tmp/restic") + --private-repos users can only access their private repo + --prometheus enable Prometheus metrics + --prometheus-no-auth disable auth for Prometheus /metrics endpoint + --tls turn on TLS support + --tls-cert string TLS certificate path + --tls-key string TLS key path + -v, --version version for rest-server ``` By default the server persists backup data in the OS temporary directory (`/tmp/restic` on Linux/BSD and others, in `%TEMP%\\restic` in Windows, etc). **If `rest-server` is launched using the default path, all backups will be lost**. To start the server with a custom persistence directory and with authentication disabled: @@ -57,7 +58,7 @@ By default the server persists backup data in the OS temporary directory (`/tmp/ rest-server --path /user/home/backup --no-auth ``` -To authenticate users (for access to the rest-server), the server supports using a `.htpasswd` file to specify users. You can create such a file at the root of the persistence directory by executing the following command (note that you need the `htpasswd` program from Apache's http-tools). In order to append new user to the file, just omit the `-c` argument. Only bcrypt and SHA encryption methods are supported, so use -B (very secure) or -s (insecure by today's standards) when adding/changing passwords. +To authenticate users (for access to the rest-server), the server supports using a `.htpasswd` file to specify users. By default, the server looks for this file at the root of the persistence directory. You can create such a file by executing the following command (note that you need the `htpasswd` program from Apache's http-tools). In order to append new user to the file, just omit the `-c` argument. Only bcrypt and SHA encryption methods are supported, so use -B (very secure) or -s (insecure by today's standards) when adding/changing passwords. ```sh htpasswd -B -c .htpasswd username @@ -104,6 +105,7 @@ Note that: - **contrary to the defaults** of `rest-server`, the persistent data volume is located to `/data`. - By default, the image uses authentication. To turn it off, set environment variable `DISABLE_AUTHENTICATION` to any value. +- By default, the image loads the `.htpasswd` file from the persistent data volume (i.e. from `/data/.htpasswd`). To change the location of this file, set the environment variable `PASSWORD_FILE` to the path of the `.htpasswd` file. - It's suggested to set a container name to more easily manage users (`--name` parameter to `docker run`). - You can set environment variable `OPTIONS` to any extra flags you'd like to pass to rest-server. diff --git a/changelog/unreleased/issue-187 b/changelog/unreleased/issue-187 new file mode 100644 index 0000000..e47b0fd --- /dev/null +++ b/changelog/unreleased/issue-187 @@ -0,0 +1,6 @@ +Feature: Allow configurable location for .htpasswd file (in present tense) + +Added the ability for a user to change the location of the .htpasswd file with the --htpasswd-file argument. + +https://github.com/restic/restic/issues/187 +https://github.com/restic/restic/pull/188 \ No newline at end of file diff --git a/cmd/rest-server/main.go b/cmd/rest-server/main.go index 4287b97..8ed850b 100644 --- a/cmd/rest-server/main.go +++ b/cmd/rest-server/main.go @@ -47,6 +47,7 @@ func init() { flags.StringVar(&server.TLSCert, "tls-cert", server.TLSCert, "TLS certificate path") flags.StringVar(&server.TLSKey, "tls-key", server.TLSKey, "TLS key path") flags.BoolVar(&server.NoAuth, "no-auth", server.NoAuth, "disable .htpasswd authentication") + flags.StringVar(&server.HtpasswdPath, "htpasswd-file", server.HtpasswdPath, "location of .htpasswd file (default: \"/.htpasswd)\"") flags.BoolVar(&server.NoVerifyUpload, "no-verify-upload", server.NoVerifyUpload, "do not verify the integrity of uploaded data. DO NOT enable unless the rest-server runs on a very low-power device") flags.BoolVar(&server.AppendOnly, "append-only", server.AppendOnly, "enable append only mode") diff --git a/cmd/rest-server/main_test.go b/cmd/rest-server/main_test.go index 685f4bf..90d4879 100644 --- a/cmd/rest-server/main_test.go +++ b/cmd/rest-server/main_test.go @@ -100,6 +100,22 @@ func TestGetHandler(t *testing.T) { t.Errorf("NoAuth=true: expected no error, got %v", err) } + // With NoAuth = true and custom .htpasswd + htpFile, err := ioutil.TempFile(dir, "custom") + if err != nil { + t.Fatal(err) + } + defer func() { + err := os.Remove(htpFile.Name()) + if err != nil { + t.Fatal(err) + } + }() + _, err = getHandler(&restserver.Server{HtpasswdPath: htpFile.Name()}) + if err != nil { + t.Errorf("NoAuth=false with custom htpasswd: expected no error, got %v", err) + } + // Create .htpasswd htpasswd := filepath.Join(dir, ".htpasswd") err = ioutil.WriteFile(htpasswd, []byte(""), 0644) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 583a838..b7dcef3 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -16,4 +16,4 @@ else fi fi -exec rest-server --path "$DATA_DIRECTORY" $OPTIONS +exec rest-server --path "$DATA_DIRECTORY" --htpasswd-file "$PASSWORD_FILE" $OPTIONS diff --git a/handlers.go b/handlers.go index 9df6adf..f1f3954 100644 --- a/handlers.go +++ b/handlers.go @@ -15,6 +15,7 @@ import ( // Server encapsulates the rest-server's settings and repo management logic type Server struct { Path string + HtpasswdPath string Listen string Log string CPUProfile string diff --git a/mux.go b/mux.go index 6b4ad4c..fd3382c 100644 --- a/mux.go +++ b/mux.go @@ -60,10 +60,14 @@ func (s *Server) wrapMetricsAuth(f http.HandlerFunc) http.HandlerFunc { func NewHandler(server *Server) (http.Handler, error) { if !server.NoAuth { var err error - server.htpasswdFile, err = NewHtpasswdFromFile(filepath.Join(server.Path, ".htpasswd")) - if err != nil { - return nil, fmt.Errorf("cannot load .htpasswd (use --no-auth to disable): %v", err) + if server.HtpasswdPath == "" { + server.HtpasswdPath = filepath.Join(server.Path, ".htpasswd") } + server.htpasswdFile, err = NewHtpasswdFromFile(server.HtpasswdPath) + if err != nil { + return nil, fmt.Errorf("cannot load %s (use --no-auth to disable): %v", server.HtpasswdPath, err) + } + log.Printf("Loaded htpasswd file: %s", server.HtpasswdPath) } const GiB = 1024 * 1024 * 1024