DACquiri
A compile-time enforced authorization framework for Rust applications.
Authorization
In typical applications, authorization checks are performed in potentially random segments of the code. This leads to implicit assumptions on what kinds of permissions or checks have been enforced at various parts of the codebase. For example:
// makes no assumptions on a user's permissions or access, initially
// Implicitly depends on user having the "SimplePermissions" permission or role.
DACquiri does things differently.
With DACquiri, you explicitly declare your authorization requirements in the function definition. DACquiri will, at compile-time, enforce all code-paths invoking your function will have checked the appropriate authorization requirements beforehand.
With DACquiri, you:
- Know all of your authorization requirements based on your function's definition
- Know that all authorization requirements are enforced in all codepaths
- Know that authorization violations cannot be introduced accidentally
Missing an authorization check? That's a compile-time error.
Missing DACquiri? That's a dev-time error.
How it works
DACquiri codifies permissions checks into the type system using a wrapper struct called GrantChain. For example, let's imagine you have two permissions called P1 and P2. If you've checked both of these permissions on some User object, you might expect to now have a type GrantChain<P2, GrantChain<P1, User>>.
The magic of DACquiri is that it doesn't matter in which order you check permissions, just that you've checked them at some point. Regardless of the order, the outer GrantChain will implement both HasGrant<P1> as well as HasGrant<P2>. This is true for no matter how many grants you add to the chain.
Grants can be checked with the try_grant function where you'll specify which Grant you are currently checking. The actual check is performed in the has_grant function you must implement when implementing Grant on your PrincipalT.
Example
Here's a simplistic example of two permissions (PermissionOne and PermissionTwo) that we'll define as being grantable to all User objects (for the sake of this example).
use *;