I'm designing the Authorization part of the AAA module of a business software suite.
- There are Users and Groups, and you can assign Permissions to any of those.
- You can Grant or Deny a permission. When there is a conflict, Deny wins. Deny is also the default permission.
- Client sends a request with a Operation type and parameters (like company, document type, site, user, etc). The Operation type might be domain-specific like "Create new invoice" or more atomic like "Update record for table X".
- The Permission is not only based on Operation type, but also on the specific data the system holds. For example: One permission can say "Allow User X to Create new Invoices", but a more specific one could be "Allow User X to Create new invoices on Company Y, on Site Z".
Data levels for last point are:
* Global (This Permission affects the Operation at every level)
* Company (Affects the Operation for this company)
** DocumentType (Inside this company, Permission only affects this kind of Document)
* Site (Affects the Operation for a specific Site. Sites can have multiple companies, and companies can be in multiple sites)
There can be multiple permissions for the same operation, and they only differ in scope: User X can make a new Invoice for company Y, Can make a new invoice for Company Z, but CANNOT make a new invoice in Site F, for example. So, if the operation requests a new invoice for user x for company z in site f, it should be denied.
- Auth module keeps a list of all permissions for all users and groups in memory.
What I'm doing:
I'm using .NET, so using LINQ I make a query to the Permission lists in memory to get:
- First I get all the permissions for this User for this Operation, and add all the Permissions for the groups the user is in, for this operation.
- In this result, I query for a Global DENY. If exists, Deny Op.
- Then query for a global ALLOW. If exists, note it down and continue next check.
- Then look for all the permissions for the requested company. If there's a Deny, then Deny the whole thing. If Allowed, then note it down and continue next check.
- Do the same thing for requested Site and DocumentType.
- Then look for the exact combination of op/company/site that the request is asking for. If there is a Deny, then deny the whole thing. If Allowed, then note it down and continue next step. If there's no permission and there is also no Allow noted down from previous steps, then deny the request.
- At this point, the request is essentially allowed, but still need to modify the request so that the Query creator can include the specific Deny found, if any, in the DB query. For example, User X is requesting a list of all invoices, has a Global grant to see all invoices, but also has a specific Deny for company Y.
Is there a better way to do this? I mean, I think this is covered by ABAC-implementations like XAMCL, but there are no clients for .NET that we can use (pricing, completion, etc). Thanks.