mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-03 03:59:07 +02:00
[management] Skip JWT group evaluation for embedded-IdP local users (#6422)
When JWT group sync is enabled with a restrictive JWTAllowGroups list, the local owner of an embedded-IdP (Dex) deployment can get locked out. The allow-groups check runs account-wide but local password users do not receive external IdP group claims, so they can't satisfy the allowed list. This skips JWT group evaluation for local Dex users so the restriction and JWT group sync continue to apply to external-IdP users as intended.
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/netbirdio/netbird/shared/auth"
|
||||
|
||||
"github.com/netbirdio/netbird/base62"
|
||||
"github.com/netbirdio/netbird/idp/dex"
|
||||
"github.com/netbirdio/netbird/management/server/store"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
nbjwt "github.com/netbirdio/netbird/shared/auth/jwt"
|
||||
@@ -74,7 +75,10 @@ func (m *manager) ValidateAndParseToken(ctx context.Context, value string) (auth
|
||||
}
|
||||
|
||||
func (m *manager) EnsureUserAccessByJWTGroups(ctx context.Context, userAuth auth.UserAuth, token *jwt.Token) (auth.UserAuth, error) {
|
||||
if userAuth.IsChild || userAuth.IsPAT {
|
||||
// Child accounts and PAT-authenticated requests do not use JWT group access checks.
|
||||
// Embedded-Dex local users also skip them because local password authentication
|
||||
// does not provide external IdP group claims.
|
||||
if userAuth.IsChild || userAuth.IsPAT || dex.IsLocalUserID(userAuth.UserId) {
|
||||
return userAuth, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/idp/dex"
|
||||
"github.com/netbirdio/netbird/management/server/auth"
|
||||
"github.com/netbirdio/netbird/management/server/store"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
@@ -206,6 +207,43 @@ func TestAuthManager_EnsureUserAccessByJWTGroups(t *testing.T) {
|
||||
_, err = manager.EnsureUserAccessByJWTGroups(context.Background(), userAuth, token)
|
||||
require.Error(t, err, "ensure user access is not in allowed groups")
|
||||
})
|
||||
|
||||
t.Run("Local embedded-Dex user is exempt from JWT allow-groups", func(t *testing.T) {
|
||||
account.Settings.JWTGroupsEnabled = true
|
||||
account.Settings.JWTGroupsClaimName = "idp-groups"
|
||||
account.Settings.JWTAllowGroups = []string{"not-a-group"}
|
||||
err := store.SaveAccount(context.Background(), account)
|
||||
require.NoError(t, err, "save account failed")
|
||||
|
||||
// Local Dex users have a "local" connector encoded in their user ID.
|
||||
localUserAuth := nbauth.UserAuth{
|
||||
AccountId: account.Id,
|
||||
Domain: domain,
|
||||
UserId: dex.EncodeDexUserID("local-owner", "local"),
|
||||
}
|
||||
|
||||
localUserAuth, err = manager.EnsureUserAccessByJWTGroups(context.Background(), localUserAuth, token)
|
||||
require.NoError(t, err, "local user must not be locked out by JWT allow-groups (issue #5337)")
|
||||
require.Len(t, localUserAuth.Groups, 0, "JWT groups must not be evaluated for local users")
|
||||
})
|
||||
|
||||
t.Run("Federated embedded-Dex user is still subject to JWT allow-groups", func(t *testing.T) {
|
||||
account.Settings.JWTGroupsEnabled = true
|
||||
account.Settings.JWTGroupsClaimName = "idp-groups"
|
||||
account.Settings.JWTAllowGroups = []string{"not-a-group"}
|
||||
err := store.SaveAccount(context.Background(), account)
|
||||
require.NoError(t, err, "save account failed")
|
||||
|
||||
// A federated user (non-"local" connector) must remain restricted.
|
||||
fedUserAuth := nbauth.UserAuth{
|
||||
AccountId: account.Id,
|
||||
Domain: domain,
|
||||
UserId: dex.EncodeDexUserID("entra-user", "entra"),
|
||||
}
|
||||
|
||||
_, err = manager.EnsureUserAccessByJWTGroups(context.Background(), fedUserAuth, token)
|
||||
require.Error(t, err, "federated user must still be restricted by JWT allow-groups")
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthManager_ValidateAndParseToken(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user