Hey everyone. I've been experimenting with some design patterns inside a monorepo for access control (maybe there is a better term to be used in this scenario). When implementing something like RBAC + creating policies for when resources can be acted on (for example a message cannot be in "processing" state when a delete operation is attempted), what is the best way to do this? In the instance of a monorepo, is there a pattern for sharing some of the policies (like the one explained above) so that I don't need to perform API calls from my frontend when displaying something like a delete option in a menu? New to this aspect of backend design as I'm transitioning from NextJs fullstack development so any ideas are appreciated!
#Permissions and policy design
16 messages · Page 1 of 1 (latest)
@strong arch
Can you clarify this some more please?
so that I don't need to perform API calls from my frontend when displaying something like a delete option in a menu?
I think I understand what you are getting at, but just want to be clear. My current understanding is, you wish to share permissions across front and backends, but I'm uncertain.
Opa + Opal maybe but that might be overkill
Just trying to figure out a pattern for handling preconditions essentially - there’s a lot of solutions for RBAC or other types of permissioning, but is there a good way to check preconditions such as an object being in a specific state to be acted on (like my status example above)?
Additionally how do people typically handle cross-cutting concerns such as a user must have an associated sender id to send a message - must check one resource/entity to determine permissions/access for another. Hopefully this makes sense
https://github.com/JanMalch/ts-code-contracts this would be something general for pre and post condition but I guess this is not what you mean
maybe CASL could work too
https://medium.com/@piyushraw12/building-a-federated-authorization-system-with-opal-opa-and-spring-security-ba4da012da28 is this maybe similar to what you try to archive?
That medium article is actually a great resource, ive also never heard of CASL so i will be looking a bit deeper into this. Now its just a matter of understanding a pattern to handle cross-cutting permission concerns such as "organization must be from a certain country to access a certain resource" - this is similar to RBAC or another kind of access control pattern but I'm trying to figure out how to create something flexible to i can essentially add any kind of condition checks and have the system handle it in a standardized way. Its a bit difficult to explain the complexities of what im trying to do but these links are a great start, ill report here once i solidify a solution - thanks for the help!
interested , good luck mate
this is similar to RBAC
You'll find out quickly that what you are doing is barely doable in RBAC. If anything, you should keep RBAC to only higher level areas of your domain(s), like only letting admins in the admin area. All the authz after that should be ABAC, if you intend on having a decent and flexible permissions system.
pattern for handling preconditions essentially
So, CASL allows for storage of rules (assuming this what you mean by "preconditions"). These rules can be permission sets and should be generated at the time of logging in. These rules can then be shared to both the backend and frontend (via your API) to derive permissions via the Ability object CASL offers. So once the rules are generated into an abilities object, imagine you have that object in your frontend and have a
if (userAbility.can('delete', componentSubject)) {
// render delete button
}
That is a hugely simplified explanation, but is that what you were looking for?
initially you will have something like an AbilityBuilder that defines all the abilities of a user for example so you check against that
# OPA
package country_access
# Default deny - explicit denial if no rules match
default allow = false
# Allow access if organization's country is in allowed list
allow {
# Get organization country from input context
org_country := input.context.organization.country
# Check if country exists in allowed countries list
data.allowed_countries[_] == org_country
}
# Optional: Add detailed reason for debugging
reason = sprintf("Organization country: %s, Allowed countries: %v", [
input.context.organization.country,
data.allowed_countries
]) {
not allow
}
// OPAL
{
"allowed_countries": ["USA", "Canada", "Germany"]
}
// input
{
"context": {
"organization": {
"country": "Canada"
}
}
}
could be something like this
you could also look into permit.io for a commercial alternative
this could be a full example for a test run