package auth_test import ( "context" "testing" "time" "github.com/coreos/go-oidc/v3/oidc" "github.com/stretchr/testify/require" "github.com/fatedier/frp/pkg/auth" v1 "github.com/fatedier/frp/pkg/config/v1" "github.com/fatedier/frp/pkg/msg" ) type mockTokenVerifier struct{} func (m *mockTokenVerifier) Verify(ctx context.Context, subject string) (*oidc.IDToken, error) { return &oidc.IDToken{ Subject: subject, }, nil } func TestPingWithEmptySubjectFromLoginFails(t *testing.T) { r := require.New(t) consumer := auth.NewOidcAuthVerifier([]v1.AuthScope{v1.AuthScopeHeartBeats}, &mockTokenVerifier{}) err := consumer.VerifyPing(&msg.Ping{ PrivilegeKey: "ping-without-login", Timestamp: time.Now().UnixMilli(), }) r.Error(err) r.Contains(err.Error(), "received different OIDC subject in login and ping") } func TestPingAfterLoginWithNewSubjectSucceeds(t *testing.T) { r := require.New(t) consumer := auth.NewOidcAuthVerifier([]v1.AuthScope{v1.AuthScopeHeartBeats}, &mockTokenVerifier{}) err := consumer.VerifyLogin(&msg.Login{ PrivilegeKey: "ping-after-login", }) r.NoError(err) err = consumer.VerifyPing(&msg.Ping{ PrivilegeKey: "ping-after-login", Timestamp: time.Now().UnixMilli(), }) r.NoError(err) } func TestPingAfterLoginWithDifferentSubjectFails(t *testing.T) { r := require.New(t) consumer := auth.NewOidcAuthVerifier([]v1.AuthScope{v1.AuthScopeHeartBeats}, &mockTokenVerifier{}) err := consumer.VerifyLogin(&msg.Login{ PrivilegeKey: "login-with-first-subject", }) r.NoError(err) err = consumer.VerifyPing(&msg.Ping{ PrivilegeKey: "ping-with-different-subject", Timestamp: time.Now().UnixMilli(), }) r.Error(err) r.Contains(err.Error(), "received different OIDC subject in login and ping") }