Designing Role/User based application security - security

I am sure this has been done by many of you and was looking for some guidance into designing a robust, scalable, application that can handle data (row level) security for multiple users.
We are looking at a system whereby users, some acting as individuals, and some as part of larger groups will need access to both their own data as well as to data shared with them by other individuals and organizations. In some cases the data is shared just to view and in other cases full edit permissions will be available.
And even within the same organization there will need to be restrictions on what users can see in terms of data created by other users in the organization.
So a very rough example may be...
User A with Role X, (individual user)
User B with Role Y (individual user)
User C with Role Z (individual user)
Users D and E with Roles X, in Organization AA
Users F and G with Roles Y in Organization AA
Each individual User might create for eg a contract on our system. That contract shoudl not be viewable by anyone else until they choose to share that contract with other individual users eg A will share his contract with User B or F.
But User A may also want to share his contract with all users of Role Y in Organization AA.
Likewise sharing the contract may even mean permission to edit the contract.
We initially had wanted to have a separate schema for each individual user to ensure security at a data level but this makes sharing more complicated and also may result in 1000's of schemas (which just doent seem like a good idea).
So it seems like our only resort is to leave all the data in one schema in one db and simply design a user and role driven application level security model which can accommodate all the required CRUD permissions on each contract. It just sounds like this is going to get very complicated and "not so pretty". For every contract we would have to define a list of users and roles by organization which with the individual permissions for each one of these users/roles.
Has anyone done anything like this? Any suggestions with regards to a good and secure application design?
Thanks

Here are some rough thoughts for this requirement
Since you are talking about data security control rather than system function/feature access control, so I will focus on data access control here.
Structure of Access Control Classes
You might want to treat all level of security atom as the same thing, e. g, it's generally defined in a way that individual / permission / role / group are inherited from the same basic principle class, and then conceptually, all access control definition will be on this basic principle, hence you don't need to know whether the control is over a role, a group or a user, this will give you more flexibility and simples the question.
You might also want to define the principles as kind of combination / hierarchy structure, for example
User A is assigned RoleA, RoleB, RoleC and PERMISSION2
Role A is a combination of RoleC and RoleD
RoleC is a combination of permission PERMISSION1, PERMISSION2 etc.
BTW: Since the design here is very flexible so you will need a system level conflict check mechanism to check
The conflict between all the principles upon any assignment to make sure there's no system level conflict(for example, roleA defines that the user can not update document of Type A, while PERMISSION2 defines it can), another possible method is to define a priority for different type of principle, for example, defined level USER > ROLE > PERMISSION.
And also a function level(SOX law etc) conflict check to make sure there's no function level conflict, for example, someone capable to do payment can not have access to operate on cash etc)
Access for Documents
Then a schema such as document / principle / restrict type / restrict operation / restrict start and thru date could be defined to store data access control for each document,
Document could be a contract, a purchase order, purchase request etc, it's actual type doesn't matter at all here.
Principle could be a user / permission / role / group etc, also you don't want to focus on the actual principle type here, by this design, only one row of data is needed for those normal documents(since we could define it on role level), and also if the user choose to share this document with a particular organization or individual, it will also be able to handle.
Restrict type might be "ALLOW" / "NOT_ALLOW" etc,
Restrict operation could be "VIEW" / "UPDATE" / "ADMIN" etc,
Restrict start and thru date will be the date range this access control take effectives, by combine this thru date, operation and restrict type we defined, you can combine exceptional access control with normal access control, hence to implement requirements like share / delegation will be easier, and it also didn't bring too much complicate for normal access control.
Organizations
If your organization has a hierarchy structure, you can also define how the access control to be inherited for parent and to child organizations, a sample schema might be,
Organization Id / Acccess inherent Type / Start and thru date.
Organization id: primary key of this organization
Access inherent type: Could be something like: ALLOW_ALL_CHILD / ALLOW_ALL_PARENT / ALLOW_ALL_SAME_LEVEL /DENY_ALL etc.
Start and thru date could be the date this role takes effective and ends.
Something you might be able to implement could be:
For organization A, all it's subsidiaries is not allowed to view / update any documents under it.
For organization B, all it's subsidiaries is allowed to have view / update permissions to all documents under it, but not to the documents on the same hierarchy level.
Then you can combine this organization level access control and the document level access control, when evaluating the rules, the document level access control always have a higher priority than organization level ones.

