AuthZ: Test List (#101721)

* Authz: Test List

* Anonymous case

* Cover rendering
pull/101794/head
Gabriel MABILLE 4 months ago committed by GitHub
parent 392124de00
commit 6a1e5dd128
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 293
      pkg/services/authz/rbac/service_test.go

@ -897,6 +897,299 @@ func TestService_Check(t *testing.T) {
}) })
} }
func TestService_List(t *testing.T) {
callingService := authn.NewAccessTokenAuthInfo(authn.Claims[authn.AccessTokenClaims]{
Claims: jwt.Claims{
Subject: types.NewTypeID(types.TypeAccessPolicy, "some-service"),
Audience: []string{"authzservice"},
},
Rest: authn.AccessTokenClaims{Namespace: "org-12"},
})
type testCase struct {
name string
req *authzv1.ListRequest
permissions []accesscontrol.Permission
expected *authzv1.ListResponse
expectErr bool
}
t.Run("Require auth info", func(t *testing.T) {
s := setupService()
ctx := context.Background()
_, err := s.List(ctx, &authzv1.ListRequest{
Namespace: "org-12",
Subject: "user:test-uid",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
})
require.Error(t, err)
require.Contains(t, err.Error(), "could not get auth info")
})
testCases := []testCase{
{
name: "should error if no namespace is provided",
req: &authzv1.ListRequest{
Namespace: "",
Subject: "user:test-uid",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
expectErr: true,
},
{
name: "should error if caller namespace does not match request namespace",
req: &authzv1.ListRequest{
Namespace: "org-13",
Subject: "user:test-uid",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
expectErr: true,
},
{
name: "should error if no subject is provided",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
expectErr: true,
},
{
name: "should error if an unsupported subject type is provided",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "api-key:12",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
expectErr: true,
},
{
name: "should error if an invalid subject is provided",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "invalid:12",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
expectErr: true,
},
{
name: "should error if an unknown group is provided",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "user:test-uid",
Group: "unknown.grafana.app",
Resource: "unknown",
Verb: "get",
},
expectErr: true,
},
{
name: "should error if an unknown verb is provided",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "user:test-uid",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "unknown",
},
expectErr: true,
},
}
t.Run("Request validation", func(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
s := setupService()
ctx := types.WithAuthInfo(context.Background(), callingService)
userID := &store.UserIdentifiers{UID: "test-uid", ID: 1}
store := &fakeStore{
userID: userID,
userPermissions: tc.permissions,
}
s.store = store
s.permissionStore = store
s.identityStore = &fakeIdentityStore{teams: []int64{1, 2}}
_, err := s.List(ctx, tc.req)
require.Error(t, err)
})
}
})
testCases = []testCase{
{
name: "should list permissions for user with permission",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "user:test-uid",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
permissions: []accesscontrol.Permission{
{Action: "dashboards:read", Scope: "dashboards:uid:dash1"},
{Action: "dashboards:read", Scope: "dashboards:uid:dash2"},
{Action: "dashboards:read", Scope: "folders:uid:fold1"},
},
expected: &authzv1.ListResponse{
Items: []string{"dash1", "dash2"},
Folders: []string{"fold1"},
},
},
{
name: "should return empty list for user without permission",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "user:test-uid",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
permissions: []accesscontrol.Permission{},
expected: &authzv1.ListResponse{},
},
}
t.Run("User permission list", func(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
s := setupService()
ctx := types.WithAuthInfo(context.Background(), callingService)
userID := &store.UserIdentifiers{UID: "test-uid", ID: 1}
store := &fakeStore{
userID: userID,
userPermissions: tc.permissions,
}
s.store = store
s.permissionStore = store
s.identityStore = &fakeIdentityStore{teams: []int64{1, 2}}
resp, err := s.List(ctx, tc.req)
require.NoError(t, err)
require.ElementsMatch(t, resp.Items, tc.expected.Items)
require.ElementsMatch(t, resp.Folders, tc.expected.Folders)
// Check cache
id, ok := s.idCache.Get(ctx, userIdentifierCacheKey("org-12", "test-uid"))
require.True(t, ok)
require.Equal(t, id.UID, "test-uid")
perms, ok := s.permCache.Get(ctx, userPermCacheKey("org-12", "test-uid", "dashboards:read"))
require.True(t, ok)
require.Len(t, perms, len(tc.expected.Items)+len(tc.expected.Folders))
})
}
})
testCases = []testCase{
{
name: "should list permissions for anonymous with permission",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "anonymous:0",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
permissions: []accesscontrol.Permission{
{Action: "dashboards:read", Scope: "dashboards:uid:dash1"},
{Action: "dashboards:read", Scope: "dashboards:uid:dash2"},
{Action: "dashboards:read", Scope: "folders:uid:fold1"},
},
expected: &authzv1.ListResponse{
Items: []string{"dash1", "dash2"},
Folders: []string{"fold1"},
},
},
{
name: "should return empty list for anonymous without permission",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "anonymous:0",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
permissions: []accesscontrol.Permission{},
expected: &authzv1.ListResponse{},
},
}
t.Run("Anonymous permission list", func(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
s := setupService()
ctx := types.WithAuthInfo(context.Background(), callingService)
store := &fakeStore{userPermissions: tc.permissions}
s.store = store
s.permissionStore = store
s.identityStore = &fakeIdentityStore{teams: []int64{1, 2}}
resp, err := s.List(ctx, tc.req)
require.NoError(t, err)
require.ElementsMatch(t, resp.Items, tc.expected.Items)
require.ElementsMatch(t, resp.Folders, tc.expected.Folders)
// Check cache
perms, ok := s.permCache.Get(ctx, anonymousPermCacheKey("org-12", "dashboards:read"))
require.True(t, ok)
require.Len(t, perms, len(tc.expected.Items)+len(tc.expected.Folders))
})
}
})
testCases = []testCase{
{
name: "should list permissions for rendering",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "render:0",
Group: "dashboard.grafana.app",
Resource: "dashboards",
Verb: "get",
},
expected: &authzv1.ListResponse{
All: true,
},
},
{
name: "should deny rendering access to another app resources",
req: &authzv1.ListRequest{
Namespace: "org-12",
Subject: "render:0",
Group: "another.grafana.app",
Resource: "dashboards",
Verb: "get",
},
expectErr: true,
},
}
t.Run("Rendering permission list", func(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
s := setupService()
ctx := types.WithAuthInfo(context.Background(), callingService)
resp, err := s.List(ctx, tc.req)
if tc.expectErr {
require.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, tc.expected.All, resp.All)
})
}
})
}
func setupService() *Service { func setupService() *Service {
cache := cache.NewLocalCache(cache.Config{Expiry: 5 * time.Minute, CleanupInterval: 5 * time.Minute}) cache := cache.NewLocalCache(cache.Config{Expiry: 5 * time.Minute, CleanupInterval: 5 * time.Minute})
logger := log.New("authz-rbac-service") logger := log.New("authz-rbac-service")

Loading…
Cancel
Save