From fce35c4b7f954202f7084b2dd2bc1b614c631481 Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Fri, 12 Jun 2026 19:31:30 +0300 Subject: [PATCH] skip JWT group sync for local Dex user --- management/server/account.go | 6 +++++- management/server/account_test.go | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/management/server/account.go b/management/server/account.go index f16717857..e7fcad9d1 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -28,6 +28,7 @@ import ( nbdns "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/formatter/hook" + "github.com/netbirdio/netbird/idp/dex" "github.com/netbirdio/netbird/management/internals/controllers/network_map" nbconfig "github.com/netbirdio/netbird/management/internals/server/config" "github.com/netbirdio/netbird/management/server/account" @@ -1588,7 +1589,10 @@ func (am *DefaultAccountManager) updateUserAuthWithSingleMode(ctx context.Contex // and propagates changes to peers if group propagation is enabled. // requires userAuth to have been ValidateAndParseToken and EnsureUserAccessByJWTGroups by the AuthManager func (am *DefaultAccountManager) SyncUserJWTGroups(ctx context.Context, userAuth auth.UserAuth) error { - if userAuth.IsChild || userAuth.IsPAT { + // Child accounts and PAT-authenticated requests do not sync JWT groups. + // Embedded-Dex local users also skip sync because local password authentication + // does not provide external IdP group claims. + if userAuth.IsChild || userAuth.IsPAT || dex.IsLocalUserID(userAuth.UserId) { return nil } diff --git a/management/server/account_test.go b/management/server/account_test.go index ba621030c..bb4779d85 100644 --- a/management/server/account_test.go +++ b/management/server/account_test.go @@ -26,6 +26,7 @@ import ( "github.com/netbirdio/netbird/shared/management/status" nbdns "github.com/netbirdio/netbird/dns" + "github.com/netbirdio/netbird/idp/dex" "github.com/netbirdio/netbird/management/internals/controllers/network_map" "github.com/netbirdio/netbird/management/internals/controllers/network_map/controller" "github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel" @@ -723,6 +724,28 @@ func TestDefaultAccountManager_SyncUserJWTGroups(t *testing.T) { require.Equal(t, g2.Name, "group2", "group2 name should match") require.Equal(t, g2.Issued, types.GroupIssuedJWT, "group2 issued should match") }) + t.Run("local embedded-Dex user is skipped", func(t *testing.T) { + initAccount.Settings.JWTGroupsEnabled = true + initAccount.Settings.JWTGroupsClaimName = "idp-groups" + err := manager.Store.SaveAccount(context.Background(), initAccount) + require.NoError(t, err, "save account failed") + + localClaims := auth.UserAuth{ + AccountId: accountID, + Domain: domain, + UserId: dex.EncodeDexUserID("local-owner", "local"), + Groups: []string{"group3", "group4"}, + } + err = manager.SyncUserJWTGroups(context.Background(), localClaims) + require.NoError(t, err, "sync should be a no-op for local users") + + account, err := manager.Store.GetAccount(context.Background(), accountID) + require.NoError(t, err, "get account failed") + for _, g := range account.Groups { + require.NotEqual(t, "group3", g.Name, "local user JWT groups must not be synced") + require.NotEqual(t, "group4", g.Name, "local user JWT groups must not be synced") + } + }) } func TestAccountManager_PrivateAccount(t *testing.T) {