Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Require auth by default, add --no-auth flag #61

Merged
merged 1 commit into from
Mar 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Flags:
-h, --help help for rest-server
--listen string listen address (default ":8000")
--log string log HTTP requests in the combined log format
--no-auth disable .htpasswd authentication
--path string data directory (default "/tmp/restic")
--private-repos users can only access their private repo
--prometheus enable Prometheus metrics
Expand All @@ -77,20 +78,22 @@ Flags:

```

By default the server persists backup data in `/tmp/restic`. Start the server with a custom persistence directory:
By default the server persists backup data in `/tmp/restic`. To start the server with a custom persistence directory and with authentication disabled:

```
rest-server --path /user/home/backup
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.

NOTE: Without a valid `.htaccess` file, the server will not authenticate users (it prints "Authentication disabled upon startup"), in which case anyone who can access the server will be able to back up to it.

```
htpasswd -B -c .htpasswd username
```

If you want to disable authentication, you must add the `--no-auth` flag. If this flag is not specified and the `.htpasswd` cannot be opened, rest-server will refuse to start.

NOTE: In older versions of rest-server (up to 0.9.7), this flag does not exist and the server disables authentication if `.htpasswd` is missing or cannot be opened.

By default the server uses HTTP protocol. This is not very secure since with Basic Authentication, username and passwords will travel in cleartext in every request. In order to enable TLS support just add the `--tls` argument and add a private and public key at the root of your persistence directory. You may also specify private and public keys by `--tls-cert` and `--tls-key`.

Signed certificate is required by the restic backend, but if you just want to test the feature you can generate unsigned keys with the following commands:
Expand Down
28 changes: 19 additions & 9 deletions cmd/rest-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func init() {
flags.BoolVar(&restserver.Config.TLS, "tls", restserver.Config.TLS, "turn on TLS support")
flags.StringVar(&restserver.Config.TLSCert, "tls-cert", restserver.Config.TLSCert, "TLS certificate path")
flags.StringVar(&restserver.Config.TLSKey, "tls-key", restserver.Config.TLSKey, "TLS key path")
flags.BoolVar(&restserver.Config.NoAuth, "no-auth", restserver.Config.NoAuth, "disable .htpasswd authentication")
flags.BoolVar(&restserver.Config.AppendOnly, "append-only", restserver.Config.AppendOnly, "enable append only mode")
flags.BoolVar(&restserver.Config.PrivateRepos, "private-repos", restserver.Config.PrivateRepos, "users can only access their private repo")
flags.BoolVar(&restserver.Config.Prometheus, "prometheus", restserver.Config.Prometheus, "enable Prometheus metrics")
Expand Down Expand Up @@ -64,6 +65,21 @@ func tlsSettings() (bool, string, string, error) {
return enabledTLS, key, cert, nil
}

func getHandler() (http.Handler, error) {
mux := restserver.NewMux()
if restserver.Config.NoAuth {
log.Println("Authentication disabled")
return mux, nil
}

log.Println("Authentication enabled")
htpasswdFile, err := restserver.NewHtpasswdFromFile(filepath.Join(restserver.Config.Path, ".htpasswd"))
if err != nil {
return nil, fmt.Errorf("cannot load .htpasswd (use --no-auth to disable): %v", err)
}
return restserver.AuthHandler(htpasswdFile, mux), nil
}

func runRoot(cmd *cobra.Command, args []string) error {
if restserver.Config.Version {
fmt.Printf("rest-server %s compiled with %v on %v/%v\n", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
Expand All @@ -86,16 +102,9 @@ func runRoot(cmd *cobra.Command, args []string) error {
defer pprof.StopCPUProfile()
}

mux := restserver.NewMux()

var handler http.Handler
htpasswdFile, err := restserver.NewHtpasswdFromFile(filepath.Join(restserver.Config.Path, ".htpasswd"))
handler, err := getHandler()
if err != nil {
handler = mux
log.Println("Authentication disabled")
} else {
handler = restserver.AuthHandler(htpasswdFile, mux)
log.Println("Authentication enabled")
log.Fatalf("error: %v", err)
}

if restserver.Config.PrivateRepos {
Expand All @@ -122,6 +131,7 @@ func runRoot(cmd *cobra.Command, args []string) error {

return err
}

func main() {
if err := cmdRoot.Execute(); err != nil {
log.Fatalf("error: %v", err)
Expand Down
45 changes: 45 additions & 0 deletions cmd/rest-server/main_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package main

import (
"io/ioutil"
"os"
"path/filepath"
"testing"

restserver "github.com/restic/rest-server"
Expand Down Expand Up @@ -71,3 +74,45 @@ func TestTLSSettings(t *testing.T) {
})
}
}

func TestGetHandler(t *testing.T) {
// Save and restore config
defaultConfig := restserver.Config
defer func() { restserver.Config = defaultConfig }()

dir, err := ioutil.TempDir("", "rest-server-test")
if err != nil {
t.Fatal(err)
}
defer os.Remove(dir)
restserver.Config.Path = dir

// With NoAuth = false and no .htpasswd
restserver.Config.NoAuth = false // default
_, err = getHandler()
if err == nil {
t.Errorf("NoAuth=false: expected error, got nil")
}

// With NoAuth = true and no .htpasswd
restserver.Config.NoAuth = true
_, err = getHandler()
if err != nil {
t.Errorf("NoAuth=true: expected no error, got %v", err)
}

// Create .htpasswd
htpasswd := filepath.Join(dir, ".htpasswd")
err = ioutil.WriteFile(htpasswd, []byte(""), 0644)
if err != nil {
t.Fatal(err)
}
defer os.Remove(htpasswd)

// With NoAuth = false and with .htpasswd
restserver.Config.NoAuth = false // default
_, err = getHandler()
if err != nil {
t.Errorf("NoAuth=false with .htpasswd: expected no error, got %v", err)
}
}
1 change: 1 addition & 0 deletions mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var Config = struct {
TLSKey string
TLSCert string
TLS bool
NoAuth bool
AppendOnly bool
PrivateRepos bool
Prometheus bool
Expand Down