Mise en place d'un système de vérification des autorisations côté

serveur

- Création d'un service d'autorisation dynamique basé sur des "voter" (à
  la Symfony)
- Mise en place des autorisations sur les principales queries/mutations
  de l'API GraphQL
This commit is contained in:
2020-09-04 10:10:32 +02:00
parent bc56c9dbae
commit 3ef495445a
19 changed files with 669 additions and 44 deletions

13
internal/model/action.go Normal file
View File

@ -0,0 +1,13 @@
package model
type Action string
const (
ActionCreate Action = "create"
ActionRead Action = "read"
ActionUpdate Action = "update"
ActionDelete Action = "delete"
ActionJoin Action = "join"
ActionLeave Action = "leave"
ActionClose Action = "close"
)

View File

@ -88,6 +88,17 @@ func (r *DSFRepository) updateFromChanges(dsf *DecisionSupportFile, changes *Dec
return nil
}
func (r *DSFRepository) Find(ctx context.Context, id string) (*DecisionSupportFile, error) {
dsf := &DecisionSupportFile{}
query := r.db.Model(dsf).Preload("Workgroup").Where("id = ?", id)
if err := query.First(&dsf).Error; err != nil {
return nil, errs.WithStack(err)
}
return dsf, nil
}
func (r *DSFRepository) Search(ctx context.Context, filter *DecisionSupportFileFilter) ([]*DecisionSupportFile, error) {
query := r.db.Model(&DecisionSupportFile{}).Preload("Workgroup")

View File

@ -0,0 +1,48 @@
package model
import (
"context"
"forge.cadoles.com/Cadoles/daddy/internal/voter"
)
type DecisionSupportFileVoter struct {
}
func (v *DecisionSupportFileVoter) Vote(ctx context.Context, subject interface{}, obj interface{}, act interface{}) (voter.Decision, error) {
user, ok := subject.(*User)
if !ok {
return voter.Abstain, nil
}
dsf, ok := obj.(*DecisionSupportFile)
if !ok {
return voter.Abstain, nil
}
action, ok := act.(Action)
if !ok {
return voter.Abstain, nil
}
switch action {
case ActionCreate:
return voter.Allow, nil
case ActionRead:
return voter.Allow, nil
case ActionUpdate:
if inWorkgroup(user, dsf.Workgroup) {
return voter.Allow, nil
}
return voter.Deny, nil
case ActionDelete:
return voter.Deny, nil
}
return voter.Abstain, nil
}
func NewDecisionSupportFileVoter() *DecisionSupportFileVoter {
return &DecisionSupportFileVoter{}
}

15
internal/model/helper.go Normal file
View File

@ -0,0 +1,15 @@
package model
func inWorkgroup(user *User, workgroup *Workgroup) bool {
if workgroup == nil {
return false
}
for _, w := range user.Workgroups {
if w.ID == workgroup.ID {
return true
}
}
return false
}

View File

@ -6,6 +6,7 @@ import (
"github.com/jinzhu/gorm"
"github.com/pkg/errors"
errs "github.com/pkg/errors"
)
type WorkgroupRepository struct {
@ -135,6 +136,17 @@ func (r *WorkgroupRepository) RemoveUserFromWorkgroup(ctx context.Context, userI
return workgroup, nil
}
func (r *WorkgroupRepository) Find(ctx context.Context, id string) (*Workgroup, error) {
wg := &Workgroup{}
query := r.db.Model(wg).Where("id = ?", id)
if err := query.First(&wg).Error; err != nil {
return nil, errs.WithStack(err)
}
return wg, nil
}
func NewWorkgroupRepository(db *gorm.DB) *WorkgroupRepository {
return &WorkgroupRepository{db}
}

View File

@ -0,0 +1,54 @@
package model
import (
"context"
"forge.cadoles.com/Cadoles/daddy/internal/voter"
)
type WorkgroupVoter struct {
}
func (v *WorkgroupVoter) Vote(ctx context.Context, subject interface{}, obj interface{}, act interface{}) (voter.Decision, error) {
user, ok := subject.(*User)
if !ok {
return voter.Abstain, nil
}
workgroup, ok := obj.(*Workgroup)
if !ok {
return voter.Abstain, nil
}
action, ok := act.(Action)
if !ok {
return voter.Abstain, nil
}
switch action {
case ActionCreate:
return voter.Allow, nil
case ActionRead:
return voter.Allow, nil
case ActionJoin:
return voter.Allow, nil
case ActionLeave:
fallthrough
case ActionUpdate:
fallthrough
case ActionClose:
if inWorkgroup(user, workgroup) {
return voter.Allow, nil
} else {
return voter.Deny, nil
}
case ActionDelete:
return voter.Deny, nil
}
return voter.Abstain, nil
}
func NewWorkgroupVoter() *WorkgroupVoter {
return &WorkgroupVoter{}
}