diff --git a/crm/service/permissions.go b/crm/service/permissions.go index 8097d1dc8..87412887e 100644 --- a/crm/service/permissions.go +++ b/crm/service/permissions.go @@ -13,7 +13,7 @@ type ( db db ctx context.Context - prm systemService.PermissionsService + rules systemService.RulesService } PermissionsService interface { @@ -25,7 +25,7 @@ type ( func Permissions() PermissionsService { return (&permissions{ - prm: systemService.DefaultPermissions, + rules: systemService.DefaultRules, }).With(context.Background()) } @@ -35,7 +35,7 @@ func (p *permissions) With(ctx context.Context) PermissionsService { db: db, ctx: ctx, - prm: p.prm.With(ctx), + rules: p.rules.With(ctx), } } @@ -43,8 +43,12 @@ func (p *permissions) CanAccessCompose() bool { return p.checkAccess("compose", "access") } +func (p *permissions) CanCreateNamspace() bool { + return p.checkAccess("compose", "namespace.create") +} + func (p *permissions) checkAccess(resource string, operation string, fallbacks ...internalRules.CheckAccessFunc) bool { - access := p.prm.Check(resource, operation, fallbacks...) + access := p.rules.Check(resource, operation, fallbacks...) if access == internalRules.Allow { return true } diff --git a/crm/service/permissions_test.go b/crm/service/permissions_test.go index 0759035eb..a439972bf 100644 --- a/crm/service/permissions_test.go +++ b/crm/service/permissions_test.go @@ -57,17 +57,17 @@ func TestPermissions(t *testing.T) { // Generate services. permissionsSvc := Permissions().With(ctx) - systemPermissionSvc := systemService.Permissions().With(ctx) + systemRulesSvc := systemService.Rules().With(ctx) // Test `access` to compose service. ret := permissionsSvc.CanAccessCompose() - Assert(t, ret == false, "expected CanAccessCompose == false, got %v", ret) + Assert(t, ret == true, "expected CanAccessCompose == true, got %v", ret) // Add `access` to compose service. list := []rules.Rule{ rules.Rule{Resource: "compose", Operation: "access", Value: rules.Allow}, } - _, err = systemPermissionSvc.Update(role.ID, list) + _, err = systemRulesSvc.Update(role.ID, list) NoError(t, err, "expected no error, got %v", err) // Test `access` to compose service. diff --git a/messaging/service/permissions.go b/messaging/service/permissions.go index cf385d3eb..28d273c17 100644 --- a/messaging/service/permissions.go +++ b/messaging/service/permissions.go @@ -14,7 +14,7 @@ type ( db db ctx context.Context - prm systemService.PermissionsService + rules systemService.RulesService } PermissionsService interface { @@ -47,7 +47,7 @@ type ( func Permissions() PermissionsService { return (&permissions{ - prm: systemService.Permissions(), + rules: systemService.Rules(), }).With(context.Background()) } @@ -57,7 +57,7 @@ func (p *permissions) With(ctx context.Context) PermissionsService { db: db, ctx: ctx, - prm: p.prm.With(ctx), + rules: p.rules.With(ctx), } } @@ -138,7 +138,7 @@ func (p *permissions) CanReactMessage(ch *types.Channel) bool { } func (p *permissions) checkAccess(resource string, operation string, fallbacks ...internalRules.CheckAccessFunc) bool { - access := p.prm.Check(resource, operation, fallbacks...) + access := p.rules.Check(resource, operation, fallbacks...) if access == internalRules.Allow { return true } diff --git a/messaging/service/permissions_test.go b/messaging/service/permissions_test.go index 14bf7e2dc..497ea03cc 100644 --- a/messaging/service/permissions_test.go +++ b/messaging/service/permissions_test.go @@ -64,7 +64,7 @@ func TestPermissions(t *testing.T) { }).With(ctx) permissionsSvc := Permissions().With(ctx) - systemPermissionSvc := systemService.Permissions().With(ctx) + systemRulesSvc := systemService.Rules().With(ctx) // Test `access` to messaging service. ret := permissionsSvc.CanAccessMessaging() @@ -74,7 +74,7 @@ func TestPermissions(t *testing.T) { list := []rules.Rule{ rules.Rule{Resource: "messaging", Operation: "access", Value: rules.Allow}, } - _, err = systemPermissionSvc.Update(role.ID, list) + _, err = systemRulesSvc.Update(role.ID, list) NoError(t, err, "expected no error, got %v", err) // Test `access` to messaging service. @@ -100,7 +100,7 @@ func TestPermissions(t *testing.T) { list = []rules.Rule{ rules.Rule{Resource: "messaging:channel:*", Operation: "read", Value: rules.Allow}, } - _, err = systemPermissionSvc.Update(role.ID, list) + _, err = systemRulesSvc.Update(role.ID, list) NoError(t, err, "expected no error, got %v", err) ret = permissionsSvc.CanRead(ch) @@ -113,7 +113,7 @@ func TestPermissions(t *testing.T) { list = []rules.Rule{ rules.Rule{Resource: "messaging:channel:*", Operation: "join", Value: rules.Deny}, } - _, err = systemPermissionSvc.Update(role.ID, list) + _, err = systemRulesSvc.Update(role.ID, list) NoError(t, err, "expected no error, got %v", err) ret = permissionsSvc.CanJoin(ch) @@ -123,7 +123,7 @@ func TestPermissions(t *testing.T) { list = []rules.Rule{ rules.Rule{Resource: ch.Resource().String(), Operation: "join", Value: rules.Allow}, } - _, err = systemPermissionSvc.Update(role.ID, list) + _, err = systemRulesSvc.Update(role.ID, list) NoError(t, err, "expected no error, got %v", err) ret = permissionsSvc.CanJoin(ch) diff --git a/system/rest/permissions.go b/system/rest/permissions.go index cdf84c6fc..9fa75cf90 100644 --- a/system/rest/permissions.go +++ b/system/rest/permissions.go @@ -14,29 +14,29 @@ var _ = errors.Wrap type ( Permissions struct { svc struct { - perm service.PermissionsService + rules service.RulesService } } ) func (Permissions) New() *Permissions { ctrl := &Permissions{} - ctrl.svc.perm = service.DefaultPermissions + ctrl.svc.rules = service.DefaultRules return ctrl } func (ctrl *Permissions) List(ctx context.Context, r *request.PermissionsList) (interface{}, error) { - return ctrl.svc.perm.List() + return ctrl.svc.rules.List() } func (ctrl *Permissions) Read(ctx context.Context, r *request.PermissionsRead) (interface{}, error) { - return ctrl.svc.perm.Read(r.RoleID) + return ctrl.svc.rules.Read(r.RoleID) } func (ctrl *Permissions) Delete(ctx context.Context, r *request.PermissionsDelete) (interface{}, error) { - return ctrl.svc.perm.Delete(r.RoleID) + return ctrl.svc.rules.Delete(r.RoleID) } func (ctrl *Permissions) Update(ctx context.Context, r *request.PermissionsUpdate) (interface{}, error) { - return ctrl.svc.perm.Update(r.RoleID, r.Permissions) + return ctrl.svc.rules.Update(r.RoleID, r.Permissions) } diff --git a/system/service/permissions.go b/system/service/rules.go similarity index 59% rename from system/service/permissions.go rename to system/service/rules.go index 6bfd5c54e..6697633ae 100644 --- a/system/service/permissions.go +++ b/system/service/rules.go @@ -6,7 +6,7 @@ import ( "github.com/pkg/errors" - "github.com/crusttech/crust/internal/rules" + internalRules "github.com/crusttech/crust/internal/rules" "github.com/crusttech/crust/system/repository" "github.com/crusttech/crust/system/types" ) @@ -16,41 +16,41 @@ const ( ) type ( - permissions struct { + rules struct { db db ctx context.Context - resources rules.ResourcesInterface + resources internalRules.ResourcesInterface } - PermissionsService interface { - With(ctx context.Context) PermissionsService + RulesService interface { + With(ctx context.Context) RulesService List() (interface{}, error) - Check(resource string, operation string, fallbacks ...rules.CheckAccessFunc) rules.Access + Check(resource string, operation string, fallbacks ...internalRules.CheckAccessFunc) internalRules.Access Read(roleID uint64) (interface{}, error) - Update(roleID uint64, rules []rules.Rule) (interface{}, error) + Update(roleID uint64, rules []internalRules.Rule) (interface{}, error) Delete(roleID uint64) (interface{}, error) } ) -func Permissions() PermissionsService { - return (&permissions{}).With(context.Background()) +func Rules() RulesService { + return (&rules{}).With(context.Background()) } -func (p *permissions) With(ctx context.Context) PermissionsService { +func (p *rules) With(ctx context.Context) RulesService { db := repository.DB(ctx) - return &permissions{ + return &rules{ db: db, ctx: ctx, - resources: rules.NewResources(ctx, db), + resources: internalRules.NewResources(ctx, db), } } -func (p *permissions) List() (interface{}, error) { +func (p *rules) List() (interface{}, error) { perms := []types.Permission{} for resource, operations := range permissionList { err := p.checkServiceAccess(resource) @@ -63,18 +63,18 @@ func (p *permissions) List() (interface{}, error) { return perms, nil } -func (p *permissions) Check(resource string, operation string, fallbacks ...rules.CheckAccessFunc) rules.Access { +func (p *rules) Check(resource string, operation string, fallbacks ...internalRules.CheckAccessFunc) internalRules.Access { return p.resources.Check(resource, operation, fallbacks...) } -func (p *permissions) Read(roleID uint64) (interface{}, error) { +func (p *rules) Read(roleID uint64) (interface{}, error) { ret, err := p.resources.Read(roleID) if err != nil { return nil, err } // Only display rules under granted scopes. - rules := []rules.Rule{} + rules := []internalRules.Rule{} for _, rule := range ret { err = p.checkServiceAccess(rule.Resource) if err == nil { @@ -84,7 +84,7 @@ func (p *permissions) Read(roleID uint64) (interface{}, error) { return rules, nil } -func (p *permissions) Update(roleID uint64, rules []rules.Rule) (interface{}, error) { +func (p *rules) Update(roleID uint64, rules []internalRules.Rule) (interface{}, error) { for _, rule := range rules { err := validatePermission(rule.Resource, rule.Operation) if err != nil { @@ -102,15 +102,15 @@ func (p *permissions) Update(roleID uint64, rules []rules.Rule) (interface{}, er return p.resources.Read(roleID) } -func (p *permissions) Delete(roleID uint64) (interface{}, error) { +func (p *rules) Delete(roleID uint64) (interface{}, error) { return nil, p.resources.Delete(roleID) } -func (p *permissions) checkServiceAccess(resource string) error { +func (p *rules) checkServiceAccess(resource string) error { service := strings.Split(resource, delimiter)[0] grant := p.resources.Check(service, "grant") - if grant == rules.Allow { + if grant == internalRules.Allow { return nil } return errors.Errorf("No grant permissions for: %v", service) diff --git a/system/service/permissions_test.go b/system/service/rules_test.go similarity index 52% rename from system/service/permissions_test.go rename to system/service/rules_test.go index e6302b2bc..7b4833780 100644 --- a/system/service/permissions_test.go +++ b/system/service/rules_test.go @@ -7,14 +7,14 @@ import ( "github.com/titpetric/factory" internalAuth "github.com/crusttech/crust/internal/auth" - "github.com/crusttech/crust/internal/rules" + internalRules "github.com/crusttech/crust/internal/rules" . "github.com/crusttech/crust/internal/test" "github.com/crusttech/crust/system/repository" "github.com/crusttech/crust/system/types" ) -func TestPermission(t *testing.T) { +func TestRules(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode.") return @@ -48,26 +48,26 @@ func TestPermission(t *testing.T) { // Set Identity. ctx = internalAuth.SetIdentityToContext(ctx, user) - // Create permission service. - permissionSvc := Permissions().With(ctx) + // Create rules service. + rulesSvc := Rules().With(ctx) // Update rules for test role, with error. { - list := []rules.Rule{ - rules.Rule{Resource: "messaging:channel:1", Operation: "message.update.all", Value: rules.Allow}, + list := []internalRules.Rule{ + internalRules.Rule{Resource: "messaging:channel:1", Operation: "message.update.all", Value: internalRules.Allow}, } - _, err := permissionSvc.Update(role.ID, list) - Error(t, err, "expected error == No Allow permissions for: messaging") + _, err := rulesSvc.Update(role.ID, list) + Error(t, err, "expected error == No Allow rule for messaging") } // Insert `grant` permission for `messaging` and `system`. { db := repository.DB(ctx) - resources := rules.NewResources(ctx, db) + resources := internalRules.NewResources(ctx, db) - list := []rules.Rule{ - rules.Rule{Resource: "system", Operation: "grant", Value: rules.Allow}, - rules.Rule{Resource: "messaging", Operation: "grant", Value: rules.Allow}, + list := []internalRules.Rule{ + internalRules.Rule{Resource: "system", Operation: "grant", Value: internalRules.Allow}, + internalRules.Rule{Resource: "messaging", Operation: "grant", Value: internalRules.Allow}, } err := resources.Grant(role.ID, list) @@ -76,7 +76,7 @@ func TestPermission(t *testing.T) { // List possible permissions with `messaging` and `system` grants. { - ret, err := permissionSvc.List() + ret, err := rulesSvc.List() NoError(t, err, "expected no error, got %v", err) perms := ret.([]types.Permission) @@ -86,74 +86,74 @@ func TestPermission(t *testing.T) { // Update rules for test role. { - list := []rules.Rule{ - rules.Rule{Resource: "messaging:channel:*", Operation: "message.update.all", Value: rules.Allow}, - rules.Rule{Resource: "messaging:channel:1", Operation: "message.update.all", Value: rules.Deny}, - rules.Rule{Resource: "messaging:channel:2", Operation: "message.update.all"}, - rules.Rule{Resource: "system", Operation: "organisation.create", Value: rules.Allow}, - rules.Rule{Resource: "system:organisation:*", Operation: "access", Value: rules.Allow}, - rules.Rule{Resource: "messaging:channel", Operation: "message.update.all", Value: rules.Allow}, + list := []internalRules.Rule{ + internalRules.Rule{Resource: "messaging:channel:*", Operation: "message.update.all", Value: internalRules.Allow}, + internalRules.Rule{Resource: "messaging:channel:1", Operation: "message.update.all", Value: internalRules.Deny}, + internalRules.Rule{Resource: "messaging:channel:2", Operation: "message.update.all"}, + internalRules.Rule{Resource: "system", Operation: "organisation.create", Value: internalRules.Allow}, + internalRules.Rule{Resource: "system:organisation:*", Operation: "access", Value: internalRules.Allow}, + internalRules.Rule{Resource: "messaging:channel", Operation: "message.update.all", Value: internalRules.Allow}, } - _, err := permissionSvc.Update(role.ID, list) + _, err := rulesSvc.Update(role.ID, list) NoError(t, err, "expected no error, got %v", err) } // Update with invalid roles { - list := []rules.Rule{ - rules.Rule{Resource: "nosystem:channel:*", Operation: "message.update.all", Value: rules.Allow}, + list := []internalRules.Rule{ + internalRules.Rule{Resource: "nosystem:channel:*", Operation: "message.update.all", Value: internalRules.Allow}, } - _, err := permissionSvc.Update(role.ID, list) + _, err := rulesSvc.Update(role.ID, list) Error(t, err, "expected error") - list = []rules.Rule{ - rules.Rule{Resource: "messaging:noresource:1", Operation: "message.update.all", Value: rules.Deny}, + list = []internalRules.Rule{ + internalRules.Rule{Resource: "messaging:noresource:1", Operation: "message.update.all", Value: internalRules.Deny}, } - _, err = permissionSvc.Update(role.ID, list) + _, err = rulesSvc.Update(role.ID, list) Error(t, err, "expected error") - list = []rules.Rule{ - rules.Rule{Resource: "messaging:channel:", Operation: "message.update.all"}, + list = []internalRules.Rule{ + internalRules.Rule{Resource: "messaging:channel:", Operation: "message.update.all"}, } - _, err = permissionSvc.Update(role.ID, list) + _, err = rulesSvc.Update(role.ID, list) Error(t, err, "expected error") - list = []rules.Rule{ - rules.Rule{Resource: "system:organisation:*", Operation: "invalid", Value: rules.Allow}, + list = []internalRules.Rule{ + internalRules.Rule{Resource: "system:organisation:*", Operation: "invalid", Value: internalRules.Allow}, } - _, err = permissionSvc.Update(role.ID, list) + _, err = rulesSvc.Update(role.ID, list) Error(t, err, "expected error") } // Read rules for test role. { - ret, err := permissionSvc.Read(role.ID) + ret, err := rulesSvc.Read(role.ID) NoError(t, err, "expected no error, got %v", err) - rules := ret.([]rules.Rule) + rules := ret.([]internalRules.Rule) Assert(t, len(rules) == 7, "expected len(rules) == 7, got %v", len(rules)) } // Delete rules for test role. { - _, err := permissionSvc.Delete(role.ID) + _, err := rulesSvc.Delete(role.ID) NoError(t, err, "expected no error, got %v", err) } // Read rules for test role. { - ret, err := permissionSvc.Read(role.ID) + ret, err := rulesSvc.Read(role.ID) NoError(t, err, "expected no error, got %v", err) - rules := ret.([]rules.Rule) + rules := ret.([]internalRules.Rule) Assert(t, len(rules) == 0, "expected len(rules) == 0, got %v", len(rules)) } // List possible permissions with no grants. { - ret, err := permissionSvc.List() + ret, err := rulesSvc.List() NoError(t, err, "expected no error, got %v", err) perms := ret.([]types.Permission) diff --git a/system/service/service.go b/system/service/service.go index deb70d75f..f34e1d6a4 100644 --- a/system/service/service.go +++ b/system/service/service.go @@ -15,7 +15,7 @@ var ( DefaultAuth AuthService DefaultUser UserService DefaultRole RoleService - DefaultPermissions PermissionsService + DefaultRules RulesService DefaultOrganisation OrganisationService DefaultApplication ApplicationService ) @@ -25,7 +25,7 @@ func Init() { DefaultAuth = Auth() DefaultUser = User() DefaultRole = Role() - DefaultPermissions = Permissions() + DefaultRules = Rules() DefaultOrganisation = Organisation() DefaultApplication = Application() })