From af08b5cd1b09a5e48e5a26a8ca31c1e0e7425299 Mon Sep 17 00:00:00 2001 From: Vano Devium Date: Thu, 2 Jun 2022 21:44:32 +0300 Subject: [PATCH] Auto session storage key (#1767) --- README.md | 3 --- main.go | 6 ------ web/auth.go | 9 ++++++++- web/routes.go | 1 - web/routes_test.go | 14 +++++++------- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index e47d0e2e..412a8828 100644 --- a/README.md +++ b/README.md @@ -105,11 +105,8 @@ Dozzle follows the [12-factor](https://12factor.net/) model. Configurations can | `--filter` | `DOZZLE_FILTER` | `""` | | `--username` | `DOZZLE_USERNAME` | `""` | | `--password` | `DOZZLE_PASSWORD` | `""` | -| `--key` | `DOZZLE_KEY` | `""` | | `--no-analytics` | `DOZZLE_NO_ANALYTICS` | false | -Note: When using username and password `DOZZLE_KEY` is required for session management. - ## Troubleshooting and FAQs
diff --git a/main.go b/main.go index 45cc0a4a..595ce55c 100644 --- a/main.go +++ b/main.go @@ -29,7 +29,6 @@ type args struct { Base string `arg:"env:DOZZLE_BASE" default:"/" help:"sets the base for http router."` Level string `arg:"env:DOZZLE_LEVEL" default:"info" help:"set Dozzle log level. Use debug for more logging."` TailSize int `arg:"env:DOZZLE_TAILSIZE" default:"300" help:"update the initial tail size when fetching logs."` - Key string `arg:"env:DOZZLE_KEY" help:"set a random key for username and password. This is required for auth."` Username string `arg:"env:DOZZLE_USERNAME" help:"sets the username for auth."` Password string `arg:"env:DOZZLE_PASSWORD" help:"sets password for auth"` NoAnalytics bool `arg:"--no-analytics,env:DOZZLE_NO_ANALYTICS" help:"disables anonymous analytics"` @@ -88,10 +87,6 @@ func main() { if args.Username == "" || args.Password == "" { log.Fatalf("Username AND password are required for authentication") } - - if args.Key == "" { - log.Fatalf("Key is required for authentication") - } } config := web.Config{ @@ -99,7 +94,6 @@ func main() { Base: args.Base, Version: version, TailSize: args.TailSize, - Key: args.Key, Username: args.Username, Password: args.Password, } diff --git a/web/auth.go b/web/auth.go index b2f06ad0..013621c2 100644 --- a/web/auth.go +++ b/web/auth.go @@ -1,6 +1,8 @@ package web import ( + "crypto/sha256" + "fmt" "net/http" "time" @@ -17,7 +19,7 @@ const sessionName = "session" func initializeAuth(h *handler) { secured = false if h.config.Username != "" && h.config.Password != "" { - store = sessions.NewCookieStore([]byte(h.config.Key)) + store = sessions.NewCookieStore(generateSessionStorageKey(h.config.Username, h.config.Password)) store.Options.HttpOnly = true store.Options.SameSite = http.SameSiteLaxMode store.Options.MaxAge = 0 @@ -115,3 +117,8 @@ func (h *handler) clearSession(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, h.config.Base, http.StatusTemporaryRedirect) } + +func generateSessionStorageKey(username string, password string) []byte { + key := sha256.Sum256([]byte(fmt.Sprintf("%s:%s", username, password))) + return key[:] +} diff --git a/web/routes.go b/web/routes.go index a822c816..dae77216 100644 --- a/web/routes.go +++ b/web/routes.go @@ -20,7 +20,6 @@ type Config struct { Addr string Version string TailSize int - Key string Username string Password string } diff --git a/web/routes_test.go b/web/routes_test.go index 1ad8bc78..5646497c 100644 --- a/web/routes_test.go +++ b/web/routes_test.go @@ -271,7 +271,7 @@ func Test_createRoutes_redirect_with_auth(t *testing.T) { fs := afero.NewMemMapFs() require.NoError(t, afero.WriteFile(fs, "index.html", []byte("index page"), 0644), "WriteFile should have no error.") - handler := createHandler(nil, afero.NewIOFS(fs), Config{Base: "/foobar", Username: "amir", Password: "password", Key: "key"}) + handler := createHandler(nil, afero.NewIOFS(fs), Config{Base: "/foobar", Username: "amir", Password: "password"}) req, err := http.NewRequest("GET", "/foobar/", nil) require.NoError(t, err, "NewRequest should not return an error.") rr := httptest.NewRecorder() @@ -320,7 +320,7 @@ func Test_createRoutes_version(t *testing.T) { func Test_createRoutes_username_password(t *testing.T) { - handler := createHandler(nil, nil, Config{Base: "/", Username: "amir", Password: "password", Key: "key"}) + handler := createHandler(nil, nil, Config{Base: "/", Username: "amir", Password: "password"}) req, err := http.NewRequest("GET", "/", nil) require.NoError(t, err, "NewRequest should not return an error.") rr := httptest.NewRecorder() @@ -329,7 +329,7 @@ func Test_createRoutes_username_password(t *testing.T) { } func Test_createRoutes_username_password_invalid(t *testing.T) { - handler := createHandler(nil, nil, Config{Base: "/", Username: "amir", Password: "password", Key: "key"}) + handler := createHandler(nil, nil, Config{Base: "/", Username: "amir", Password: "password"}) req, err := http.NewRequest("GET", "/api/logs/stream?id=123", nil) require.NoError(t, err, "NewRequest should not return an error.") rr := httptest.NewRecorder() @@ -338,7 +338,7 @@ func Test_createRoutes_username_password_invalid(t *testing.T) { } func Test_createRoutes_username_password_login_happy(t *testing.T) { - handler := createHandler(nil, nil, Config{Base: "/", Username: "amir", Password: "password", Key: "key"}) + handler := createHandler(nil, nil, Config{Base: "/", Username: "amir", Password: "password"}) body := &bytes.Buffer{} writer := multipart.NewWriter(body) @@ -368,7 +368,7 @@ func Test_createRoutes_username_password_login_happy(t *testing.T) { } func Test_createRoutes_username_password_login_failed(t *testing.T) { - handler := createHandler(nil, nil, Config{Base: "/", Username: "amir", Password: "password", Key: "key"}) + handler := createHandler(nil, nil, Config{Base: "/", Username: "amir", Password: "password"}) body := &bytes.Buffer{} writer := multipart.NewWriter(body) @@ -398,7 +398,7 @@ func Test_createRoutes_username_password_valid_session(t *testing.T) { mockedClient := new(MockedClient) mockedClient.On("FindContainer", "123").Return(docker.Container{ID: "123"}, nil) mockedClient.On("ContainerLogs", mock.Anything, "123", 0).Return(ioutil.NopCloser(strings.NewReader("test data")), io.EOF) - handler := createHandler(mockedClient, nil, Config{Base: "/", Username: "amir", Password: "password", Key: "key"}) + handler := createHandler(mockedClient, nil, Config{Base: "/", Username: "amir", Password: "password"}) // Get cookie first req, err := http.NewRequest("GET", "/api/logs/stream?id=123", nil) @@ -422,7 +422,7 @@ func Test_createRoutes_username_password_invalid_session(t *testing.T) { mockedClient := new(MockedClient) mockedClient.On("FindContainer", "123").Return(docker.Container{ID: "123"}, nil) mockedClient.On("ContainerLogs", mock.Anything, "123", 0).Return(ioutil.NopCloser(strings.NewReader("test data")), io.EOF) - handler := createHandler(mockedClient, nil, Config{Base: "/", Username: "amir", Password: "password", Key: "key"}) + handler := createHandler(mockedClient, nil, Config{Base: "/", Username: "amir", Password: "password"}) req, err := http.NewRequest("GET", "/api/logs/stream?id=123", nil) require.NoError(t, err, "NewRequest should not return an error.") req.AddCookie(&http.Cookie{Name: "session", Value: "baddata"})