From 683c5a2eace0ccb22737d306e6eb01ad73a73eaa Mon Sep 17 00:00:00 2001 From: Kenneth Jenkins <51246568+kenjenkins@users.noreply.github.com> Date: Wed, 11 Dec 2024 12:55:04 -0800 Subject: [PATCH] authorize: change handling of empty groups claim (#5394) Make sure to serialize the JWT "groups" claim as an empty list rather than a JSON null. This matches the behavior of Pomerium v0.27.2 and earlier, and should provide better compatibility with some third-party libraries. --- .../evaluator/headers_evaluator_evaluation.go | 6 +++++ authorize/evaluator/headers_evaluator_test.go | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/authorize/evaluator/headers_evaluator_evaluation.go b/authorize/evaluator/headers_evaluator_evaluation.go index d61215b6a..c5f9c30a1 100644 --- a/authorize/evaluator/headers_evaluator_evaluation.go +++ b/authorize/evaluator/headers_evaluator_evaluation.go @@ -280,6 +280,12 @@ func (e *headersEvaluatorEvaluation) getJWTPayloadGroups(ctx context.Context) [] s, _ := e.getSessionOrServiceAccount(ctx) groups, _ := getClaimStringSlice(s, "groups") + if groups == nil { + // If there are no groups, marshal this claim as an empty list rather than a JSON null, + // for better compatibility with third-party libraries. + // See https://github.com/pomerium/pomerium/issues/5393 for one example. + groups = []string{} + } return groups } diff --git a/authorize/evaluator/headers_evaluator_test.go b/authorize/evaluator/headers_evaluator_test.go index c9194d7bd..3e365695a 100644 --- a/authorize/evaluator/headers_evaluator_test.go +++ b/authorize/evaluator/headers_evaluator_test.go @@ -281,6 +281,28 @@ func TestHeadersEvaluator(t *testing.T) { assert.Equal(t, []any{"g1", "g2", "g3", "g4", "GROUP1", "GROUP2", "GROUP3", "GROUP4"}, claims["groups"]) }) + t.Run("jwt no groups", func(t *testing.T) { + t.Parallel() + + output, err := eval(t, + []protoreflect.ProtoMessage{ + &session.Session{Id: "s1", UserId: "u1", Claims: map[string]*structpb.ListValue{ + "name": {Values: []*structpb.Value{ + structpb.NewStringValue("User Name"), + }}, + }}, + }, + &HeadersRequest{ + Session: RequestSession{ID: "s1"}, + }) + require.NoError(t, err) + jwtHeader := output.Headers.Get("X-Pomerium-Jwt-Assertion") + var decoded map[string]any + err = json.Unmarshal(decodeJWSPayload(t, jwtHeader), &decoded) + require.NoError(t, err) + assert.Equal(t, []any{}, decoded["groups"]) + }) + t.Run("set_request_headers", func(t *testing.T) { output, err := eval(t, []proto.Message{