rc: methods marked as AuthRequired need auth unless --rc-no-auth
Methods which can read or mutate external storage will require authorisation - enforce this. This can be overidden by `--rc-no-auth`.
This commit is contained in:
parent
181267e20e
commit
fa0a9653d2
8 changed files with 102 additions and 4 deletions
|
@ -106,6 +106,7 @@ type Server struct {
|
||||||
httpServer *http.Server
|
httpServer *http.Server
|
||||||
basicPassHashed string
|
basicPassHashed string
|
||||||
useSSL bool // if server is configured for SSL/TLS
|
useSSL bool // if server is configured for SSL/TLS
|
||||||
|
usingAuth bool // set if authentication is configured
|
||||||
}
|
}
|
||||||
|
|
||||||
// singleUserProvider provides the encrypted password for a single user
|
// singleUserProvider provides the encrypted password for a single user
|
||||||
|
@ -143,6 +144,7 @@ func NewServer(handler http.Handler, opt *Options) *Server {
|
||||||
}
|
}
|
||||||
authenticator := auth.NewBasicAuthenticator(s.Opt.Realm, secretProvider)
|
authenticator := auth.NewBasicAuthenticator(s.Opt.Realm, secretProvider)
|
||||||
handler = auth.JustCheck(authenticator, handler.ServeHTTP)
|
handler = auth.JustCheck(authenticator, handler.ServeHTTP)
|
||||||
|
s.usingAuth = true
|
||||||
}
|
}
|
||||||
|
|
||||||
s.useSSL = s.Opt.SslKey != ""
|
s.useSSL = s.Opt.SslKey != ""
|
||||||
|
@ -255,3 +257,8 @@ func (s *Server) URL() string {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s://%s/", proto, addr)
|
return fmt.Sprintf("%s://%s/", proto, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UsingAuth returns true if authentication is required
|
||||||
|
func (s *Server) UsingAuth() bool {
|
||||||
|
return s.usingAuth
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,19 @@ implementing browser based GUIs for rclone functions.
|
||||||
|
|
||||||
Default Off.
|
Default Off.
|
||||||
|
|
||||||
|
### --rc-no-auth
|
||||||
|
|
||||||
|
By default rclone will require authorisation to have been set up on
|
||||||
|
the rc interface in order to use any methods which access any rclone
|
||||||
|
remotes. Eg `operations/list` is denied as it involved creating a
|
||||||
|
remote as is `sync/copy`.
|
||||||
|
|
||||||
|
If this is set then no authorisation will be required on the server to
|
||||||
|
use these methods. The alternative is to use `--rc-user` and
|
||||||
|
`--rc-pass` and use these credentials in the request.
|
||||||
|
|
||||||
|
Default Off.
|
||||||
|
|
||||||
## Accessing the remote control via the rclone rc command
|
## Accessing the remote control via the rclone rc command
|
||||||
|
|
||||||
Rclone itself implements the remote control protocol in its `rclone
|
Rclone itself implements the remote control protocol in its `rclone
|
||||||
|
|
|
@ -17,6 +17,16 @@ func init() {
|
||||||
Help: `
|
Help: `
|
||||||
This echoes the input parameters to the output parameters for testing
|
This echoes the input parameters to the output parameters for testing
|
||||||
purposes. It can be used to check that rclone is still alive and to
|
purposes. It can be used to check that rclone is still alive and to
|
||||||
|
check that parameter passing is working properly.`,
|
||||||
|
})
|
||||||
|
Add(Call{
|
||||||
|
Path: "rc/noopauth",
|
||||||
|
AuthRequired: true,
|
||||||
|
Fn: rcNoop,
|
||||||
|
Title: "Echo the input to the output parameters requiring auth",
|
||||||
|
Help: `
|
||||||
|
This echoes the input parameters to the output parameters for testing
|
||||||
|
purposes. It can be used to check that rclone is still alive and to
|
||||||
check that parameter passing is working properly.`,
|
check that parameter passing is working properly.`,
|
||||||
})
|
})
|
||||||
Add(Call{
|
Add(Call{
|
||||||
|
|
|
@ -21,6 +21,7 @@ type Options struct {
|
||||||
Enabled bool // set to enable the server
|
Enabled bool // set to enable the server
|
||||||
Serve bool // set to serve files from remotes
|
Serve bool // set to serve files from remotes
|
||||||
Files string // set to enable serving files locally
|
Files string // set to enable serving files locally
|
||||||
|
NoAuth bool // set to disable auth checks on AuthRequired methods
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultOpt is the default values used for Options
|
// DefaultOpt is the default values used for Options
|
||||||
|
|
|
@ -19,5 +19,6 @@ func AddFlags(flagSet *pflag.FlagSet) {
|
||||||
flags.BoolVarP(flagSet, &Opt.Enabled, "rc", "", false, "Enable the remote control server.")
|
flags.BoolVarP(flagSet, &Opt.Enabled, "rc", "", false, "Enable the remote control server.")
|
||||||
flags.StringVarP(flagSet, &Opt.Files, "rc-files", "", "", "Path to local files to serve on the HTTP server.")
|
flags.StringVarP(flagSet, &Opt.Files, "rc-files", "", "", "Path to local files to serve on the HTTP server.")
|
||||||
flags.BoolVarP(flagSet, &Opt.Serve, "rc-serve", "", false, "Enable the serving of remote objects.")
|
flags.BoolVarP(flagSet, &Opt.Serve, "rc-serve", "", false, "Enable the serving of remote objects.")
|
||||||
|
flags.BoolVarP(flagSet, &Opt.NoAuth, "rc-no-auth", "", false, "Don't require auth for certain methods.")
|
||||||
httpflags.AddFlagsPrefix(flagSet, "rc-", &Opt.HTTPOptions)
|
httpflags.AddFlagsPrefix(flagSet, "rc-", &Opt.HTTPOptions)
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,12 @@ func (s *Server) handlePost(w http.ResponseWriter, r *http.Request, path string)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check to see if it requires authorisation
|
||||||
|
if !s.opt.NoAuth && call.AuthRequired && !s.UsingAuth() {
|
||||||
|
writeError(path, in, w, errors.Errorf("authentication must be set up on the rc server to use %q or the --rc-no-auth flag must be in use", path), http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if it is async or not
|
// Check to see if it is async or not
|
||||||
isAsync, err := in.GetBool("_async")
|
isAsync, err := in.GetBool("_async")
|
||||||
if rc.NotErrParamNotFound(err) {
|
if rc.NotErrParamNotFound(err) {
|
||||||
|
|
|
@ -537,6 +537,65 @@ func TestNoServe(t *testing.T) {
|
||||||
testServer(t, tests, &opt)
|
testServer(t, tests, &opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAuthRequired(t *testing.T) {
|
||||||
|
tests := []testRun{{
|
||||||
|
Name: "auth",
|
||||||
|
URL: "rc/noopauth",
|
||||||
|
Method: "POST",
|
||||||
|
Body: `{}`,
|
||||||
|
ContentType: "application/javascript",
|
||||||
|
Status: http.StatusForbidden,
|
||||||
|
Expected: `{
|
||||||
|
"error": "authentication must be set up on the rc server to use \"rc/noopauth\" or the --rc-no-auth flag must be in use",
|
||||||
|
"input": {},
|
||||||
|
"path": "rc/noopauth",
|
||||||
|
"status": 403
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
opt := newTestOpt()
|
||||||
|
opt.Serve = false
|
||||||
|
opt.Files = ""
|
||||||
|
opt.NoAuth = false
|
||||||
|
testServer(t, tests, &opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoAuth(t *testing.T) {
|
||||||
|
tests := []testRun{{
|
||||||
|
Name: "auth",
|
||||||
|
URL: "rc/noopauth",
|
||||||
|
Method: "POST",
|
||||||
|
Body: `{}`,
|
||||||
|
ContentType: "application/javascript",
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Expected: "{}\n",
|
||||||
|
}}
|
||||||
|
opt := newTestOpt()
|
||||||
|
opt.Serve = false
|
||||||
|
opt.Files = ""
|
||||||
|
opt.NoAuth = true
|
||||||
|
testServer(t, tests, &opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithUserPass(t *testing.T) {
|
||||||
|
tests := []testRun{{
|
||||||
|
Name: "auth",
|
||||||
|
URL: "rc/noopauth",
|
||||||
|
Method: "POST",
|
||||||
|
Body: `{}`,
|
||||||
|
ContentType: "application/javascript",
|
||||||
|
Status: http.StatusOK,
|
||||||
|
Expected: "{}\n",
|
||||||
|
}}
|
||||||
|
opt := newTestOpt()
|
||||||
|
opt.Serve = false
|
||||||
|
opt.Files = ""
|
||||||
|
opt.NoAuth = false
|
||||||
|
opt.HTTPOptions.BasicUser = "user"
|
||||||
|
opt.HTTPOptions.BasicPass = "pass"
|
||||||
|
testServer(t, tests, &opt)
|
||||||
|
}
|
||||||
|
|
||||||
func TestRCAsync(t *testing.T) {
|
func TestRCAsync(t *testing.T) {
|
||||||
tests := []testRun{{
|
tests := []testRun{{
|
||||||
Name: "ok",
|
Name: "ok",
|
||||||
|
|
|
@ -19,6 +19,7 @@ type Call struct {
|
||||||
Path string // path to activate this RC
|
Path string // path to activate this RC
|
||||||
Fn Func `json:"-"` // function to call
|
Fn Func `json:"-"` // function to call
|
||||||
Title string // help for the function
|
Title string // help for the function
|
||||||
|
AuthRequired bool // if set then this call requires authorisation to be set
|
||||||
Help string // multi-line markdown formatted help
|
Help string // multi-line markdown formatted help
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue