Add user-resource permission checking
We check for update, suspend, unsuspend, delete and create, reading is not checked
This commit is contained in:
parent
37f24d01fb
commit
aa4f705227
@ -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),
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:")
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user