3
0

Permission testing

This commit is contained in:
Denis Arh
2019-09-10 03:46:59 +02:00
parent 4e5288cce4
commit 08e9d5af5b
17 changed files with 373 additions and 27 deletions
+5 -1
View File
@@ -175,12 +175,16 @@ func (svc accessControl) can(ctx context.Context, res permissionResource, op per
}
func (svc accessControl) Grant(ctx context.Context, rr ...*permissions.Rule) error {
if !svc.CanGrant(ctx) {
return ErrNoGrantPermissions
}
return svc.permissions.Grant(ctx, svc.Whitelist(), rr...)
}
func (svc accessControl) FindRulesByRoleID(ctx context.Context, roleID uint64) (permissions.RuleSet, error) {
if !svc.CanGrant(ctx) {
return nil, ErrNoGrantPermissions
return nil, ErrNoPermissions
}
return svc.permissions.FindRulesByRoleID(roleID), nil
+1
View File
@@ -11,6 +11,7 @@ type (
const (
ErrInvalidID serviceError = "InvalidID"
ErrStaleData serviceError = "StaleData"
ErrNoPermissions serviceError = "NoPermissions"
ErrNoGrantPermissions serviceError = "NoGrantPermissions"
ErrNoCreatePermissions serviceError = "NoCreatePermissions"
ErrNoReadPermissions serviceError = "NoReadPermissions"
+15 -9
View File
@@ -30,6 +30,8 @@ type (
)
var (
DefaultStore store.Store
DefaultLogger *zap.Logger
// DefaultPermissions Retrieves & stores permissions
@@ -64,19 +66,23 @@ func Init(ctx context.Context, log *zap.Logger, c Config) (err error) {
DefaultLogger = log.Named("service")
fs, err := store.New(c.Storage.Path)
log.Info("initializing store", zap.String("path", c.Storage.Path), zap.Error(err))
if err != nil {
return err
if DefaultStore == nil {
DefaultStore, err = store.New(c.Storage.Path)
log.Info("initializing store", zap.String("path", c.Storage.Path), zap.Error(err))
if err != nil {
return err
}
}
// Permissions, access control
DefaultPermissions = permissions.Service(
ctx,
DefaultLogger,
permissions.Repository(db, "compose_permission_rules"))
if DefaultPermissions == nil {
DefaultPermissions = permissions.Service(
ctx,
DefaultLogger,
permissions.Repository(db, "compose_permission_rules"))
}
DefaultAccessControl = AccessControl(DefaultPermissions)
DefaultNamespace = Namespace()
DefaultModule = Module()
+17
View File
@@ -2,6 +2,8 @@ package permissions
import (
"context"
"fmt"
"strings"
)
type (
@@ -49,6 +51,21 @@ func (svc *TestService) ClearGrants() {
svc.rules = RuleSet{}
}
func (svc *TestService) String() (out string) {
tpl := "%20v\t%-30s\t%-30s\t%v\n"
out = fmt.Sprintf(tpl, "role", "res", "op", "access")
out += strings.Repeat("-", 120) + "\n"
_ = svc.rules.Walk(func(r *Rule) error {
out += fmt.Sprintf(tpl, r.RoleID, r.Resource, r.Operation, r.Access)
return nil
})
out += strings.Repeat("-", 120) + "\n"
return
}
func NewTestService() *TestService {
return &TestService{
service: service{},
+4
View File
@@ -215,6 +215,10 @@ func (svc accessControl) can(ctx context.Context, res permissionResource, op per
}
func (svc accessControl) Grant(ctx context.Context, rr ...*permissions.Rule) error {
if !svc.CanGrant(ctx) {
return ErrNoGrantPermissions
}
return svc.permissions.Grant(ctx, svc.Whitelist(), rr...)
}
+3 -2
View File
@@ -9,8 +9,9 @@ type (
)
const (
ErrInvalidID serviceError = "InvalidID"
ErrNoPermissions serviceError = "NoPermissions"
ErrInvalidID serviceError = "InvalidID"
ErrNoPermissions serviceError = "NoPermissions"
ErrNoGrantPermissions serviceError = "NoGrantPermissions"
)
func (e serviceError) Error() string {
+2 -2
View File
@@ -35,12 +35,12 @@ func (svc accessControl) Effective(ctx context.Context) (ee permissions.Effectiv
ee = permissions.EffectiveSet{}
ee.Push(types.SystemPermissionResource, "access", svc.CanAccess(ctx))
ee.Push(types.SystemPermissionResource, "grant", svc.CanGrant(ctx))
ee.Push(types.SystemPermissionResource, "settings.read", svc.CanReadSettings(ctx))
ee.Push(types.SystemPermissionResource, "settings.manage", svc.CanManageSettings(ctx))
ee.Push(types.SystemPermissionResource, "application.create", svc.CanCreateApplication(ctx))
ee.Push(types.SystemPermissionResource, "role.create", svc.CanCreateRole(ctx))
ee.Push(types.SystemPermissionResource, "organisation.create", svc.CanCreateOrganisation(ctx))
ee.Push(types.SystemPermissionResource, "grant", svc.CanCreateRole(ctx))
return
}
@@ -151,7 +151,7 @@ func (svc accessControl) can(ctx context.Context, res permissionResource, op per
func (svc accessControl) Grant(ctx context.Context, rr ...*permissions.Rule) error {
if !svc.CanGrant(ctx) {
return ErrNoPermissions
return ErrNoGrantPermissions
}
return svc.permissions.Grant(ctx, svc.Whitelist(), rr...)
+5 -4
View File
@@ -69,10 +69,11 @@ func Init(ctx context.Context, log *zap.Logger, c Config) (err error) {
DefaultIntSettings = internalSettings.NewService(internalSettings.NewRepository(repository.DB(ctx), "sys_settings"))
DefaultPermissions = permissions.Service(
ctx,
DefaultLogger,
permissions.Repository(repository.DB(ctx), "sys_permission_rules"))
if DefaultPermissions == nil {
pRepo := permissions.Repository(repository.DB(ctx), "sys_permission_rules")
DefaultPermissions = permissions.Service(ctx, DefaultLogger, pRepo)
}
DefaultAccessControl = AccessControl(DefaultPermissions)
DefaultSettings = Settings(ctx, DefaultIntSettings)
+17 -7
View File
@@ -6,29 +6,39 @@ import (
"testing"
"github.com/cortezaproject/corteza-server/internal/permissions"
"github.com/cortezaproject/corteza-server/messaging/types"
"github.com/cortezaproject/corteza-server/tests/helpers"
)
func TestPermissionsDelete(t *testing.T) {
h := newHelper(t)
h.a.Empty(p.FindRulesByRoleID(h.roleID))
// Make sure our user can grant
h.allow(types.MessagingPermissionResource, "grant")
h.allow("messaging", "access")
h.allow("messaging", "grant")
h.deny("messaging", "channel.group.create")
// New role.
permDelRole := h.roleID + 1
h.a.Len(p.FindRulesByRoleID(h.roleID), 3)
h.a.Len(p.FindRulesByRoleID(permDelRole), 0)
// Setup a few fake rules for new roke
h.mockPermissions(
permissions.AllowRule(permDelRole, types.MessagingPermissionResource, "access"),
permissions.DenyRule(permDelRole, types.MessagingPermissionResource, "channel.group.create"),
permissions.DenyRule(permDelRole, types.MessagingPermissionResource, "channel.private.create"),
)
h.a.Len(p.FindRulesByRoleID(permDelRole), 3)
h.apiInit().
Delete(fmt.Sprintf("/permissions/%d/rules", h.roleID)).
Delete(fmt.Sprintf("/permissions/%d/rules", permDelRole)).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
// Make sure everything is deleted
rr, _ := p.FindRulesByRoleID(h.roleID).Filter(func(r *permissions.Rule) (b bool, e error) {
rr, _ := p.FindRulesByRoleID(permDelRole).Filter(func(r *permissions.Rule) (b bool, e error) {
return r.Access != permissions.Inherit, nil
})
@@ -10,9 +10,7 @@ import (
func TestPermissionsUpdate(t *testing.T) {
h := newHelper(t)
h.allow("messaging", "access")
h.allow("messaging", "grant")
h.deny("messaging", "channel.group.create")
h.apiInit().
Patch(fmt.Sprintf("/permissions/%d/rules", h.roleID)).
+21
View File
@@ -0,0 +1,21 @@
package system
import (
"testing"
)
func TestApplicationCreate(t *testing.T) {
t.Skip("to be implemented")
}
func TestApplicationRead(t *testing.T) {
t.Skip("to be implemented")
}
func TestApplicationUpdate(t *testing.T) {
t.Skip("to be implemented")
}
func TestApplicationDelete(t *testing.T) {
t.Skip("to be implemented")
}
+146
View File
@@ -0,0 +1,146 @@
package system
import (
"context"
"os"
"testing"
_ "github.com/joho/godotenv/autoload"
"github.com/steinfletcher/apitest"
"github.com/stretchr/testify/require"
"github.com/titpetric/factory"
"github.com/go-chi/chi"
"go.uber.org/zap"
"github.com/cortezaproject/corteza-server/internal/auth"
"github.com/cortezaproject/corteza-server/internal/permissions"
"github.com/cortezaproject/corteza-server/internal/rand"
"github.com/cortezaproject/corteza-server/pkg/api"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/pkg/logger"
"github.com/cortezaproject/corteza-server/system"
"github.com/cortezaproject/corteza-server/system/rest"
"github.com/cortezaproject/corteza-server/system/service"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/cortezaproject/corteza-server/tests/helpers"
)
type (
helper struct {
t *testing.T
a *require.Assertions
cUser *types.User
roleID uint64
}
)
var (
cfg *cli.Config
r chi.Router
p = permissions.NewTestService()
)
func InitConfig() {
var err error
if cfg != nil {
return
}
helpers.RecursiveDotEnvLoad()
ctx := context.Background()
log, _ := zap.NewDevelopment()
cfg = system.Configure()
cfg.Log = log
cfg.Init()
auth.SetupDefault(string(rand.Bytes(32)), 10)
if err = cfg.RootCommandDBSetup.Run(ctx, nil, cfg); err != nil {
panic(err)
}
logger.SetDefault(log)
service.DefaultPermissions = p
// if service.DefaultStore, err = store.NewWithAfero(afero.NewMemMapFs(), "test"); err != nil {
// panic(err)
// }
cfg.InitServices(ctx, cfg)
}
func InitApp() {
InitConfig()
helpers.InitAuth()
if r != nil {
return
}
r = chi.NewRouter()
r.Use(api.Base(logger.Default())...)
helpers.BindAuthMiddleware(r)
rest.MountRoutes(r)
}
func TestMain(m *testing.M) {
InitApp()
os.Exit(m.Run())
}
func newHelper(t *testing.T) helper {
h := helper{
t: t,
a: require.New(t),
roleID: factory.Sonyflake.NextID(),
cUser: &types.User{
ID: factory.Sonyflake.NextID(),
},
}
h.cUser.SetRoles([]uint64{h.roleID})
p.ClearGrants()
// Setup permissions with allowed access to system
h.mockPermissions(
permissions.AllowRule(permissions.EveryoneRoleID, types.SystemPermissionResource, "access"),
)
return h
}
// apitest basics, initialize, set handler, add auth
func (h helper) apiInit() *apitest.APITest {
InitApp()
return apitest.
New().
Handler(r).
Intercept(helpers.ReqHeaderAuthBearer(h.cUser))
}
func (h helper) mockPermissions(rules ...*permissions.Rule) {
h.a.NoError(p.Grant(
// TestService we use does not have any backend storage,
context.Background(),
// We want to make sure we did not make a mistake with any of the mocked resources or actions
service.DefaultAccessControl.Whitelist(),
rules...,
))
}
// Set allow permision for test role
func (h helper) allow(r permissions.Resource, o permissions.Operation) {
h.mockPermissions(permissions.AllowRule(h.roleID, r, o))
}
// set deny permission for test role
func (h helper) deny(r permissions.Resource, o permissions.Operation) {
h.mockPermissions(permissions.DenyRule(h.roleID, r, o))
}
+46
View File
@@ -0,0 +1,46 @@
package system
import (
"fmt"
"net/http"
"testing"
"github.com/cortezaproject/corteza-server/internal/permissions"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/cortezaproject/corteza-server/tests/helpers"
)
func TestPermissionsDelete(t *testing.T) {
h := newHelper(t)
// Make sure our user can grant
h.allow(types.SystemPermissionResource, "grant")
// New role.
permDelRole := h.roleID + 1
h.a.Len(p.FindRulesByRoleID(permDelRole), 0)
// Setup a few fake rules for new roke
h.mockPermissions(
permissions.AllowRule(permDelRole, types.SystemPermissionResource, "access"),
permissions.DenyRule(permDelRole, types.SystemPermissionResource, "application.create"),
permissions.DenyRule(permDelRole, types.SystemPermissionResource, "user.create"),
)
h.a.Len(p.FindRulesByRoleID(permDelRole), 3)
h.apiInit().
Delete(fmt.Sprintf("/permissions/%d/rules", permDelRole)).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
// Make sure everything is deleted
rr, _ := p.FindRulesByRoleID(permDelRole).Filter(func(r *permissions.Rule) (b bool, e error) {
return r.Access != permissions.Inherit, nil
})
h.a.Empty(rr)
}
@@ -0,0 +1,22 @@
package system
import (
"net/http"
"testing"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/cortezaproject/corteza-server/tests/helpers"
)
func TestPermissionsEffective(t *testing.T) {
h := newHelper(t)
h.allow(types.SystemPermissionResource, "access")
h.deny(types.SystemPermissionResource, "application.create")
h.apiInit().
Get("/permissions/effective").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
}
+22
View File
@@ -0,0 +1,22 @@
package system
import (
"net/http"
"testing"
jsonpath "github.com/steinfletcher/apitest-jsonpath"
"github.com/cortezaproject/corteza-server/tests/helpers"
)
func TestPermissionsList(t *testing.T) {
h := newHelper(t)
h.apiInit().
Get("/permissions/").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
Assert(jsonpath.Present(`$.response[? @.resource=="system"]`)).
End()
}
+24
View File
@@ -0,0 +1,24 @@
package system
import (
"fmt"
"net/http"
"testing"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/cortezaproject/corteza-server/tests/helpers"
)
func TestPermissionsRead(t *testing.T) {
h := newHelper(t)
h.allow(types.SystemPermissionResource, "access")
h.allow(types.SystemPermissionResource, "grant")
h.deny(types.SystemPermissionResource, "application.create")
h.apiInit().
Get(fmt.Sprintf("/permissions/%d/rules", h.roleID)).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
}
+23
View File
@@ -0,0 +1,23 @@
package system
import (
"fmt"
"net/http"
"testing"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/cortezaproject/corteza-server/tests/helpers"
)
func TestPermissionsUpdate(t *testing.T) {
h := newHelper(t)
h.allow(types.SystemPermissionResource, "grant")
h.apiInit().
Patch(fmt.Sprintf("/permissions/%d/rules", h.roleID)).
JSON(`{"rules":[{"resource":"system","operation":"application.create","access":"allow"}]}`).
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
}