Permissioning/Authorization (not Authentication) is a cross-cutting concern, I think.
In an Onion Architecture or Hexagonal Architecture, where should permissioning be performed? Examples of permissioning required would be:
- Filtering data returned to the front end (UI, API, or otherwise)
- Validating that a business operation can be performed at all
Ideally, via the Single Responsibility Principle, the code that performs the business operations and returns data shouldn't need to be aware of a user's permissions at all. The implementations of that functionality should know how to perform business operations or query a repository or domain service - that's it.
Would a wrapper/facade implementing the same interface as the class performing the business operation or returning the data be the place to put this permissioning? Or is there a better way?
Also, if the best practice is to permission by activity, not by role, is it still valid to say permissioning should be performed by a service whose purpose is simply to return data?
One could argue that access checking should always be as close to the code that performs the operation as possible to reduce the chance that someone can find a side-channel that bypasses access checking. That said, if you can use a wrapper class such that you guarantee that in the production system access checking will always be in place, I think it is fine.
I find that it is very natural to put access checks that determine if an operation can be performed or not in a wrapper. The wrapper code is typically simple glue that understands the arguments that are being passed to the protected function and converts those into a form appropriate for making authorization decisions.
By this I am assuming that you mean filtering rows out of a query's response based on the permissions of the caller. For example, if a department manager makes a query for everyone's salary, the manager would be returned only the salaries of people who report to him/her as they don't have permission to access other people's salaries.
For this type of filtering I have never found a way of implementing it as a crosscutting concern. I have either baked filtering into the business logic or fallen back on a model that simply refuses to allow the query to execute due to lack of permission.
The problem that I've faced is that, to enable filtering, the security code must look at the data that is returned and be able to associate permissions with it. It seems a fair amount of work to do this in the simple case and downright hairy in the complex case (imagine a data set being returned that is a join of several database operations).
That said, I'm not against the content filtering. I just haven't seen a good solution for it.