From a0df97c0df5cccbc82f0db9743b4f017ef0a70f8 Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Sun, 3 Oct 2021 16:05:05 +0000 Subject: [PATCH 1/2] pkg/xtermjs/utils: Fix missing argument in Warnf --- pkg/xtermjs/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/xtermjs/utils.go b/pkg/xtermjs/utils.go index 67484a4..b9e8b96 100644 --- a/pkg/xtermjs/utils.go +++ b/pkg/xtermjs/utils.go @@ -23,7 +23,7 @@ func getConnectionUpgrader( return true } } - logger.Warnf("failed to find '%s' in the list of allowed hostnames ('%s')", requesterHostname) + logger.Warnf("failed to find '%s' in the list of allowed hostnames ('%s')", requesterHostname, allowedHostnames) return false }, HandshakeTimeout: 0, From cff1cff5b505bbe37a77eafc450a196184586718 Mon Sep 17 00:00:00 2001 From: Vladimir Panteleev Date: Tue, 5 Oct 2021 09:53:38 +0000 Subject: [PATCH 2/2] Add configurable HTTP basic authentication --- README.md | 1 + cmd/cloudshell/config.go | 5 +++++ cmd/cloudshell/main.go | 9 ++++++++- cmd/cloudshell/middleware.go | 14 ++++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 91ec7a3..fb9507b 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Configurations can be set via flags or environment variables. To view available | Configuration | Flag | Environment Variable | Default Value | Description | | --- | --- | --- | --- | --- | | Allowed hostnames | `--allowed-hostnames` | `ALLOWED_HOSTNAMES` | `"localhost"` | Comma delimited list of hostnames that are allowed to connect to the websocket | +| Authentication | `--authentication` | `AUTHENTICATION` | `""` | If set, require this *username*:*password* using HTTP Basic Authorization | | Arguments | `--arguments` | `ARGUMENTS` | `"-l"` | Comma delimited list of arguments that should be passed to the target binary | | Command | `--command` | `COMMAND` | `"/bin/bash"` | Absolute path to the binary to run | | Connection error limit | `--connection-error-limit` | `CONNECTION_ERROR_LIMIT` | `10` | Number of times a connection should be re-attempted by the server to the XTerm.js frontend before the connection is considered dead and shut down | diff --git a/cmd/cloudshell/config.go b/cmd/cloudshell/config.go index 83ffd7a..2784de1 100644 --- a/cmd/cloudshell/config.go +++ b/cmd/cloudshell/config.go @@ -14,6 +14,11 @@ var conf = config.Map{ Usage: "comma-delimited list of hostnames that are allowed to connect to the websocket", Shorthand: "H", }, + "authentication": &config.String{ + Default: "", + Usage: "require this username:password using HTTP Basic Authorization", + Shorthand: "A", + }, "arguments": &config.StringSlice{ Default: []string{}, Usage: "comma-delimited list of arguments that should be passed to the terminal command", diff --git a/cmd/cloudshell/main.go b/cmd/cloudshell/main.go index 4b11f67..59dcc3f 100644 --- a/cmd/cloudshell/main.go +++ b/cmd/cloudshell/main.go @@ -41,6 +41,7 @@ func runE(_ *cobra.Command, _ []string) error { connectionErrorLimit := conf.GetInt("connection-error-limit") arguments := conf.GetStringSlice("arguments") allowedHostnames := conf.GetStringSlice("allowed-hostnames") + authentication := conf.GetString("authentication") keepalivePingTimeout := time.Duration(conf.GetInt("keepalive-ping-timeout")) * time.Second maxBufferSizeBytes := conf.GetInt("max-buffer-size-bytes") pathLiveness := conf.GetString("path-liveness") @@ -131,11 +132,17 @@ func runE(_ *cobra.Command, _ []string) error { } }(time.NewTicker(time.Second * 30)) + var handler http.Handler = router + handler = addIncomingRequestLogging(handler) + if authentication != "" { + handler = addAuthentication(handler, authentication) + } + // listen listenOnAddress := fmt.Sprintf("%s:%v", serverAddress, serverPort) server := http.Server{ Addr: listenOnAddress, - Handler: addIncomingRequestLogging(router), + Handler: handler, } log.Infof("starting server on interface:port '%s'...", listenOnAddress) diff --git a/cmd/cloudshell/middleware.go b/cmd/cloudshell/middleware.go index 0011781..14f5bff 100644 --- a/cmd/cloudshell/middleware.go +++ b/cmd/cloudshell/middleware.go @@ -18,3 +18,17 @@ func addIncomingRequestLogging(next http.Handler) http.Handler { createRequestLog(r).Infof("request completed in %vms", float64(duration.Nanoseconds())/1000000) }) } + +func addAuthentication(next http.Handler, authentication string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) + + username, password, ok := r.BasicAuth() + if !ok || username + ":" + password != authentication { + http.Error(w, "Unauthorized", 401) + return + } + + next.ServeHTTP(w, r) + }) +}