Related

DDD - bounded contexts sharing/communication

I am trying to utilize some DDD approaches in the app that allows guest purchase. While it looks easy, I got a bit confused and asking for your DDD advice.
The app has several bounded contexts and we are looking at 3 of them:
Customers (customers manage their user settings here, authentication, also admin can potentially create users)
Sales (orders)
Billing (charging customers for one-off payments and subscriptions)
The user story:
As a guest I want to order the product to do something.
This is one form and on checkout he/she will be asked for email and password. We need to create account on this step, but based on business logic this fits to Sales context - guest makes an order. We actually need to do simple steps:
Create user with ACTIVE status
Store billing details
Create order
Charge user later (event handled by Billing)
The confusion here is that it requires creating a user first. It looks more naturally to create it in customers, but probably it’s wrong? User can not sign up in any other way - only by placing an order, but admin can create a user manually. Based on different system events(from different contexts), the Customer context may change the user status based on special logic that is placed into Customer domain. Is there any safe way for sharing this User status logic between different contexts (while creating User in Sales we need that status enum class)? Does this logic for placing order look ok? Could you please recommend another approach if you think that this one is wrong?
Status is DDD at its worst. Including a status field is 1) lazy, and yet 2) very convenient. Yes, one of those design trade offs.
When you assign a status or read a status you are ignoring or sublimating significant business logic and structure for your domain. When “status” changes some very significant changes could occur in your domain... way beyond changing a status property.
Throw status out and instead consider some concepts: a CasualShopper or Guest (no purchases, browsing for products), a PotentialNewShopper (someone adding things in their basket who you’ve never seen before), and your usual Customer (which should probably be subdivided based on their current activity).
With this modeled, you can attach behaviors directly to each of these objects and “status” itself is sublimated into a richer DDD model. A common DDD mistake is not creating a transactionally-significant object (e.g. a Potential Shopper role) for some static/non-temporal object (e.g. a person).
From here you may decide you need a few bounded contexts; perhaps PotentialCustomers and EstablishedCustomers. In each the set of domain transitions are different and can be encapsulated rather than externalized.
So...
With that out of the way it looks like you have a Customer BC and a PossibleCustomer BC. You can safely do what you need to do in the latter now that it is self-contained.
Oh, but that may affect billing! and ordering!
True. That may mean new BCs or new objects in those BCs such as ProvisionalPayment and UnauthenticatedOrder. I’m spitballing a bit now...
My point is you have events that can transition between states rather than encoding those states, and as such you can attach the behaviors you need and persist them as needed in some physical store, that is likely partitioned in a way suitable to your DDD.
Doing all this work means not sharing unsafe status but sharing safe projections of relevant objects only.
Jumping into implementation briefly and anecdotally, developers are loath to store “temporary” state. “Temporary” state is OK to store and necessary when you’re modeling a domain without that cruddy status field.
You probably should ask yourself first whether you got the Bounded Contexts right.
In my opinion you have the following BCs
Identity and Users
Sales and Billing
consider this: the same person is a User in the first context but a Customer in the latter. so you have two views on the same real world entity which suggests that you have two bounded contexts where this entity means different things.
your bcs sound more like modules in the Sales and Billing context.
If you agree, then the control flow for your problem may be simplified where an entity in one context is created and the creation is propagated via event into the other. so the initial request could be handled by the Sales bc and the guest user handling would be propagated to Identity.

Modeling a hierarchical security with a graph

