diff --git a/internal/hub/hub.go b/internal/hub/hub.go index 89fb4a9..890abae 100644 --- a/internal/hub/hub.go +++ b/internal/hub/hub.go @@ -175,35 +175,31 @@ func (h *Hub) registerCronJobs(_ *core.ServeEvent) error { // custom middlewares func (h *Hub) registerMiddlewares(se *core.ServeEvent) { + // authorizes request with user matching the provided email + authorizeRequestWithEmail := func(e *core.RequestEvent, email string) (err error) { + if e.Auth != nil || email == "" { + return e.Next() + } + isAuthRefresh := e.Request.URL.Path == "/api/collections/users/auth-refresh" && e.Request.Method == http.MethodPost + e.Auth, err = e.App.FindFirstRecordByData("users", "email", email) + if err != nil || !isAuthRefresh { + return e.Next() + } + // auth refresh endpoint, make sure token is set in header + token, _ := e.Auth.NewAuthToken() + e.Request.Header.Set("Authorization", token) + return e.Next() + } + // authenticate with trusted header + if autoLogin, _ := GetEnv("AUTO_LOGIN"); autoLogin != "" { + se.Router.BindFunc(func(e *core.RequestEvent) error { + return authorizeRequestWithEmail(e, autoLogin) + }) + } // authenticate with trusted header if trustedHeader, _ := GetEnv("TRUSTED_AUTH_HEADER"); trustedHeader != "" { se.Router.BindFunc(func(e *core.RequestEvent) error { - if e.Auth != nil { - return e.Next() - } - trustedEmail := e.Request.Header.Get(trustedHeader) - if trustedEmail == "" { - return e.Next() - } - isAuthRefresh := e.Request.URL.Path == "/api/collections/users/auth-refresh" && e.Request.Method == http.MethodPost - if !isAuthRefresh { - authRecord, err := e.App.FindAuthRecordByEmail("users", trustedEmail) - if err == nil { - e.Auth = authRecord - } - return e.Next() - } - // if auth refresh endpoint, find user record directly and generate token - user, err := e.App.FindFirstRecordByData("users", "email", trustedEmail) - if err != nil { - return e.Next() - } - e.Auth = user - // need to set the authorization header for the client sdk to pick up the token - if token, err := user.NewAuthToken(); err == nil { - e.Request.Header.Set("Authorization", token) - } - return e.Next() + return authorizeRequestWithEmail(e, e.Request.Header.Get(trustedHeader)) }) } } diff --git a/internal/hub/hub_test.go b/internal/hub/hub_test.go index 47b5300..2b8762e 100644 --- a/internal/hub/hub_test.go +++ b/internal/hub/hub_test.go @@ -712,6 +712,60 @@ func TestCreateUserEndpointAvailability(t *testing.T) { }) } +func TestAutoLoginMiddleware(t *testing.T) { + var hubs []*beszelTests.TestHub + + defer func() { + defer os.Unsetenv("AUTO_LOGIN") + for _, hub := range hubs { + hub.Cleanup() + } + }() + + os.Setenv("AUTO_LOGIN", "user@test.com") + + testAppFactory := func(t testing.TB) *pbTests.TestApp { + hub, _ := beszelTests.NewTestHub(t.TempDir()) + hubs = append(hubs, hub) + hub.StartHub() + return hub.TestApp + } + + scenarios := []beszelTests.ApiScenario{ + { + Name: "GET /getkey - without auto login should fail", + Method: http.MethodGet, + URL: "/api/beszel/getkey", + ExpectedStatus: 401, + ExpectedContent: []string{"requires valid"}, + TestAppFactory: testAppFactory, + }, + { + Name: "GET /getkey - with auto login should fail if no matching user", + Method: http.MethodGet, + URL: "/api/beszel/getkey", + ExpectedStatus: 401, + ExpectedContent: []string{"requires valid"}, + TestAppFactory: testAppFactory, + }, + { + Name: "GET /getkey - with auto login should succeed", + Method: http.MethodGet, + URL: "/api/beszel/getkey", + ExpectedStatus: 200, + ExpectedContent: []string{"\"key\":", "\"v\":"}, + TestAppFactory: testAppFactory, + BeforeTestFunc: func(t testing.TB, app *pbTests.TestApp, e *core.ServeEvent) { + beszelTests.CreateUser(app, "user@test.com", "password123") + }, + }, + } + + for _, scenario := range scenarios { + scenario.Test(t) + } +} + func TestTrustedHeaderMiddleware(t *testing.T) { var hubs []*beszelTests.TestHub diff --git a/supplemental/CHANGELOG.md b/supplemental/CHANGELOG.md index f719a84..323f856 100644 --- a/supplemental/CHANGELOG.md +++ b/supplemental/CHANGELOG.md @@ -1,5 +1,9 @@ ## 0.12.8 +- Add `TRUSTED_AUTH_HEADER` environment variable for authentication forwarding. (#399) + +- Add `AUTO_LOGIN` environment variable for automatic login. (#399) + - Add FreeBSD support for agent install script and update command. ## 0.12.7