rc: require authentication to list the remotes with --rc-serve GHSA-mfvx-7rcj-9m5g
With --rc-serve set the root listing enumerated the names of all configured remotes without any authentication. Make the root listing obey the same fail-closed rule as the rest of the rc endpoints: it now requires authentication to be configured or an explicit opt out with --rc-no-auth. Addresses GHSA-mfvx-7rcj-9m5g finding 2.
This commit is contained in:
@@ -329,6 +329,12 @@ func (s *Server) handleOptions(w http.ResponseWriter, r *http.Request, path stri
|
||||
}
|
||||
|
||||
func (s *Server) serveRoot(w http.ResponseWriter, r *http.Request) {
|
||||
// Listing the configured remotes discloses their names so
|
||||
// require auth like the rest of the rc endpoints
|
||||
if !s.noAuth && !s.server.UsingAuth() {
|
||||
writeError(r.URL.Path, nil, w, errors.New("listing the remotes requires authentication to be set up on the rc server or the --rc-no-auth flag"), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
remoteNames := config.GetRemoteNames()
|
||||
sort.Strings(remoteNames)
|
||||
directory := serve.NewDirectory("", s.server.HTMLTemplate())
|
||||
|
||||
@@ -787,6 +787,7 @@ func TestServingRoot(t *testing.T) {
|
||||
opt := newTestOpt()
|
||||
opt.Serve = true
|
||||
opt.Files = testFs
|
||||
opt.NoAuth = true
|
||||
testServer(t, tests, &opt)
|
||||
}
|
||||
|
||||
@@ -800,6 +801,53 @@ func TestServingRootNoFiles(t *testing.T) {
|
||||
opt := newTestOpt()
|
||||
opt.Serve = true
|
||||
opt.Files = ""
|
||||
opt.NoAuth = true
|
||||
testServer(t, tests, &opt)
|
||||
}
|
||||
|
||||
// On a server with no authentication configured and without --rc-no-auth the
|
||||
// remote listing must not disclose the configured remote names.
|
||||
func TestServingRootFailClosed(t *testing.T) {
|
||||
forbidden := regexp.MustCompile(`"status": 403`)
|
||||
tests := []testRun{{
|
||||
Name: "rootlist-star",
|
||||
URL: "*",
|
||||
Status: http.StatusForbidden,
|
||||
Contains: forbidden,
|
||||
}, {
|
||||
Name: "rootlist-empty",
|
||||
URL: "",
|
||||
Status: http.StatusForbidden,
|
||||
Contains: forbidden,
|
||||
}}
|
||||
opt := newTestOpt()
|
||||
opt.Serve = true
|
||||
opt.Files = ""
|
||||
testServer(t, tests, &opt)
|
||||
}
|
||||
|
||||
// With authentication configured the remote listing is available to
|
||||
// authenticated requests only.
|
||||
func TestServingRootWithAuth(t *testing.T) {
|
||||
const user, pass = "user", "pass"
|
||||
tests := []testRun{{
|
||||
Name: "rootlist-authed",
|
||||
URL: "",
|
||||
User: user,
|
||||
Pass: pass,
|
||||
Status: http.StatusOK,
|
||||
Contains: matchRemoteDirListing,
|
||||
}, {
|
||||
Name: "rootlist-unauthed",
|
||||
URL: "",
|
||||
Status: http.StatusUnauthorized,
|
||||
Contains: regexp.MustCompile(`Unauthorized`),
|
||||
}}
|
||||
opt := newTestOpt()
|
||||
opt.Serve = true
|
||||
opt.Files = ""
|
||||
opt.Auth.BasicUser = user
|
||||
opt.Auth.BasicPass = pass
|
||||
testServer(t, tests, &opt)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user