add(crm): check service access permissions
This commit is contained in:
18
crm/rest/middleware.go
Normal file
18
crm/rest/middleware.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/crusttech/crust/crm/service"
|
||||
)
|
||||
|
||||
func middlewareAllowedAccess(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !service.DefaultPermissions.With(r.Context()).CanAccessCompose() {
|
||||
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
@@ -16,11 +16,12 @@ func MountRoutes() func(chi.Router) {
|
||||
notification = Notification{}.New()
|
||||
)
|
||||
|
||||
// Initialize handers & controllers.
|
||||
// Initialize handlers & controllers.
|
||||
return func(r chi.Router) {
|
||||
// Protect all _private_ routes
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(auth.MiddlewareValidOnly)
|
||||
r.Use(middlewareAllowedAccess)
|
||||
|
||||
handlers.NewPage(page).MountRoutes(r)
|
||||
handlers.NewModule(module).MountRoutes(r)
|
||||
|
||||
@@ -63,20 +63,6 @@ func TestMain(m *testing.M) {
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func db() *factory.DB {
|
||||
return factory.Database.MustGet()
|
||||
}
|
||||
|
||||
func must(t *testing.T, err error, message ...string) {
|
||||
prefix := "Error"
|
||||
if len(message) > 0 {
|
||||
prefix = message[0]
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf(prefix+": %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func assert(t *testing.T, ok bool, format string, args ...interface{}) bool {
|
||||
if !ok {
|
||||
t.Fatalf(format, args...)
|
||||
|
||||
64
crm/service/permissions.go
Normal file
64
crm/service/permissions.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crusttech/crust/crm/repository"
|
||||
internalRules "github.com/crusttech/crust/internal/rules"
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
)
|
||||
|
||||
type (
|
||||
permissions struct {
|
||||
db db
|
||||
ctx context.Context
|
||||
|
||||
prm systemService.PermissionsService
|
||||
}
|
||||
|
||||
// Fallback option
|
||||
Fallback func() bool
|
||||
|
||||
PermissionsService interface {
|
||||
With(context.Context) PermissionsService
|
||||
|
||||
CanAccessCompose() bool
|
||||
}
|
||||
)
|
||||
|
||||
func Permissions() PermissionsService {
|
||||
return (&permissions{
|
||||
prm: systemService.DefaultPermissions,
|
||||
}).With(context.Background())
|
||||
}
|
||||
|
||||
func (p *permissions) With(ctx context.Context) PermissionsService {
|
||||
db := repository.DB(ctx)
|
||||
return &permissions{
|
||||
db: db,
|
||||
ctx: ctx,
|
||||
|
||||
prm: p.prm.With(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *permissions) CanAccessCompose() bool {
|
||||
return p.checkAccess("compose", "access")
|
||||
}
|
||||
|
||||
func (p *permissions) checkAccess(resource string, operation string, fbs ...Fallback) bool {
|
||||
access := p.prm.Check(resource, operation)
|
||||
switch access {
|
||||
case internalRules.Allow:
|
||||
return true
|
||||
case internalRules.Deny:
|
||||
return false
|
||||
default:
|
||||
for _, fb := range fbs {
|
||||
if fb() == true {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
62
crm/service/permissions_test.go
Normal file
62
crm/service/permissions_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/crusttech/crust/internal/auth"
|
||||
"github.com/crusttech/crust/internal/rules"
|
||||
. "github.com/crusttech/crust/internal/test"
|
||||
|
||||
systemService "github.com/crusttech/crust/system/service"
|
||||
systemTypes "github.com/crusttech/crust/system/types"
|
||||
)
|
||||
|
||||
func TestPermissions(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
// Create user with role and add it to context.
|
||||
userSvc := systemService.User().With(ctx)
|
||||
user := &systemTypes.User{
|
||||
Name: "John Crm Doe",
|
||||
Username: "johndoe",
|
||||
SatosaID: "12345",
|
||||
}
|
||||
err := user.GeneratePassword("johndoe")
|
||||
NoError(t, err, "expected no error generating password, got %v", err)
|
||||
|
||||
_, err = userSvc.Create(user)
|
||||
NoError(t, err, "expected no error creating user, got %v", err)
|
||||
|
||||
roleSvc := systemService.Role().With(ctx)
|
||||
role := &systemTypes.Role{
|
||||
Name: "Test role v1",
|
||||
}
|
||||
role, err = roleSvc.Create(role)
|
||||
NoError(t, err, "expected no error creating role, got %v", err)
|
||||
|
||||
err = roleSvc.MemberAdd(role.ID, user.ID)
|
||||
NoError(t, err, "expected no error adding user to role, got %v", err)
|
||||
|
||||
// Set Identity.
|
||||
ctx = auth.SetIdentityToContext(ctx, user)
|
||||
|
||||
// Generate services.
|
||||
permissionsSvc := Permissions().With(ctx)
|
||||
systemPermissionSvc := systemService.Permissions().With(ctx)
|
||||
|
||||
// Test `access` to compose service.
|
||||
ret := permissionsSvc.CanAccessCompose()
|
||||
Assert(t, ret == false, "expected CanAccessCompose == false, 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)
|
||||
NoError(t, err, "expected no error, got %v", err)
|
||||
|
||||
// Test `access` to compose service.
|
||||
ret = permissionsSvc.CanAccessCompose()
|
||||
Assert(t, ret == true, "expected CanAccessCompose == true, got %v", ret)
|
||||
}
|
||||
@@ -4,6 +4,12 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
db interface {
|
||||
Transaction(callback func() error) error
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
o sync.Once
|
||||
DefaultRecord RecordService
|
||||
@@ -12,6 +18,7 @@ var (
|
||||
DefaultChart ChartService
|
||||
DefaultPage PageService
|
||||
DefaultNotification NotificationService
|
||||
DefaultPermissions PermissionsService
|
||||
)
|
||||
|
||||
func Init() {
|
||||
@@ -22,5 +29,6 @@ func Init() {
|
||||
DefaultPage = Page()
|
||||
DefaultChart = Chart()
|
||||
DefaultNotification = Notification()
|
||||
DefaultPermissions = Permissions()
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user