From d291e3effe27e6a34d9942e73a060f21f8105085 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 9 Apr 2026 13:13:43 +0200 Subject: [PATCH] test(auth): add failing unit tests for OIDC TOTP enforcement Covers the four states the OIDC TOTP gate must handle: user without TOTP, TOTP enabled with missing passcode, invalid passcode, and valid passcode. The helper function under test does not exist yet, so the package currently fails to compile. Refs GHSA-8jvc-mcx6-r4cg --- pkg/modules/auth/openid/openid_test.go | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/pkg/modules/auth/openid/openid_test.go b/pkg/modules/auth/openid/openid_test.go index a7c739f55..05ade6745 100644 --- a/pkg/modules/auth/openid/openid_test.go +++ b/pkg/modules/auth/openid/openid_test.go @@ -18,12 +18,14 @@ package openid import ( "testing" + "time" "code.vikunja.io/api/pkg/models" "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "github.com/coreos/go-oidc/v3/oidc" + "github.com/pquerna/otp/totp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -420,6 +422,57 @@ func TestMergeClaims(t *testing.T) { }) } +func TestEnforceTOTPIfRequired(t *testing.T) { + // user 10 has TOTP enabled in pkg/db/fixtures/totp.yml with this secret. + const user10Secret = "JBSWY3DPEHPK3PXP" + + t.Run("user without TOTP - no passcode required", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + // user 1 has a totp row but with enabled=false. + u := &user.User{ID: 1} + err := enforceTOTPIfRequired(s, u, "") + require.NoError(t, err) + }) + + t.Run("TOTP enabled - missing passcode returns ErrInvalidTOTPPasscode", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + u := &user.User{ID: 10} + err := enforceTOTPIfRequired(s, u, "") + require.Error(t, err) + assert.True(t, user.IsErrInvalidTOTPPasscode(err)) + }) + + t.Run("TOTP enabled - invalid passcode returns ErrInvalidTOTPPasscode", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + u := &user.User{ID: 10} + err := enforceTOTPIfRequired(s, u, "000000") + require.Error(t, err) + assert.True(t, user.IsErrInvalidTOTPPasscode(err)) + }) + + t.Run("TOTP enabled - valid passcode succeeds", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + passcode, err := totp.GenerateCode(user10Secret, time.Now()) + require.NoError(t, err) + + u := &user.User{ID: 10} + err = enforceTOTPIfRequired(s, u, passcode) + require.NoError(t, err) + }) +} + func TestSyncUserAvatarFromOpenID(t *testing.T) { t.Run("empty picture URL resets openid provider to default", func(t *testing.T) { db.LoadAndAssertFixtures(t)