I'm trying to create an access control list for my documents. Each document needs to store which groups have CRUD rights, well not create rights on a created document. The rights may be hierarchical in that a document might not have explicit rights, but rather inherit them from the account that owns the document.
For example a user can have lots of recipes. By default the user only allows his group to read the recipes. Think Linux style groups where each user gets their own group. This default is part of the user's profile. Now for 10 recipes the user allows the group "public" to read the recipes. These are explicit designations within the recipe document itself.
Is a graph a good fit here? Should I have a vertex for user and a vertex for recipe with an edge between them called, I don't know, OWNS? In the query I could say, in pseudocode, WHERE recipe.CRUD.readers contains "public" OR recipe's OWNS inbound profile.recipes.CRUD.readers contains "public". Is this doable? Would Arango perform well on this?
I know I could duplicate the default CRUD from the profile down into the recipes. This seems like a) a massive waste of memory, and b) error prone if the system gets out of sync (do transactions work across collections in a cluster?), and c) operationally intensive since ever document has to get scanned and possibly updated.

Solve apparent need for outside reference to entity inside aggregate (DDD)

I'm trying to follow DDD principles to create a model for determining whether or not an Identity has access to an Action belonging to a Resource.
A Resource (e.g. a webservice) is something that holds a number of Actions (e.g. methods), which can be accessed or not. An Identity is something that wants to access one or more Actions on a Resource. For example, someone uses an api-key in a call to a webservice method, and it must be determined whether or not access is allowed.
As I currently see it, Identity and Resource are aggregate roots, and Action is an entity belonging to Resource. It doesn't seem to make sense for an Action to live on its own; it will always belong to one Resource. An Identity needs to know to which Resource Actions it has access. This seems to suggest the following model.
However, as I understand it, this violates the principle that something outside an aggregate cannot reference an entity within the aggregate. It must go through the root. Then I'm thinking, what if Action was the aggregate root and Resource an entity? But that doesn't seem very logical to me. I've also been thinking of merging Resource and Action into one entity, which would then be an aggregate root, but that also seems wrong to me.
So it leaves me kind of stuck on how to model this correctly using DDD principles. Anyone have a good idea on how to model this?
Update: The model I'm trying to create is the identity model for defining which resource actions an Identity is allowed to access. It is not a model for the actual implementation of resources and actions.
Update 2 - invariants:
Id of all objects is given at birth, is unique, and doesn't change. ApiKey of Identity must be unique across all Identities.
Name of Action must be unique within aggregate, but two different Resources can have Actions with same names, e.g. Resource "R1" can have an Action "A1" and Resource "R2" can also have an Action "A1", but the two "A1"s are not the same.
Query or Write Operation?
The domain model in terms of aggregates and entities has it's purpose in DDD in order to simplify expression and enforcement of the invariants - as write operations are applied to the model.
As mentioned in #VoiceOfUnreason's answer, the question 'Can this user do action A on resource R' is a question that doesn't necessarily need to flow through the domain model - it can be answered with a query against either a pre-projected read-only model, or standard SQL querying against the tables that make up the write model persistence (depend on your needs).
Splitting Contexts to Simplify Invariants
However, your question, whilst mostly about how to identify if an identity is allowed to carry out an action, is implicitly seeking a simpler model for the updating of resources, actions and permissions. So to explore that idea... there are implicitly two types of write operations:
Defining available resources and actions
Defining which resource action combinations a particular identity is permitted to carry out
It's possible that the model for these two types of operations might by simplified if they were split into different bounded contexts.
In the first, you'd model as you have done, an Aggregate with Resource as the aggregate root and Action as a contained entity. This permits enforcing the invariant that the action name must be unique within a resource.
As changes are made in this context, you publish events e.g. ActionAddedToResource, ActionRemovedFromResource.
In the second context, you'd have three aggregates:
Identity
ResourceAction
Properties: Id, ResourceId, ResourceName, ActionId, ActionName
Permission
ResourceAction instances would be updated based events published from the first context - created on ActionAddedToResource, removed on ActionRemovedFromResource. If there is a resource with no actions, there is no ResourceAction at all.
Permission would contain two identity references - IdentityId and ResourceActionId
This way when carrying out the operation "Permit this user to do this action on this resource" the operation is just to create a new Permission instance - reducing the set of operations that affect the Identity aggregate's consistency boundary - assuming there are no invariants that require the concept of a 'permission' to be enforced within an Identity aggregate?
This also simplifies the query side of things, as you just need to search for a Permission entry with matching identityId, resourceName and actionName after joining Permissions to ResourceActions.
Responsibility Layers
The DDD Book in the section on Strategic Design refers to organising your contexts according to responsibility layers. To use the terms from the book, the above suggestion is based on the idea of a 'capability' responsibility layer (defining resources and actions) and an 'operational' responsibility layer (defining identity permissions and checking identity permissions).
For example, someone uses an api-key in a call to a webservice method, and it must be determined whether or not access is allowed.
That's a query. Fundamentally, there's nothing wrong with answering a query by joining two read-only copies of entities that belong to different aggregates.
You do need to be aware that, because the aggregates can change independently of each other, and because they can change independently of your query, the answer you get when you do the join may be stale, and not entirely consistent.
For example, you may be joining a copy of an Identity written 100ms ago to a copy of an Action written 200ms ago. Either of the aggregates could be changing while you are running the query.
Based on the invariants you mention, Identity can contain a Resources dictionary/map where resourceId is the key and the value is a set of unique action names/ids. This gives you uniqueness of action names for each resource per identity:
Map<Resource, Set<Action>>
Alternatively, you could have a set/list of Resources and they have a collection of Actions on them. Uniqueness can be enforced by the collection types available in the language you're coding in:
Set<Resource> Resources
class Resource {
Set<Action> Actions
}
Even simpler, just create a Resource-Action key by combining the two ids and store it in a set or something to give you uniqueness:
Resource1-Action1
Resource1-Action2
Resource2-Action1
...etc
You can then have a method on Identity to add a new Resource-Action combination.
I don't see anything in your description to warrant Actions being Entities as they appear to have no identity of their own.
This is really simple though, so I am presuming you've simplified the domain considerably.
I will also expand on the bit identified by #VoiceOfUnreason:
For example, someone uses an api-key in a call to a webservice method,
and it must be determined whether or not access is allowed.
How would the particular bit of exposed functionality know what security is applied to it? The answer is provided by #Chris Simon: Permission.
I have a common implementation that I use that has not been distilled into an Identity & Access BC of its own but follows closely with what you are attempting --- I hope :)
A Session has a list of Permission strings. Typically I use a uri to represent a permission since it is quite readable. Something like my-system:\\users\list. Anyway, how the user is assigned these permissions could be anything. There may very well be a Role containing permissions and a user is assigned to one or more roles; or the user may even have a custom list of permissions.
When a SessionToken is requested (via authentication) the server retrieves the permissions for the relevant user and creates a session with the relevant permissions assigned to it. This results in a read-side token/permission.
Each exposed bit of functionality (such as a rest endpoint) is assigned a permission. In c# web-api it is simply an attribute on the method:
[RequiredPermission("my-system:\\order\create")]
My session token is passed in the header and a quick check determines whether the session has expired and whether the session (assigned to the user) has access to the resource.
Using your design the Action may very well carry the required Permission. The User would still require a list of either roles or UserAction entries that contain, perhaps, the ResourceId and ActionId. When the use logs in the read-optimized session structures are created using that structure.
If there is an arbitrary Action list that can be assigned to any Resource then both Resource and Action are probably aggregates. Then you would need a ResourceAction as mentioned by #Chris Simon. The ResourceAction would then contain the Permission.
That's my take on it...

