3
0

Add user-resource permission checking

We check for update, suspend, unsuspend, delete and create,
reading is not checked
This commit is contained in:
Denis Arh 2019-03-25 07:04:27 +01:00
parent 37f24d01fb
commit aa4f705227
5 changed files with 91 additions and 5 deletions

View File

@ -163,6 +163,7 @@ func (r *role) Reset() error {
// Value: Allow (2), Deny (1), Inherit(0)
sql = `REPLACE INTO sys_rules (rel_role, resource, operation, value) VALUES
-- Everyone
(1, 'system', 'user.create', 2),
(1, 'compose:*', 'access', 2),
(1, 'messaging:*', 'access', 2),
-- Admins
@ -188,8 +189,14 @@ func (r *role) Reset() error {
(2, 'system', 'access', 2),
(2, 'system', 'grant', 2),
(2, 'system', 'organisation.create', 2),
(2, 'system', 'user.create', 2),
(2, 'system', 'role.create', 2),
(2, 'system:organisation:*', 'access', 2),
(2, 'system:user:*', 'read', 2),
(2, 'system:user:*', 'update', 2),
(2, 'system:user:*', 'suspend', 2),
(2, 'system:user:*', 'unsuspend', 2),
(2, 'system:user:*', 'delete', 2),
(2, 'system:role:*', 'read', 2),
(2, 'system:role:*', 'update', 2),
(2, 'system:role:*', 'delete', 2),

View File

@ -26,6 +26,7 @@ type (
Effective() (ee []effectivePermission, err error)
CanCreateOrganisation() bool
CanCreateUser() bool
CanCreateRole() bool
CanCreateApplication() bool
@ -37,6 +38,11 @@ type (
CanReadApplication(app *types.Application) bool
CanUpdateApplication(app *types.Application) bool
CanDeleteApplication(app *types.Application) bool
CanUpdateUser(u *types.User) bool
CanSuspendUser(u *types.User) bool
CanUnsuspendUser(u *types.User) bool
CanDeleteUser(u *types.User) bool
}
effectivePermission struct {
@ -88,6 +94,10 @@ func (p *permissions) CanCreateOrganisation() bool {
return p.checkAccess(types.PermissionResource, "organisation.create")
}
func (p *permissions) CanCreateUser() bool {
return p.checkAccess(types.PermissionResource, "user.create", p.allow())
}
func (p *permissions) CanCreateRole() bool {
return p.checkAccess(types.PermissionResource, "role.create")
}
@ -124,6 +134,22 @@ func (p *permissions) CanDeleteApplication(app *types.Application) bool {
return p.checkAccess(app, "delete")
}
func (p *permissions) CanUpdateUser(u *types.User) bool {
return p.checkAccess(u, "update")
}
func (p *permissions) CanSuspendUser(u *types.User) bool {
return p.checkAccess(u, "suspend")
}
func (p *permissions) CanUnsuspendUser(u *types.User) bool {
return p.checkAccess(u, "unsuspend")
}
func (p *permissions) CanDeleteUser(u *types.User) bool {
return p.checkAccess(u, "delete")
}
func (p *permissions) checkAccess(r resource, operation string, fallbacks ...internalRules.CheckAccessFunc) bool {
return p.rules.Check(r.PermissionResource(), operation, fallbacks...) == internalRules.Allow
}

View File

@ -6,6 +6,7 @@ import (
"github.com/pkg/errors"
"github.com/titpetric/factory"
internalAuth "github.com/crusttech/crust/internal/auth"
"github.com/crusttech/crust/system/internal/repository"
"github.com/crusttech/crust/system/types"
)
@ -22,6 +23,8 @@ type (
db *factory.DB
ctx context.Context
prm PermissionsService
user repository.UserRepository
}
@ -57,20 +60,54 @@ func (svc *user) With(ctx context.Context) UserService {
return &user{
db: db,
ctx: ctx,
prm: DefaultPermissions,
user: repository.User(ctx, db),
}
}
func (svc *user) Delete(id uint64) error {
return svc.user.DeleteByID(id)
return svc.db.Transaction(func() (err error) {
var u *types.User
if u, err = svc.user.FindByID(id); err != nil {
return
}
if !svc.prm.CanDeleteUser(u) {
return errors.New("not allowed to update this user")
}
return svc.user.DeleteByID(id)
})
}
func (svc *user) Suspend(id uint64) error {
return svc.user.SuspendByID(id)
return svc.db.Transaction(func() (err error) {
var u *types.User
if u, err = svc.user.FindByID(id); err != nil {
return
}
if !svc.prm.CanSuspendUser(u) {
return errors.New("not allowed to update this user")
}
return svc.user.SuspendByID(id)
})
}
func (svc *user) Unsuspend(id uint64) error {
return svc.user.UnsuspendByID(id)
return svc.db.Transaction(func() (err error) {
var u *types.User
if u, err = svc.user.FindByID(id); err != nil {
return
}
if !svc.prm.CanUnsuspendUser(u) {
return errors.New("not allowed to update this user")
}
return svc.user.UnsuspendByID(id)
})
}
func (svc *user) ValidateCredentials(username, password string) (*types.User, error) {
@ -121,6 +158,7 @@ func (svc *user) FindOrCreate(user *types.User) (out *types.User, err error) {
out, err = svc.user.FindBySatosaID(user.SatosaID)
if err == repository.ErrUserNotFound {
// @todo do we allow autocreation of nonexisting users?
out, err = svc.user.Create(user)
return err
}
@ -130,7 +168,6 @@ func (svc *user) FindOrCreate(user *types.User) (out *types.User, err error) {
return err
}
// @todo need to be more selective with fields we update...
out, err = svc.user.Update(out)
if err != nil {
return err
@ -142,10 +179,14 @@ func (svc *user) FindOrCreate(user *types.User) (out *types.User, err error) {
func (svc *user) Create(input *types.User) (out *types.User, err error) {
return out, svc.db.Transaction(func() error {
// Encrypt user password
if out, err = svc.user.Create(input); err != nil {
return err
}
if !svc.prm.CanCreateUser() {
return errors.New("not allowed to create users")
}
return nil
})
}
@ -156,6 +197,10 @@ func (svc *user) Update(mod *types.User) (u *types.User, err error) {
return
}
if mod.ID != internalAuth.GetIdentityFromContext(svc.ctx).Identity() && !svc.prm.CanUpdateUser(u) {
return errors.New("not allowed to update this user")
}
// Assign changed values
u.Email = mod.Email
u.Username = mod.Username

View File

@ -7,4 +7,5 @@ import (
const PermissionResource = rules.Resource("system")
const ApplicationPermissionResource = rules.Resource("system:application:")
const OrganisationPermissionResource = rules.Resource("system:organisation:")
const UserPermissionResource = rules.Resource("system:user:")
const RolePermissionResource = rules.Resource("system:role:")

View File

@ -5,6 +5,8 @@ import (
"github.com/jmoiron/sqlx/types"
"golang.org/x/crypto/bcrypt"
"github.com/crusttech/crust/internal/rules"
)
type (
@ -61,3 +63,8 @@ func (u *User) GeneratePassword(password string) error {
u.Password = pwd
return nil
}
// Resource returns a resource ID for this type
func (u *User) PermissionResource() rules.Resource {
return UserPermissionResource.AppendID(u.ID)
}