serve http/webdav: add --user --pass authentication #1802

This commit is contained in:
Nick Craig-Wood 2018-02-14 23:14:14 +00:00
parent 221a8a9c5d
commit cc9d7156e4

View file

@ -14,13 +14,19 @@ import (
// Globals // Globals
var ( var (
bindAddress = "localhost:8080" bindAddress = "localhost:8080"
htPasswdFile string htPasswdFile = ""
realm = "rclone"
basicUser = ""
basicPass = ""
) )
// AddFlags adds the http server specific flags // AddFlags adds the http server specific flags
func AddFlags(flagSet *pflag.FlagSet) { func AddFlags(flagSet *pflag.FlagSet) {
flagSet.StringVarP(&bindAddress, "addr", "", bindAddress, "IPaddress:Port to bind server to.") flagSet.StringVarP(&bindAddress, "addr", "", bindAddress, "IPaddress:Port to bind server to.")
flagSet.StringVarP(&htPasswdFile, "htpasswd", "", htPasswdFile, "File to use for htpasswd authentication.") flagSet.StringVarP(&htPasswdFile, "htpasswd", "", htPasswdFile, "File to use for htpasswd authentication.")
flagSet.StringVarP(&realm, "realm", "", realm, "Realm name for authentication.")
flagSet.StringVarP(&basicUser, "user", "", basicUser, "User name for authentication.")
flagSet.StringVarP(&basicPass, "pass", "", basicPass, "Password for authentication.")
} }
// Help contains text describing the http server to add to the command // Help contains text describing the http server to add to the command
@ -32,6 +38,13 @@ Use --addr to specify which IP address and port the server should
listen on, eg --addr 1.2.3.4:8000 or --addr :8080 to listen to all listen on, eg --addr 1.2.3.4:8000 or --addr :8080 to listen to all
IPs. By default it only listens on localhost. IPs. By default it only listens on localhost.
#### Authentication
By default this will serve files without needing a login.
You can either use an htpasswd file which can take lots of users, or
set a single username and password with the --user and --pass flags.
Use --htpasswd /path/to/htpasswd to provide an htpasswd file. This is Use --htpasswd /path/to/htpasswd to provide an htpasswd file. This is
in standard apache format and supports MD5, SHA1 and BCrypt for basic in standard apache format and supports MD5, SHA1 and BCrypt for basic
authentication. Bcrypt is recommended. authentication. Bcrypt is recommended.
@ -41,27 +54,47 @@ To create an htpasswd file:
touch htpasswd touch htpasswd
htpasswd -B htpasswd user htpasswd -B htpasswd user
htpasswd -B htpasswd anotherUser htpasswd -B htpasswd anotherUser
`
Use --realm to set the authentication realm.`
// Server contains info about the running http server // Server contains info about the running http server
type Server struct { type Server struct {
bindAddress string bindAddress string
httpServer *http.Server httpServer *http.Server
basicUser string
basicPassHashed string
}
// singleUserProvider provides the encrypted password for a single user
func (s *Server) singleUserProvider(user, realm string) string {
if user == s.basicUser {
return s.basicPassHashed
}
return ""
} }
// NewServer creates an http server // NewServer creates an http server
func NewServer(handler http.Handler) *Server { func NewServer(handler http.Handler) *Server {
// Use htpasswd if required on everything
if htPasswdFile != "" {
fs.Infof(nil, "Using %q as htpasswd storage", htPasswdFile)
secretProvider := auth.HtpasswdFileProvider(htPasswdFile)
authenticator := auth.NewBasicAuthenticator("rclone", secretProvider)
handler = auth.JustCheck(authenticator, handler.ServeHTTP)
}
s := &Server{ s := &Server{
bindAddress: bindAddress, bindAddress: bindAddress,
} }
// Use htpasswd if required on everything
if htPasswdFile != "" || basicUser != "" {
var secretProvider auth.SecretProvider
if htPasswdFile != "" {
fs.Infof(nil, "Using %q as htpasswd storage", htPasswdFile)
secretProvider = auth.HtpasswdFileProvider(htPasswdFile)
} else {
fs.Infof(nil, "Using --user %s --pass XXXX as authenticated user", basicUser)
s.basicUser = basicUser
s.basicPassHashed = string(auth.MD5Crypt([]byte(basicPass), []byte("dlPL2MqE"), []byte("$1$")))
secretProvider = s.singleUserProvider
}
authenticator := auth.NewBasicAuthenticator(realm, secretProvider)
handler = auth.JustCheck(authenticator, handler.ServeHTTP)
}
// FIXME make a transport? // FIXME make a transport?
s.httpServer = &http.Server{ s.httpServer = &http.Server{
Addr: s.bindAddress, Addr: s.bindAddress,