package voter import ( "context" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) type Voter interface { Vote(ctx context.Context, subject interface{}, obj interface{}, action interface{}) (Decision, error) } type Strategy func(ctx context.Context, decisions []Decision) (Decision, error) type Manager struct { strategy Strategy voters []Voter } func (m *Manager) Authorized(ctx context.Context, subject interface{}, obj interface{}, action interface{}) (Decision, error) { decisions := make([]Decision, 0, len(m.voters)) logger.Debug( ctx, "checking authorization", logger.F("subject", subject), logger.F("object", obj), logger.F("action", action), ) for _, v := range m.voters { dec, err := v.Vote(ctx, subject, obj, action) if err != nil { return Deny, errors.WithStack(err) } decisions = append(decisions, dec) } result, err := m.strategy(ctx, decisions) if err != nil { return Deny, errors.WithStack(err) } logger.Debug( ctx, "authorization checked", logger.F("subject", subject), logger.F("object", obj), logger.F("action", action), logger.F("result", AsString(result)), ) return result, nil } func NewManager(strategy Strategy, voters ...Voter) *Manager { return &Manager{strategy, voters} }