2

I am looking at ways to implement an authorization (not authentication) scheme in my app.

There are currently two roles in the system: A and B, but there may be more. User's only have one role.

Basically, the I have it set up now is with two database tables. One is for role-based permissions on a model, and the other is for specific user-based permissions. I am thinking that this way, users can have a set of default permissions based on their role-based permissions, but then they can also have specific permissions granted/revoked.

So for example:

table: user_permissions
columns:
    user_id: [int]
    action: [string]
    allowed: [boolean]
    model_id: [int]
    model_type: [string]

table: role_permissions
columns:
    role: [int]
    action: [string]
    model_type: [string]        

In the user_permissions table, the allowed field specifies whether the action is allowed or not, so that permissions can be revoked if this value is 0.

In another table, I have the definitions for each action:

table: model_actions
columns:
    action: [string]
    bitvalue: [int]
    model_type: [string]

I do this so that when I check permissions on a model, for example ['create', 'delete'], I can use a bitwise and operation to compare the user's permissions to the permissions I am checking. For example, a model X could have the following model_actions:

action: 'create'
bitvalue: 4
model_type: X

action: 'delete'
bitvalue: 2
model_type: X

action: 'view'
bitvalue: 1
model_type: X

If my user/role permissions specify that the create, view, and delete actions for the model X are 1, 0, and 1, respectively, then this is represented as 110 based on the model_actions table. When I check if I can create model X, I use the fact that create is 4 to construct the bitarray 100. If the bitwise AND operation of 110 and 100 is 100, then the permission is valid.

ANYWAY, I think I have a granular permissions design pattern figured out. If not PLEASE feel free to educate me on the subject.

The actual focus of my question concerns the following:

Some of my models have actions that are time-dependent. For example, you can only delete a model Y no more than 24 hours after its created_at date.

What I am thinking is to automatically create a cron job when the model is created that will update the permissions on the date that this occurs. In the case of model Y, I would want to insert a record into the user_permissions that revokes the 'delete' action of this model.

My question is: is this advisable?

Edit

What if I include another row in the SQL tables, that specifies a date for the permission to 'flip' (flipDate)? If a flipDate is defined, and if the current date is after the flip date, the permission is reversed. This seems much easier to manage than a series of cron jobs, especially when models may be updated.

user2205763
  • 1,499
  • 2
  • 14
  • 30

1 Answers1

6

Your models seems fine, but... you are reinventing the wheel a bit and, as you realized yourself, your model is not flexible enough to cater for additional parameters e.g. time.

In the history of authorization, there is a traditional, well-accepted model, called role-based access control (RBAC). That model works extremely well when you have a clearly defined set of roles and a hierarchy between these roles.

However, when the hierarchy isn't as clear or when there are relationships (e.g. a doctor-patient relationship) or when there are dynamic attributes (such as time, location, IP...), RBAC doesn't work well. A new model emerged a few years back called attribute-based access control (ABAC). In a way, it's an evolution or generalization of RBAC. With ABAC, you can define authorization logic in terms of attributes. Attributes are a set of key-value pairs that describe the user, the action, the resource, and the context. With attributes, you can describe any number of authorization situations such as:

  • a doctor can view a patient's medical record between 9am and 5pm if and only if the patient is assigned to that doctor
  • a nurse can edit a patient's medical record if and only if the patient belongs to the same clinic as the nurse.

ABAC enables what one could call PBAC or policy-based access control since now the authorization logic moves away from proprietary code and database schemes into a set of centrally managed policies. The de-facto standard for these policies is XACML, the eXtensible Access Control Markup Language.

In a nutshell, XACML lets you do what you are looking for in a technology-neutral way, in a decoupled, externalized way. It means, you get to define authorization once and enforce it everywhere it matters.

I recommend you check out these great resources on the topic:

David Brossard
  • 13,584
  • 6
  • 55
  • 88
  • 1
    Actually,.. this answer deserves a bounty reward, as it points to already existing solutions. And, also it made me realize, that authorization can be integrated to, but decoupled from, domain. As, authorization can (optionally) operate on domain model, it can also ignore the model. And, interface (ports & adapters pattern) implementation would define permissions, and domain implementation doesn't depend on authorization, but sophisticated authorization implementation can be developed later, or there can be implemented authorization using some external system. – kravemir Oct 26 '19 at 14:29
  • Thanks, much appreciated – David Brossard Oct 31 '19 at 19:48