mirror of https://github.com/grafana/grafana
parent
5533b30135
commit
95379dcd23
@ -0,0 +1,24 @@ |
||||
package common |
||||
|
||||
// Common relation for each resource
|
||||
const ( |
||||
RelationView string = "view" |
||||
RelationEdit string = "edit" |
||||
RelationAdmin string = "admin" |
||||
|
||||
RelationRead string = "read" |
||||
RelationWrite string = "write" |
||||
RelationCreate string = "create" |
||||
RelationDelete string = "delete" |
||||
RelationPermissionsRead string = "permissions_read" |
||||
RelationPermissionsWrite string = "permissions_write" |
||||
) |
||||
|
||||
var ResourceRelations = [...]string{ |
||||
RelationRead, |
||||
RelationWrite, |
||||
RelationCreate, |
||||
RelationDelete, |
||||
RelationPermissionsRead, |
||||
RelationPermissionsWrite, |
||||
} |
@ -0,0 +1,69 @@ |
||||
package server |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
authzv1 "github.com/grafana/authlib/authz/proto/v1" |
||||
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana/common" |
||||
authzextv1 "github.com/grafana/grafana/pkg/services/authz/zanzana/proto/v1" |
||||
) |
||||
|
||||
func (s *Server) Capabilities(ctx context.Context, r *authzextv1.CapabilitiesRequest) (*authzextv1.CapabilitiesResponse, error) { |
||||
if info, ok := common.GetTypeInfo(r.Group, r.Resource); ok { |
||||
return s.capabilitiesTyped(ctx, r, info) |
||||
} |
||||
return s.capabilitiesGeneric(ctx, r) |
||||
} |
||||
|
||||
func (s *Server) capabilitiesTyped(ctx context.Context, r *authzextv1.CapabilitiesRequest, info common.TypeInfo) (*authzextv1.CapabilitiesResponse, error) { |
||||
out := make([]string, 0, len(common.ResourceRelations)) |
||||
for _, relation := range common.ResourceRelations { |
||||
res, err := s.checkTyped(ctx, &authzv1.CheckRequest{ |
||||
Subject: r.Subject, |
||||
Group: r.Group, |
||||
Resource: r.Resource, |
||||
Namespace: r.Namespace, |
||||
Name: r.Name, |
||||
Folder: r.Folder, |
||||
Subresource: r.Subresource, |
||||
Path: r.Path, |
||||
}, info, relation) |
||||
|
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if res.GetAllowed() { |
||||
out = append(out, relation) |
||||
} |
||||
} |
||||
|
||||
return &authzextv1.CapabilitiesResponse{Capabilities: out}, nil |
||||
} |
||||
|
||||
func (s *Server) capabilitiesGeneric(ctx context.Context, r *authzextv1.CapabilitiesRequest) (*authzextv1.CapabilitiesResponse, error) { |
||||
out := make([]string, 0, len(common.ResourceRelations)) |
||||
for _, relation := range common.ResourceRelations { |
||||
res, err := s.checkGeneric(ctx, &authzv1.CheckRequest{ |
||||
Subject: r.Subject, |
||||
Group: r.Group, |
||||
Resource: r.Resource, |
||||
Namespace: r.Namespace, |
||||
Name: r.Name, |
||||
Folder: r.Folder, |
||||
Subresource: r.Subresource, |
||||
Path: r.Path, |
||||
}, relation) |
||||
|
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if res.GetAllowed() { |
||||
out = append(out, relation) |
||||
} |
||||
} |
||||
|
||||
return &authzextv1.CapabilitiesResponse{Capabilities: out}, nil |
||||
} |
@ -0,0 +1,68 @@ |
||||
package server |
||||
|
||||
import ( |
||||
"context" |
||||
"testing" |
||||
|
||||
"github.com/stretchr/testify/assert" |
||||
"github.com/stretchr/testify/require" |
||||
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana/common" |
||||
authzextv1 "github.com/grafana/grafana/pkg/services/authz/zanzana/proto/v1" |
||||
) |
||||
|
||||
func testCapabilities(t *testing.T, server *Server) { |
||||
newReq := func(subject, group, resource, folder, name string) *authzextv1.CapabilitiesRequest { |
||||
return &authzextv1.CapabilitiesRequest{ |
||||
// FIXME: namespace should map to store
|
||||
// Namespace: storeID,
|
||||
Subject: subject, |
||||
Group: group, |
||||
Resource: resource, |
||||
Name: name, |
||||
Folder: folder, |
||||
} |
||||
} |
||||
|
||||
t.Run("user:1 should only be able to read and write resource:dashboards.grafana.app/dashboards/1", func(t *testing.T) { |
||||
res, err := server.Capabilities(context.Background(), newReq("user:1", dashboardGroup, dashboardResource, "1", "1")) |
||||
require.NoError(t, err) |
||||
assert.Equal(t, res.GetCapabilities(), []string{common.RelationRead, common.RelationWrite}) |
||||
}) |
||||
|
||||
t.Run("user:2 should be able to read and write resource:dashboards.grafana.app/dashboards/1 through namespace", func(t *testing.T) { |
||||
res, err := server.Capabilities(context.Background(), newReq("user:2", dashboardGroup, dashboardResource, "1", "1")) |
||||
require.NoError(t, err) |
||||
assert.Equal(t, res.GetCapabilities(), []string{common.RelationRead, common.RelationWrite}) |
||||
}) |
||||
|
||||
t.Run("user:3 should be able to read resource:dashboards.grafana.app/dashboards/1 with set relation", func(t *testing.T) { |
||||
res, err := server.Capabilities(context.Background(), newReq("user:3", dashboardGroup, dashboardResource, "1", "1")) |
||||
require.NoError(t, err) |
||||
assert.Equal(t, res.GetCapabilities(), []string{common.RelationRead}) |
||||
}) |
||||
|
||||
t.Run("user:4 should be able to read dashboards.grafana.app/dashboards in folder 1", func(t *testing.T) { |
||||
res, err := server.Capabilities(context.Background(), newReq("user:4", dashboardGroup, dashboardResource, "1", "1")) |
||||
require.NoError(t, err) |
||||
assert.Equal(t, res.GetCapabilities(), []string{common.RelationRead}) |
||||
}) |
||||
|
||||
t.Run("user:5 should be able to read, write, create and delete resource:dashboards.grafana.app/dashboards/1 through folder with set relation", func(t *testing.T) { |
||||
res, err := server.Capabilities(context.Background(), newReq("user:5", dashboardGroup, dashboardResource, "1", "1")) |
||||
require.NoError(t, err) |
||||
assert.Equal(t, res.GetCapabilities(), []string{common.RelationRead, common.RelationWrite, common.RelationCreate, common.RelationDelete}) |
||||
}) |
||||
|
||||
t.Run("user:6 should be able to read folder 1 ", func(t *testing.T) { |
||||
res, err := server.Capabilities(context.Background(), newReq("user:6", folderGroup, folderResource, "", "1")) |
||||
require.NoError(t, err) |
||||
assert.Equal(t, res.GetCapabilities(), []string{common.RelationRead}) |
||||
}) |
||||
|
||||
t.Run("user:7 should be able to read folder one through namespace access", func(t *testing.T) { |
||||
res, err := server.Capabilities(context.Background(), newReq("user:7", folderGroup, folderResource, "", "1")) |
||||
require.NoError(t, err) |
||||
assert.Equal(t, res.GetCapabilities(), []string{common.RelationRead}) |
||||
}) |
||||
} |
Loading…
Reference in new issue