From 7a24d8efbf6a16f3d7ba2e51096bbadf9213f6ff Mon Sep 17 00:00:00 2001 From: Yimin Chen Date: Thu, 27 Apr 2023 16:41:53 -0700 Subject: [PATCH] defaultJWTClaimMapper treat namespace as case sensitive (#4244) Change defaultJWTClaimMapper treat namespace as case sensitive. Change system namespace from system to temporal-system and make it case sensitive. --- .../authorization/default_jwt_claim_mapper.go | 7 +++--- .../default_jwt_claim_mapper_test.go | 24 ++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/common/authorization/default_jwt_claim_mapper.go b/common/authorization/default_jwt_claim_mapper.go index 0909fbee096..0b53fcff4bc 100644 --- a/common/authorization/default_jwt_claim_mapper.go +++ b/common/authorization/default_jwt_claim_mapper.go @@ -31,6 +31,7 @@ import ( "github.com/golang-jwt/jwt/v4" "go.temporal.io/api/serviceerror" + "go.temporal.io/server/common/primitives" "go.temporal.io/server/common/config" "go.temporal.io/server/common/log" @@ -40,7 +41,7 @@ const ( defaultPermissionsClaimName = "permissions" authorizationBearer = "bearer" headerSubject = "sub" - permissionScopeSystem = "system" + permissionScopeSystem = primitives.SystemLocalNamespace permissionRead = "read" permissionWrite = "write" permissionWorker = "worker" @@ -110,8 +111,8 @@ func (a *defaultJWTClaimMapper) extractPermissions(permissions []interface{}, cl a.logger.Warn(fmt.Sprintf("ignoring permission in unexpected format: %v", permission)) continue } - namespace := strings.ToLower(parts[0]) - if strings.EqualFold(namespace, permissionScopeSystem) { + namespace := parts[0] + if namespace == permissionScopeSystem { claims.System |= permissionToRole(parts[1]) } else { if claims.Namespaces == nil { diff --git a/common/authorization/default_jwt_claim_mapper_test.go b/common/authorization/default_jwt_claim_mapper_test.go index 74fda73b1e5..f4244eb041e 100644 --- a/common/authorization/default_jwt_claim_mapper_test.go +++ b/common/authorization/default_jwt_claim_mapper_test.go @@ -38,6 +38,7 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "go.temporal.io/server/common/primitives" "go.temporal.io/server/common/config" "go.temporal.io/server/common/log" @@ -65,7 +66,7 @@ const ( ) var ( - permissionsAdmin = []string{"system:admin", "default:read"} + permissionsAdmin = []string{primitives.SystemLocalNamespace + ":admin", "default:read"} permissionsReaderWriterWorker = []string{"default:read", "default:write", "default:worker"} ) @@ -163,6 +164,27 @@ func (s *defaultClaimMapperSuite) testTokenWithAdminPermissions(alg keyAlgorithm s.Equal(RoleReader, defaultRole) } +func (s *defaultClaimMapperSuite) TestNamespacePermissionCaseSensitive() { + tokenString, err := s.tokenGenerator.generateToken(RSA, + testSubject, []string{"Temporal-system:admin", "Foo:read"}, errorTestOptionNoError) + s.NoError(err) + authInfo := &AuthInfo{ + AddBearer(tokenString), + nil, + nil, + "", + "", + } + claims, err := s.claimMapper.GetClaims(authInfo) + s.NoError(err) + s.Equal(testSubject, claims.Subject) + s.Equal(RoleUndefined, claims.System) // no system role + s.Equal(2, len(claims.Namespaces)) + // claims contain namespace role for 'Foo', not for 'foo'. + s.Equal(RoleReader, claims.Namespaces["Foo"]) + s.Equal(RoleAdmin, claims.Namespaces["Temporal-system"]) +} + func (s *defaultClaimMapperSuite) TestTokenWithReaderWriterWorkerPermissionsRSA() { s.testTokenWithReaderWriterWorkerPermissions(RSA) }