Security in collaborative software (collaboration groups)

Lets say i have objects A, B, C, D, E, F, collaborator groups C1, C2, users C1U1 (admin), C1U2 (user), C2U1 (admin), C2U2 (user).
A, C, E belongs to group C1.
B, D, F belongs to group C2.
Thus only members of correpsonding group can view their respective objects. Also any object created ends up in group to which its creator (user) belongs.
Admin can create and edit every entity, user can only create entities and only edit his entities.
And ofcourse each user (admin or regular user) as said before can view only entities that belong to his group.
In my particular task there are number of type of entities (static) and number of types of users (static). There will be multiple collaboration groups (dynamic) where users will create some entities. Some of the users will have ability only to view entities (to which they are entitiled to view due to being member of correspodning collaboration group), create and edit. Some of them will have ability to edit entities of other users (but only ceratin types of entities). Essentialy its a little bit like JIRA.
That said, my question is quite simple: what pattern helps organising this stuff? I believe this is a common problem, thus it must have common name.
I know there is a blunt way to create this. Im using symfony 2 and it have both RBAC and ACL, but not RBACL afaik. RBAC will help me with user types (i use UserGroups and i create roles like ROLE_EDIT_ENTITYTYPE1), checks for ownership are performed with ACL.
But how do i implement those collaboration groups?
Im sorry if my explanation sounds vague or just stupid or anything else, i would like to hear anything about subject. I got a feeling that i'm missing something here.
PS: Not sure about "security" tag, if its related to this question.
For your case the just Role Hierachy is not suffiecient enough. What you need is complete ACL:
http://symfony.com/doc/current/cookbook/security/acl.html
You can create the ACL right in a Listener when Entities are saved and then grant the access for all the group members.
You can also work with different ACL Masks, in order to control which user can EDIT entities and which users can only view them:
http://symfony.com/doc/current/cookbook/security/acl_advanced.html
Sorry for mainly linking to the default documentation, but I think this basically covers everything you need.

Modelling Access Control in MongoDB

Does anyone have an example of modelling access control in MongoDB? The situation I'm thinking of is:
There are a set of resources, each being their own document (e.g. cars, people, trees etc.).
A user can gain access to a resource through an explicit grant, or implicitly by being the owner of a resource, existing in another collection (e.g. a role) or some other implicit ways.
In one collection.find() method, that could have skip and limit options applied (for pagination), is there a way to check all these explicit and implicit paths and produce a result of resources a user has access to?
In MySQL we have modelled this using a grants table with resource id, granting user id, authorized user id and operation (read, write etc.). We then, in one query, select all resources where at least one subquery is true, and the subqueries then check all the different paths to access e.g. one checks for a grant, one checks for ownership etc.
I just can't wrap my head around doing this in MongoDB, I'm not sure if it's even possible...
Thanks
You can't query more than one document at a time. Ideally, shouldn't access control be a part of the business logic. Your backend php/c#/language ought to ensure that the current request is authorized. If so, then simply query the requested document.
If you feel, you need to implement the exact same structure in mongodb, which I suggest you don't, then you will need to embed all those fields (the ones from the other mysql tables that help you identify whether the request is authorized) in each and every document of every collection. You will be duplicating data (denormalizing it). Which brings the headache of ensuring that all the copies are updated and have the same value.
Edit 1:
Lets talk about Car document. To track its owner, you will have owner property (this will contain the _id of the owner document). To track all users who can 'use' (explicit grant) the car, you will have an array allowerdDrivers (this will contain the _id of each user document). Lets assume the current user making the request belong to the 'admin' role. The user document will have an array applicableRoles that store the _id of each role document applicable.
To retrieve all cars that the user has access to, you only need to make two queries. One to fetch his roles. If he is an admin, return ALL cars. If he is not, then make another query where owner equals his id or allowedDrivers contains his id.
I understand your actual use case may be more complicated, but chances are there is a document-oriented way of solving that. You have to realize that the way data is modelled in documents is vastly different from how you would model it in a RDbMS.
Doing it in business logic would be painfully slow and inefficient.
How so? This is business logic, if user a owns post b then let them do the action (MVC style), otherwise don't.
That sounds like business logic to me and most frameworks consider this business logic to be placed within the controller action (of the MVC paradigm); i.e. in PHP Yii:
Yii::app()->roles->hasAccess('some_view_action_for_a_post', $post)
I think that by doing it in the database end you have confused your storage layer with your business layer.
Also with how complex some role based permission actions can get the queries you commit must be pretty big with many sub selects. Considering how MySQL creates and handles result sets (sub selects ARE NOT JOINS) I have a feeling these queries do not scale particularly well.
Also you have to consider when you want to change the roles, or a function that defines a role, that can access a certain object you will have to change your SQL queries directly instead of just adding the role to a roles table and assigning the object properties for that role and assigning users that role (AKA code changes).
So I would seriously look into how other frameworks in other languages (and your own) do their RBAC because I think you have blurred the line and made your life quite hard with what you have done, in fact here might be a good place to start: Group/rule-based authorization approach in node.js and express.js

Resources