Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conceptualizing policy layer #15

Closed
blaggacao opened this issue Nov 17, 2020 · 1 comment
Closed

Conceptualizing policy layer #15

blaggacao opened this issue Nov 17, 2020 · 1 comment

Comments

@blaggacao
Copy link
Contributor

blaggacao commented Nov 17, 2020

While thinking about

type Repository interface {
AddTraining(ctx context.Context, tr *Training) error
GetTraining(ctx context.Context, trainingUUID string, user User) (*Training, error)
UpdateTraining(
ctx context.Context,
trainingUUID string,
user User,
updateFn func(ctx context.Context, tr *Training) (*Training, error),
) error
}

I realized that user is passed to implement access policy. As a fan of OPA I immediately wondered how an integration would be best devised.

  1. Generically speaking an external agent only can ever interact with the domain through the application service layer.
  2. The necessary metadata to decide upon an access policy:
  • Identifier of the actor
  • eventually an elevation token
  • an instance of the domain entity (to base decisions on domain values)
  • the command to be executed (probably the most important data point to make a policy decision)
  1. Hence, I'm inclined to thing the policy could be well implemented at the application layer and the domain be freed of any policy decision. Although being part of the business logic, it will be flexibly implemented in the policy service (OPA) based on those data points.

I feel this mental model is advantageous, since the domain logic could be implemented free of any policy considerations.

// StartRecordingHandler knows how to start a recording
type StartRecordingHandler struct {
	aggregate domain.Repository
	commMgr domain.CommManager // interface
	policy app.Policy // policy interface implemented at the application, not the domain layer?
}

// Handle starts a recording
func (h StartRecordingHandler) Handle(ctx context.Context, livecallToStartRecordingFor uuid.UUID, userID uuid.UUID, elevationToken string) error {
	err := h.aggregate.Update(ctx, livecallToStartRecordingFor, func(l *livecall.Livecall) error {
		if ok := h.policy.Can(ctx, "StartRecording", userID, elevationToken, *l); !ok {
			return ErrNotAuthorizedToStartRecording
		}
		if err := l.StartRecording(h.commMgr); err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		return ErrUnableToStartRecording
	}

	return nil
}

}
@blaggacao
Copy link
Contributor Author

blaggacao commented Nov 22, 2020

I implemented this idea in ddd-gen. I'm going to open a new issue with a couple of ideas while working on that. Closing here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant