Add integration tests for record ctx roles

This commit is contained in:
Tomaž Jerman
2021-10-01 10:08:58 +02:00
committed by Denis Arh
parent 2d2e02b3a0
commit 43fe13a128
11 changed files with 258 additions and 8 deletions
+3 -3
View File
@@ -837,7 +837,7 @@ func initRoles(ctx context.Context, log *zap.Logger, opt options.RBACOpt, eb eve
DefaultRole.SetClosed(tmp...)
// Initial RBAC update
if err = updateRbacRoles(ctx, log, ru, bypass, authenticated, anonymous); err != nil {
if err = UpdateRbacRoles(ctx, log, ru, bypass, authenticated, anonymous); err != nil {
return
}
@@ -846,7 +846,7 @@ func initRoles(ctx context.Context, log *zap.Logger, opt options.RBACOpt, eb eve
eb.Register(
func(_ context.Context, ev eventbus.Event) error {
log.Debug("role changed, updating RBAC")
return updateRbacRoles(ctx, log, ru, bypass, authenticated, anonymous)
return UpdateRbacRoles(ctx, log, ru, bypass, authenticated, anonymous)
},
eventbus.For("system:role"),
eventbus.On("afterUpdate", "afterCreate", "afterDelete"),
@@ -855,7 +855,7 @@ func initRoles(ctx context.Context, log *zap.Logger, opt options.RBACOpt, eb eve
return nil
}
func updateRbacRoles(ctx context.Context, log *zap.Logger, ru rbacRoleUpdater, bypass, authenticated, anonymous map[string]bool) error {
func UpdateRbacRoles(ctx context.Context, log *zap.Logger, ru rbacRoleUpdater, bypass, authenticated, anonymous map[string]bool) error {
var (
p = expr.NewParser()
f = types.RoleFilter{}
+8 -4
View File
@@ -111,14 +111,18 @@ func newHelper(t *testing.T) helper {
h.cUser.SetRoles(h.roleID)
helpers.UpdateRBAC(h.roleID)
h.identityToHelper(h.cUser)
return h
}
func (h *helper) identityToHelper(u *sysTypes.User) {
var err error
h.token, err = auth.DefaultJwtHandler.Generate(context.Background(), h.cUser)
h.cUser = u
h.token, err = auth.DefaultJwtHandler.Generate(context.Background(), u)
if err != nil {
panic(err)
}
return h
}
func (h helper) MyRole() uint64 {
@@ -184,7 +188,7 @@ func cleanup(t *testing.T) {
}
func loadScenario(ctx context.Context, s store.Storer, t *testing.T, h helper) {
loadScenarioWithName(ctx, s, t, h, "S"+t.Name()[4:])
loadScenarioWithName(ctx, s, t, h, t.Name()[5:])
}
func loadScenarioWithName(ctx context.Context, s store.Storer, t *testing.T, h helper, scenario string) {
@@ -72,7 +72,7 @@ func findPageByHandle(pp types.PageSet, h string) *types.Page {
return nil
}
func Test0001_namespace_duplicate(t *testing.T) {
func Test_namespace_duplicate(t *testing.T) {
ctx, h, s := setup(t)
loadScenario(ctx, defStore, t, h)
ns, _, _, _, _, err := fetchEntireNamespace(ctx, s, "ns1")
+154
View File
@@ -0,0 +1,154 @@
package compose
import (
"context"
"fmt"
"net/http"
"testing"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/rbac"
"github.com/cortezaproject/corteza-server/store"
"github.com/cortezaproject/corteza-server/system/service"
systemTypes "github.com/cortezaproject/corteza-server/system/types"
"github.com/cortezaproject/corteza-server/tests/helpers"
)
func crissCrossUserRoles(ctx context.Context, s store.Storer, h helper, uu systemTypes.UserSet, rr systemTypes.RoleSet) (map[string]*systemTypes.User, map[string]*systemTypes.Role) {
ux := make(map[string]*systemTypes.User)
for _, r := range uu {
ux[r.Name] = r
}
rx := make(map[string]*systemTypes.Role)
for _, r := range rr {
rx[r.Handle] = r
}
for _, u := range uu {
if _, ok := rx[u.Name]; !ok {
h.a.FailNow(fmt.Sprintf("corresponding role not found for user: r: %s; u: %s", u.Name, u.Handle))
}
rID := rx[u.Name].ID
h.a.NoError(store.CreateRoleMember(ctx, s, &systemTypes.RoleMember{
RoleID: rID,
UserID: u.ID,
}))
u.SetRoles(rID)
}
return ux, rx
}
func Test_record_access_context(t *testing.T) {
ctx, h, s := setup(t)
loadScenario(ctx, defStore, t, h)
// setup
rr, _, err := store.SearchRoles(ctx, s, systemTypes.RoleFilter{})
h.a.NoError(err)
uu, _, err := store.SearchUsers(ctx, s, systemTypes.UserFilter{})
h.a.NoError(err)
ux, rx := crissCrossUserRoles(ctx, s, h, uu, rr)
ns, err := store.LookupComposeNamespaceBySlug(ctx, s, "ns1")
h.a.NoError(err)
mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, ns.ID, "mod1")
h.a.NoError(err)
records, _, err := store.SearchComposeRecords(ctx, s, mod, types.RecordFilter{})
h.a.NoError(err)
rec := records[0]
for _, r := range rr {
helpers.Allow(r, types.NamespaceRbacResource(0), "read")
helpers.Allow(r, types.ModuleRbacResource(0, 0), "read")
}
helpers.DenyMe(h, rec.RbacResource(), "read")
helpers.Allow(rx["owner"], rec.RbacResource(), "read")
helpers.Allow(rx["creator"], rec.RbacResource(), "read")
helpers.Allow(rx["updater"], rec.RbacResource(), "read")
helpers.Allow(rx["deleter"], rec.RbacResource(), "read")
h.a.NoError(service.UpdateRbacRoles(ctx, testApp.Log, rbac.Global(), nil, nil, nil))
rbac.Global().Reload(ctx)
t.Run("generic user with no ctx role", func(t *testing.T) {
h.apiInit().
Get(fmt.Sprintf("/namespace/%d/module/%d/record/%d", mod.NamespaceID, mod.ID, rec.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertError("record.errors.notAllowedToRead")).
End()
})
t.Run("user with owner ctx role", func(t *testing.T) {
h.identityToHelper(ux["owner"])
h.apiInit().
Get(fmt.Sprintf("/namespace/%d/module/%d/record/%d", mod.NamespaceID, mod.ID, rec.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
})
t.Run("user with creator ctx role", func(t *testing.T) {
h.identityToHelper(ux["creator"])
h.apiInit().
Get(fmt.Sprintf("/namespace/%d/module/%d/record/%d", mod.NamespaceID, mod.ID, rec.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
})
t.Run("user with updater ctx role", func(t *testing.T) {
h.identityToHelper(ux["updater"])
h.apiInit().
Get(fmt.Sprintf("/namespace/%d/module/%d/record/%d", mod.NamespaceID, mod.ID, rec.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
})
t.Run("user with deleter ctx role", func(t *testing.T) {
h.identityToHelper(ux["deleter"])
h.apiInit().
Get(fmt.Sprintf("/namespace/%d/module/%d/record/%d", mod.NamespaceID, mod.ID, rec.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
})
t.Run("user with creator ctx role", func(t *testing.T) {
h.identityToHelper(ux["creator"])
h.apiInit().
Get(fmt.Sprintf("/namespace/%d/module/%d/record/%d", mod.NamespaceID, mod.ID, rec.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
})
t.Run("user with creator ctx role", func(t *testing.T) {
h.identityToHelper(ux["creator"])
h.apiInit().
Get(fmt.Sprintf("/namespace/%d/module/%d/record/%d", mod.NamespaceID, mod.ID, rec.ID)).
Header("Accept", "application/json").
Expect(t).
Status(http.StatusOK).
Assert(helpers.AssertNoErrors).
End()
})
}
@@ -0,0 +1,30 @@
namespaces:
ns1:
name: ns1 name
modules:
mod1:
name: mod1 name
fields:
f1:
label: f1 label
kind: String
required: true
f2:
label: f2 label
kind: Select
options:
options:
- f2 opt 1
- f2 opt 2
- f2 opt 3
records:
mod1:
- createdBy: user_createdby
updatedBy: user_updatedby
deletedBy: user_deletedby
ownedBy: user_ownedby
values:
f1: "mod1 f1 v1"
f2: "f2 opt 1"
@@ -0,0 +1,49 @@
users:
user_createdby:
email: user_createdby@test.tld
name: creator
user_updatedby:
email: user_updatedby@test.tld
name: updater
user_deletedby:
email: user_deletedby@test.tld
name: deleter
user_ownedby:
email: user_ownedby@test.tld
name: owner
roles:
owner:
name: Owner
meta:
context:
expr: resource.ownedBy == userID
resourceType:
- corteza::compose:record
creator:
name: Creator
meta:
context:
expr: resource.createdBy == userID
resourceType:
- corteza::compose:record
updater:
name: Updater
meta:
context:
expr: resource.updatedBy == userID
resourceType:
- corteza::compose:record
deleter:
name: Deleter
meta:
context:
expr: resource.deletedBy == userID
resourceType:
- corteza::compose:record
+13
View File
@@ -7,6 +7,7 @@ import (
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/pkg/eventbus"
"github.com/cortezaproject/corteza-server/pkg/rbac"
"github.com/cortezaproject/corteza-server/system/types"
)
type (
@@ -41,12 +42,24 @@ func AllowMe(mrg myRoleGetter, r string, oo ...string) {
}
}
func Allow(role *types.Role, r string, oo ...string) {
for _, o := range oo {
Grant(rbac.AllowRule(role.ID, r, o))
}
}
func DenyMe(mrg myRoleGetter, r string, oo ...string) {
for _, o := range oo {
Grant(rbac.DenyRule(mrg.MyRole(), r, o))
}
}
func Deny(role *types.Role, r string, oo ...string) {
for _, o := range oo {
Grant(rbac.DenyRule(role.ID, r, o))
}
}
func Grant(rr ...*rbac.Rule) {
cli.HandleError(rbac.Global().Grant(context.Background(), rr...))
}