diff --git a/system/service/application.go b/system/service/application.go index 6c2ea7fde..060c32f9e 100644 --- a/system/service/application.go +++ b/system/service/application.go @@ -3,6 +3,7 @@ package service import ( "context" + "github.com/pkg/errors" "github.com/titpetric/factory" "github.com/crusttech/crust/system/repository" @@ -14,6 +15,8 @@ type ( db *factory.DB ctx context.Context + prm PermissionsService + application repository.ApplicationRepository } @@ -30,7 +33,9 @@ type ( ) func Application() ApplicationService { - return (&application{}).With(context.Background()) + return (&application{ + prm: DefaultPermissions, + }).With(context.Background()) } func (svc *application) With(ctx context.Context) ApplicationService { @@ -38,28 +43,51 @@ func (svc *application) With(ctx context.Context) ApplicationService { return &application{ db: db, ctx: ctx, + prm: svc.prm.With(ctx), application: repository.Application(ctx, db), } } func (svc *application) FindByID(id uint64) (*types.Application, error) { - // @todo: permission check if current user has access to this application - return svc.application.FindByID(id) + app, err := svc.application.FindByID(id) + if err != nil { + return nil, err + } + + if !svc.prm.CanReadApplication(app) { + return nil, errors.New("Not allowed to access application") + } + + return app, nil } func (svc *application) Find() (types.ApplicationSet, error) { - // @todo: permission check to return only applications that current user has access to - return svc.application.Find() + apps, err := svc.application.Find() + if err != nil { + return nil, err + } + + ret := []*types.Application{} + for _, app := range apps { + if svc.prm.CanReadApplication(app) { + ret = append(ret, app) + } + } + return ret, nil } func (svc *application) Create(mod *types.Application) (*types.Application, error) { - // @todo: permission check if current user can add/edit application - + if !svc.prm.CanCreateApplication() { + return nil, errors.New("Not allowed to create application") + } return svc.application.Create(mod) } func (svc *application) Update(mod *types.Application) (t *types.Application, err error) { - // @todo: permission check if current user can add/edit application + if !svc.prm.CanUpdateApplication(mod) { + return nil, errors.New("Not allowed to update application") + } + // @todo: make sure archived & deleted entries can not be edited return t, svc.db.Transaction(func() (err error) { @@ -83,7 +111,11 @@ func (svc *application) Update(mod *types.Application) (t *types.Application, er func (svc *application) DeleteByID(id uint64) error { // @todo: make history unavailable // @todo: notify users that application has been removed (remove from web UI) - // @todo: permissions check if current user can remove application + + app := &types.Application{ID: id} + if !svc.prm.CanDeleteApplication(app) { + return errors.New("Not allowed to delete application") + } return svc.application.DeleteByID(id) } diff --git a/system/service/permissions.go b/system/service/permissions.go index 02835bc29..9df842642 100644 --- a/system/service/permissions.go +++ b/system/service/permissions.go @@ -27,6 +27,10 @@ type ( CanUpdateRole(rl *types.Role) bool CanDeleteRole(rl *types.Role) bool CanManageRoleMembers(rl *types.Role) bool + + CanReadApplication(app *types.Application) bool + CanUpdateApplication(app *types.Application) bool + CanDeleteApplication(app *types.Application) bool } ) @@ -74,6 +78,18 @@ func (p *permissions) CanManageRoleMembers(rl *types.Role) bool { return p.checkAccess(rl.Resource().String(), "members.manage") } +func (p *permissions) CanReadApplication(app *types.Application) bool { + return p.checkAccess(app.Resource().String(), "read") +} + +func (p *permissions) CanUpdateApplication(app *types.Application) bool { + return p.checkAccess(app.Resource().String(), "update") +} + +func (p *permissions) CanDeleteApplication(app *types.Application) bool { + return p.checkAccess(app.Resource().String(), "delete") +} + func (p *permissions) checkAccess(resource string, operation string, fallbacks ...internalRules.CheckAccessFunc) bool { access := p.rules.Check(resource, operation, fallbacks...) if access == internalRules.Allow { diff --git a/system/service/validation.go b/system/service/validation.go index 8a7ac74ea..eca255001 100644 --- a/system/service/validation.go +++ b/system/service/validation.go @@ -23,7 +23,7 @@ var ( "delete": true, "members.manage": true, }, - "application:role": map[string]bool{ + "system:application": map[string]bool{ "read": true, "update": true, "delete": true, diff --git a/system/types/applications.go b/system/types/applications.go index f167565c3..ea609d7e4 100644 --- a/system/types/applications.go +++ b/system/types/applications.go @@ -6,6 +6,8 @@ import ( "time" "github.com/pkg/errors" + + "github.com/crusttech/crust/internal/rules" ) type ( @@ -41,6 +43,19 @@ func (u *Application) Identity() uint64 { return u.ID } +// Resource returns a system resource ID for this type +func (u *Application) Resource() rules.Resource { + resource := rules.Resource{ + Service: "system", + Scope: "application", + } + if u != nil { + resource.ID = u.ID + resource.Name = u.Name + } + return resource +} + func (au *ApplicationUnify) Scan(value interface{}) error { switch value.(type) { case nil: