Solve apparent need for outside reference to entity inside aggregate (DDD) - domain-driven-design

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...

Related

DDD: how should I check state of related aggregates inside one usecase?

Let's say I have three aggregates in the same bounded context:
PhoneAggregate
ServiceCenterAggregate
ServiceWorkAggregate
ServiceWorkAggregate references both PhoneAggregate and ServiceCenterAggregate by id.
Now when new ServiceWorkAggregate is created, a POST request is sent:
{
"phone_id": uuid,
"servicecenter_id": uuid
}
I can't just create a new aggregate using those IDs, I need to perform some checks: at least confirm that those UUIDs are valid entity IDs, maybe also perform some business logic checks involving current state of selected PhoneAggregate and ServiceCenterAggregate. What is the best way to do this?
I could make ServiceWorkAggregate application service or domain service include repositories for all three aggregates.
if I go this route, should application service just pass IDs into domain service and domain service would load aggregates and do all the checks, since there could be business login involved.
or should application service fetch aggregates and pass them into domain service?
I could treat referenced aggregates as value objects and instead of phone_id and servicecenter_id fields inside ServiceWorkAggregate use value objects Repairable and ServiceLocation, which would be immutable copies of those aggregates, fetched from the same table etc. Then I would need only one repository in my servicework application service.
Is there a better way?
A lot of developpers think that the domain layer of an application must be designed as a single normalized data model, like an RDBMS schema. This is not true, and is the cause of many suffering.
The fact that you have 3 different contexts does not mean that the ServiceWork context is not able to manipulate data from the other two concepts. It only means that this context is not able to authoritatively change these concepts states. Put in other words, ServiceWorkRepository can read data about the Phone context, but it cannot create, delete or change a phone's state.
Also, you don't need the same information regarding a phone's state when you are changing a phone's context, or when you are changing a service work's context. This allows you to have two different models for the same concept, depending on the current context. Let's call them ServiceWorkContext.PhoneEntity and PhoneContext.PhoneEntity. These entities can map to the same table/columns in the database, but they can have different level of details: flattened relationships, fewer columns read, and do not allow changing the state.
This concept is called polysemic domain modeling.
In other words, you have the following classes:
MyApp.Domain.PhoneContext.PhoneAggregate
MyApp.Domain.PhoneContext.PhoneRepository
MyApp.Domain.ServiceCenterContext.ServiceCenterAggregate
MyApp.Domain.ServiceCenterContext.ServiceCenterRepository
MyApp.Domain.ServiceWorkContext.PhoneEntity
MyApp.Domain.ServiceWorkContext.ServiceCenterEntity
MyApp.Domain.ServiceWorkContext.ServiceWorkAggregate
MyApp.Domain.ServiceWorkContext.ServiceWorkRepository
MyApp.Domain.PhoneContext.PhoneAggregate represents the phone's state when you want to create or update a phone, and validates business rules regarding these use casses.
MyApp.Domain.ServiceWorkContext.PhoneEntity represents a simplified readonly copy of the phone's state, used when trying to create / update a service work. For instance it can contain a single Country property (which maps to Phone->Owner->Address->Country->Name) to be compared with the ServiceCenter's country, if you have a business rule stating that the phone's country must match the service center's. In that case, you may not need to read Phone.Number from the database for instance.

DDD and defining aggregates

