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.
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:
NIST's website on RBAC (the older model)
NIST's website on ABAC (the model you need)
the OASIS XACML Technical Committee website (the standard that implements ABAC)
Gartner's Externalized Authorization Management
Kuppinger Cole's Dynamic Authorization Management
The ALFA plugin for Eclipse, a tool to write attribute-based policies.
Related
Based on my coarse reading, ABAC, i.e. attribute based access control, boils down to attach attributes to subjects, resources and other related entities (such as actions to be performed on the resources), and then evaluate a set of boolean valued functions to grant or deny the access.
To be concrete, let's consider XACML.
This is fine when the resource to be accessed is known before it hits the decision engine (PDP, in the case of XACML), e.g. view the mobile number of some account, in which case the attributes of the resource to be accessed probability can be easily retrieved with a single select SQL.
However consider the function of listing one's bank account transaction history, 10 entries per page, let's assume that only the account owner can view this history, and the transaction is stored in the database in a table transaction like:
transaction_id, from_account_id, to_account_id, amount, time_of_transaction
This function, without access control, is usually written with a SQL like this:
select to_account_id, amount, time_of_transaction
from transaction
where from_account_id = $current_user_account_id
The question: How can one express this in XACML? Obviously, the following approach is not practical (due to performance reasons):
Attach each transaction in the transaction table with the from_account_id attribute
Attach the request (of listing transaction history) with the account_id attribute
The decision rule, R, is if from_account_id == account_id then grant else deny
The decision engine fetch loops the transaction table, evaluate each row according to R, if granted, then emit the row, util 10 rows are emitted.
I assume that there will be some preprocess step to fetch the transactions first, (without consulting the decision engine), and then consult the decision engine with the fetched transaction, to see if it has access?
What you are referring to is known as 'open-ended' or data-centric authorization i.e.access control on an unknown number (or a large number) of items such as a bank account's transaction history. Typically ABAC (and XACML or alfa) have a decision model that is transactional (i.e. Can Alice view record #123?)
It's worth noting the policy in XACML/ALFA doesn't change in either scenario. You'd still write something along the lines of:
A user can view a transaction history item if the owner is XXX and the date is less than YYY...
What you need to consider is how to ask the question (that goes from the PEP to the PDP). There are 2 ways to do this:
Use the Multiple Decision Profile to bundle your request e.g. Can Alice view items #1, #2, #3...
Use an open-ended request. This is known as partial evaluation or reverse querying. Axiomatics has a product (ARQ) that addresses this use case.
I actually wrote about a similar use case in this SO post.
HTH,
David
I'm designing a Java application and the model data is stored in Oracle SQL Server. I'm trying to design the best user/role model according to what is necessary.
Because of business rules all users have basic common information:
Identification ID
Name
Surname
Email
IsActiveUser
But then depending on the role, the user will have extra fields like:
Client Role:
Birth Date
Address
Lawyer Role:
Specialty
Professional Registration ID
Expert Role:
Occupation
Manager Role:
Region
I think in two possible solutions:
User table will have all the common fields and the optional fields that will be filled depending on the role.
User table will only have the common fields, and then I create a Detail_User table to save the optional fields that vary with the role.
Do you think this possible solutions are good? Is there an alternative better solution?
Answering in the Relational database paradigm, as you have tagged it.
Do you think this possible solutions are good? Is there an alternative better solution?
No. This is a classic case for Subtypes.
I have a Role table and the User table have a FK to this, because every user will have only one role.
That won't solve your problem. You need to store the values for each instance of a Role, each instance of an User.
Further, you will appreciate the correct solution only when you wish to constrain some child table (eg. Portfolio.LawyerId) to Lawyer, not User.
Data Model
The Data Model in IDEF1X/ER Level (not ERD) is:
Note
The Standard for Relational Data Modelling since 1983 is IDEF1X. For those unfamiliar with the Standard, refer to the short IDEF1X Introduction.
For full definition and usage considerations re Subtypes, refer to Subtype Definition.
Unless you are going to have zillions of rows, there is no need to split the tables in the two that you specify.
You might consider a separate table for each role -- or more specifically for each role that has bespoke columns. This would give you a little efficiency in storage space in many cases (versus NULL) in a wider record, although that depends on the database and data types being used.
A more important reason to split them is for foreign key references. If you have other tables where "lawyer" would be a foreign key, then you need a lawyers table for that. Voila! Having a separate table for different roles allows such specialized relationships, as well as general purpose relationships for all users.
My DB has following tables:
Resource: Some resources can be uploaded on site
Groups: Groups on site
Users: Users on site (not necessarily be part of any group but could be if they like)
Now, when some one uploads a resource then currently, ownership of that resource is given to it's uploader by default. So resource table has column OwnerID with foreign key association to User table.
But now, this has to be changed such that ownership of a resource could be given to either a user or entire group.
I'm trying to decide the migration scheme, to move this owner being user to an entity that could be either user or group. Intuition is that when someone uploads a material, he can choose its owner to be a user or entire group.
Currently my migration plans involves:
Add OwnerType (User, Group, Global) and UserOwner and GroupOwner within the Material table (probably worse normalized table).
OwnerType could be Global if owner is everyone --or-- Group if owner is group entity else user.
Then when I'm querying the Resource table, I can check the OwnerType to condionally select its Owner from either user table or group table.
I do not know if this is good way. I'm using entity framework, and things are already started to look ugly as User and Group hardly have any relationaship that would require me to make generalized entity.
Can some expert guide me on this? What is generally considered good migration plan in this case? Thanks for any help or suggestions.
I'm building a rather complex web application with Java / Spring and at least 2 different databases:
RDBMS for main data
MongoDB for files (via GridFS) and other data CLOBs/JSON/etc.
The next step is authorization. Simple role based authorization isn't enough, because users should be allowed/disallowed to view/modify different resources. Though ACL came to my mind.
The most common simple ACL table probably looks like:
TABLE | FIELDS
-------+--------------
class | id, className
object | id, class_id, objectId
acl | id, object_id, user_id, permissionBitMask (crud)
But unfortunately that's not enough for my needs :(.
I also need:
Roles:
each User can have several roles, and
an ACL entry can also belong to a role
More Permissions:
For example: each Project can have multiple tasks, but a User who can modify the project details isn't allowed to create new tasks for this project. So there must be a separate permission for that.
ObjectId of different types:
The RDBMS tables will use UUID surrogate keys (so at least I never have to deal with composite keys here)
But MongoDB of course uses its own ObjectId
Additionally I will have some static resources inside the code which must be access restricted as well.
Parent Objects to inherit permissions
If I combine all these aspects, I get the following table structure:
TABLE | FIELDS
---------------+--------------
class | id, className
object | id, class_id, objectId, parent_object_id
acl | id, object_id, user_id, role_id
permission | id, permissionName
acl_permission | id, acl_id, permission_id, granted
Of course I could split the acl table into 2 tables (1. object + user, 2. object + role), but I don't think that really matters.
The "objectId" will be a simple VARCHAR and my application has to convert it from/to String. Else I'd have 5 additional tables for my different ObjectId types. And this would result in 5 additional JOIN operations...
Now the basic lookup query would be something like this:
SELECT p.granted
FROM acl a
JOIN acl_permission p
WHERE p.permission_id = ?
AND (
a.object_id = ? AND a.user_id = ?
OR a.object_id = ? AND a.role_id IN (?)
)
(Permissions are cached, Roles for current user are also cached via session context. granted just indicates, if the user has the permission or not.)
Then I would also have to apply an recursive SELECT, in order to get the parent object's ACL, if there's no ACL entry for the current object.
This can't be really performant. So what are the alternatives? My ideas:
Different DB schema (any ideas!?)
Graph Database like Neo4j.
Neo4j advantages:
Finding the first parent with a permission entry is a simple task for this DB
Storing an array of permissions within the ACL entry is possible -> no JOIN
Basically I could store all information in a single Node:
.
{
class: ClassName,
object: ObjectId,
parent: RelationToParentNode,
user: UserId,
role: RoleId,
grantedPermissions: [Permission1, Permission2, ...]
}
(Every permission, that is not listed inside the array, is automatically not granted. It's not possible to store complex types in a Neo4j array, so there's no way to store something like permissions: [{Permission1: true}, {Permission2: false}])
Of course it's also possible to store Permissions and Classes as separate Nodes and just link them all together. But I don't know what's the better approach with Neo4j.
Any ideas on this? Is there any out-of-the-box solution? Maybe there's a reason to use MongoDB for ACL?
I read about XACML and OAuth(2), but both seem to need an additional ACL schema to do what I need. Or am I wrong?
First of all, the complex Permission System you're looking for has a standard spec called RBAC (Role-Based Access Control). I've implemented various RBAC models in SQL both simple and complex. Work fine, SQL implementation is not fast on commodity hardware when the number of relationships grow above million. Reads are instant, but writes are slow due to the heavy work to duplicate records in order to provide fast reads.
Originally, when I designed the Permission System I literally "drew" it on a paper based on the RBAC spec. The output was, indeed, a graph. So, after two years of production usage, I'm thinking of switching to a native graph database.
Neof4j is a popular solution, but some important customers seem to be dissatisfied with it due to its weak clustering and replications system. So have a look at OrientDB (see OrientDB vs Neo4j).
You have mentioned above that "it's not possible to store complex types in a Neo4j array". OrientDB boasts having addressed this issue with custom data types. I haven't personally tried it yet, but planning to test after migrating our production data.
I have a database and normally users are the central object.
In database I have a tables roles and users in roles so I can give users different permissions on site.
But now I have one doubt.
I saw before one database with structure like this (User is in 1:1 relation to other tables):
User{UserId, Username, Email etc.}
Admin{UserId, some specific columns}
Child{UserId, some specific columns}
Admin{Parent, some specific columns}
and other tables are connected to user not through User table but through Admin, Child and admin.
Because now I design my database I have Users and user can be Admin, CompanyManager and Professor.
I wonder should I design table like I show above or just relied on roles?
What is advantage of the first approach?
And also in my business model User doesn't have to be CompanyManager or Professor so this is actually 1 to 0 or 1 design.
What is a good way to design database with scenario like this?
The advantage of having specific tables for certain types of users is to store information that is only relevant to that class of user.
In your example,
perhaps all users would have a manager - so the manager ID would go in the users column.
managers would have permissions to view certain information, so this would be handled via a role.
only professors would have a Subject, or the "HasTenure" property. So this information would go in a professors table. Using this approach, you avoid the need to have a "Subject" column in the users table, when it is only applicable to a certain subset of users. As such you avoid a functional dependency in the users table, and a violation of 3rd Normal Form.
I prefer this approach:
In this way, you can easily group Roles into categories and assign them to users.