modernice/goes

contrib/auth: Permission Granter

Closed this issue · 0 comments

Implement a PermissionGranter within the authorization module that grants permissions automatically.

Background

Currently, there is no automated way to grant permissions to actors on specific events. In order to grant permissions when an event is published, the developer must manually implement an event handler that dispatches the GrantToXXX() commands. Additionally, if a developer adds new permissions/actions to the handler, past events must trigger the handler so that actors and roles are granted the new permissions on already existing aggregates.

Proposal

Proposal is to implement a PermissionGranter that can be added to applications as a background task. Users define the events to subscribe to and the events provide the permissions to grant or revoke.

package example

// FooEvent is user-defined event data
type FooEvent {...}

func (evt FooEvent) GrantPermissions(g auth.EventGranter) error {
  // grant actions on the aggregate of the event (evt.Aggregate()) to the given actor
  err := g.GrantToActor(<actor-id>, "action-1", "action-2")

  // revoke actions on the aggregate of the event (evt.Aggregate()) from the given actor
  err := g.RevokeFromActor(<actor-id>, "action-1", "action-2")

  // grant actions on the aggregate of the event (evt.Aggregate()) to the given role
  err := g.GrantToRole(<actor-id>, "action-1", "action-2")

  // revoke actions on the aggregate of the event (evt.Aggregate()) from the given role
  err := g.RevokeFromRole(<actor-id>, "action-1", "action-2")
}

func example(lookup *auth.Lookup,  bus event.Bus, store event.Store) {
  granter := auth.NewPermissionGranter(
    lookup, // lookup is used to lookup actor and role ids
    bus,
    auth.StartupGrant(store), // optionally handle events from the event store when the task is started

    // initial permissions for roles and actors
    auth.InitialRoleGrant(<role-name>, aggregate.Ref{...}, "action-1", "action-2", "..."),
    auth.InitialActorGrant(<actor-string-id>, aggregate.Ref{...}, "action-1", "action-2", "..."),
  )

  errs, err := granter.Run(context.TODO())
}

A Role() method needs to be added to the auth.Lookup for looking up role ids from role names.