We are building a system which can sell our api services to multiple companies.
We have
companies (companies which purchased our api)
accounts (each company can have multiple accounts, and each account has it's user types)
users (users within account)
Infrastructurally, it looks something like this:
"company1" : {
"accounts" : [
account1 :{"users" : [{user1,user2}], accountType},
account2 :{"users" : [{user1,user2}], accountType},
]}
One of the business rules states that users can't change accounts after registration.
Other rule states that user can change his type, but only within that account type.
From my understanding, my domain model should be called UserAccount, and it should consist of Account, User and UserType entities, where Account would be aggregate root.
class UserAccount{
int AccountId;
string AccountName;
int AccountTypeId;
List<UserTypes> AvailableUserTypesForThisAccount
User User
void SetUserType(userTypeId){
if(AvailableUserTypesForThisAccount.Contains(userTypeId) == false)
throw new NotSupportedException();
}
}
With this aggregate, we can change type of the user, but it can only be type which is available for that account (one of invariants).
When I fetch UserAccount from repository, I would fetch all necessary tables (or entity data objects) and mapped them to aggregate, and returned it as a whole.
Is my understanding and modeling going in to the right direction?
It's important to understand the design trade-off of aggregates; because aggregates partition your domain model into independent spaces, you gain the ability to modify unrelated parts of the model concurrently. But you lose the ability to enforce business rules that span multiple aggregates at the point of change.
What this means is that you need to have a clear understanding of the business value of those two things. For entities that aren't going to change very often, your business may prefer strict enforcement over concurrent changes; where the data is subject to frequent change, you will probably end up preferring more isolation.
In practice, isolation means evaluating whether or not the business can afford to mitigate the cases where "conflicting" edits leave the model in an unsatisfactory state.
With this aggregate, we can change type of the user, but it can only be type which is available for that account (one of invariants).
With an invariant like this, an important question to ask is "what is the business cost of a failure here"?
If User and Account are separate aggregates, then you face the problem that a user is being assigned to a "type" at the same time that an account is dropping support for that type. So what would it cost you to detect (after the change) that a violation of the "invariant" had occurred, and what would it cost to apply a correction?
If Account is relatively stable (as seems likely), then most of those errors can be mitigated by comparing the user type to a cached list of those allowed in the account. This cache can be evaluated when the user is being changed, or in the UI that supports the edit. That will reduce (but not eliminate) the error rate without compromising concurrent edits.
From my understanding, my domain model should be called UserAccount, and it should consist of Account, User and UserType entities, where Account would be aggregate root.
I think you've lost the plot here. The "domain model" isn't really a named thing, it's just a collection of aggregates.
If you wanted an Account aggregates that contain Users and UserTypes, then you would probably model it something like
Account : Aggregate {
accountId : Id<Account>,
name : AccountName,
users : List<User>,
usertypes : List<UserType>
}
This design implies that all changes to a User need to be accessed via the Account aggregate, and that no User belongs to more than one account, and that no other aggregate can directly reference a user (you need to negotiate directly with the Account aggregate).
Account::SetUserType(UserHint hint, UserType userTypeId){
if(! usertypes.Contains(userTypeId)) {
throw new AccountInvariantViolationException();
}
User u = findUser(users, hint);
...
}
When I fetch UserAccount from repository, I would fetch all necessary tables (or entity data objects) and mapped them to aggregate, and returned it as a whole.
Yes, that's exactly right -- it's another reason that we generally prefer small aggregates loosely coupled, rather than one large aggregate.
what about having only the relationship between Account and User live in the Account aggregate as well as the type of user (as an AccountUser entity) and have the rest of the user information live in a separate User aggregate?
That model could work for some kinds of problems -- in that case, the Account aggregate would probably looks something like
Account : Aggregate {
accountId : Id<Account>,
name : AccountName,
users : Map<Id<User>,UserType>
usertypes : List<UserType>
}
This design allows you to throw exceptions if somebody tries to remove a UserType from an Account when some User is currently of that type. But it cannot, for example, ensure that the user type described here is actually consistent with the state of the independent User aggregate -- or event be certain that the identified User exists (you'll be relying on detection and mitigation for those cases).
Is that better? worse? It's not really possible to say without a more thorough understanding of the actual problem being addressed (trying to understand ddd from toy problems is really hard).
The principle is to understand which the business invariant that must be maintained at all times (as opposed to those where later reconciliation is acceptable), and then group together all of the state which must be kept consistent to satisfy the invariant.
But what if account can have hundreds or thousands of users? What would be your vision of aggregate?
Assuming the same constraints: that we have some aggregate that is responsible for the allowed range of user types.... if the aggregate got to be too large to manage in a reasonable way, and the constraints imposed by the business cannot be relaxed, then I would probably compromise the "repository" abstraction, and allow the enforcement of the set validation rules to leak into the database itself.
The conceit of DDD, taken from its original OO best practices roots, is that the model is real, and the persistence store is just an environmental detail. But looked at with a practical eye, in a world where the processes have life cycles and there are competing consumers and... it's the persistence store that represents the truth of the business.

Domain security involving domain logic

Together with my application's domain logic I am trying to outline the security model. I am stuck with a requirement that prevents me from considering security just a cross-cutting concern over my domain logic. Here follows my situation.
A user in my system can potentially be allowed to create a certain kind of objects, say, 'filters'. I introduce a permission called 'CREATE_FILTER', and a user is either allowed to create filters or not, depending on whether the admin assigned such a permission to this user, or not. Ok.
Now consider a more complex requirement when the number of filters a user can create is limited. So, e.g. the admin should be able to set max number of filters any user is allowed to create, or even more complex, to assign max numbers individually to users, say value of 3 to User1, 5 to User2 and so on. So, the security system, in order to authorize filter creation to a user, is not sufficient to check whether a user has such a permission assigned, but has to analyze the domain model in a complex way in order to look how many filters there are already created by the user to make the decision. To make things more complex, we can imagine that the max limit will depend on the amount of money user has on their account, or something.
I want to conceptually separate (at least in my mind), whether such a complicated security logic purely pertains to security (which will of course depend on the domain model) or is this already a full-fledged part of the domain logic itself? Does it make sense to keep a 'permission' concept, when assigning/removing permissions does not help much (since it's domain state on which depends authorization decision rather than assigned permissions)? Would it be a way to go, say, to have a complicated permission concept which not simply allows an action by a mere fact of its existence but would rather involve some complex decision making logic?
Here's one way you could handle this ...
On one side you have a security model (might be a bounded context in ddd speak) that is solving the problem of assigning permissions to subjects (users), maybe indirectly through the use of roles. I would envision upper boundaries (max numbers) to be an attribute associated with the assigned permission.
There's also a query part to this model. Yet, it can only answer "simple" questions:
Has this user permission to create filters?
How many filters can this user create?
Some would even say this query part is a separate model altogether.
On the other end you have your application's model which is largely "security" free apart from these pesky requirements along the lines of "user John Doe can only create 3 filter". As an aside, it's doubtful we're still speaking of a "user" at this point, but rather of a person acting in a certain role in this particular use case. Anyway, back to how we could keep this somewhat separate. Suppose we have a somewhat layered approach and we have an application service with an authorization service in front. The responsibility of the authorization service is to answer the question "is this user allowed to perform this operation? yes or no?" and stop processing if the answer is no. Here's a very naive version of that (C#).
public class FilterAuthorizationServices :
Handles<CreateFilter>
{
public FilterAuthorizationServices(FilterRepository filterRepository) { ... }
public void Authorize(Subject subject, CreateFilter message)
{
if(!subject.HasPermissionTo("CreateFilter"))
{
throw new NotAuthorizedException("...");
}
if(filterRepository.CountFiltersCreatedBy(subject.Id) >
subject.GetTheMaximumNumberOfFiltersAllowedToCreate())
{
throw new NotAuthorizedException("...");
}
}
}
Notice how the application service is not even mentioned here. It can concentrate on invoking the actual domain logic. Yet, the authorization service is using both the query part of the above model (embodied by the Subject) and the model of the application (embodied by the FilterRepository) to fulfill the authorization request. Nothing wrong with doing it this way.
You could even go a step further and ditch the need for the application's model if that model could somehow provide the "current number of created filters" to the security model. But that might be a bridge too far for you, since that would lead down the path of evaluating dynamic expressions (which wouldn't necessarily be a bad place to be in). If you want to go there, may I suggest you create a mini DSL to define the required expressions and associated code to parse and evaluate them.
If you'd like brokered authorization you could look at something like XACML (https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xacml) though you'll have to overcome your fear of XML first ;-)

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

Bounded Contexts and Aggregate Roots

We are trying to model an RBAC-based user maintenance system using DDD principles. We have identified the following entities:
Authorization is an Aggregate Root with the following:
User (an entity object)
List<Authority> (list of value objects)
Authority contains the following value objects:
AuthorityType (base class of classes Role and Permission)
effectiveDate
Role contains a List<Permission>
Permission has code and description attributes
In a typical scenario, Authorization is definitely the Aggregate Root since everything in user maintenance revolves around that (e.g. I can grant a user one or more Authority-ies which is either a Role or Permission)
My question is : what about Role and Permission? Are they also Aggregate Roots in their own separate contexts? (i.e. I have three contexts, authorization, role, permission). While can combine all in just one context, wouldn't the Role be too heavy enough since it will be loaded as part of the Authorization "object graph"?
Firstly I can't help but feel you've misunderstood the concept of a bounded context. What you've described as BC's I would describe as entities. In my mind, bounded contexts serve to give entities defined in the ubiquitous language a different purpose for a given context.
For example, in a hospital domain, a Patient being treated in the outpatients department might have a list of Referrals, and methods such as BookAppointment(). A Patient being treated as an Inpatient however, will have a Ward property and methods such as TransferToTheatre(). Given this, there are two bounded contexts that patients exist in: Outpatients & Inpatients. In the insurance domain, the sales team put together a Policy that has a degree of risk associated to it and therefore cost. But if it reaches the claims department, that information is meaningless to them. They only need to verify whether the policy is valid for the claim. So there is two contexts here: Sales & Claims
Secondly, are you just using RBAC as an example while you experiment with implementing DDD? The reason I ask is because DDD is designed to help solve complex business problems - i.e. where calculations are required (such as the risk of a policy). In my mind RBAC is a fairly simple infrastructure service that doesn't concern itself with actual domain logic and therefore doesn't warrant a strict DDD implementation. DDD is expensive to invest in, and you shouldn't adopt it just for the sake of it; this is why bounded contexts are important - only model the context with DDD if it's justifiable.
Anyway, at the risk of this answer sounding to 'academic' I'll now try to answer your question assuming you still want to model this as DDD:
To me, this would all fit under one context (called 'Security' or something)
As a general rule of thumb, make everything an aggregate that requires an independent transaction, so:
On the assumption that the system allows for Authorities to be added to the Authorization object, make Authorization an aggregate. (Although there might be an argument for ditching Authorization and simply making User the aggregate root with a list of Authorities)
Authorities serve no meaning outside of the Authorization aggregate and are only created when adding one, so these remain as entities.
On the assumption that system allows for Permissions to be added to a Role, Role becomes an aggregate root.
On the assumption that Permissions cannot be created/delete - i.e. they are defined by the system itself, so these are simple value objects.
Whilst on the subject of aggregate design, I cannot recommend these articles enough.

Resources