Dinemic framework strongly relays on cryptographic tools, like symmetric and asymmetric encryption as well as the digital signatures. This made possible to use its cryptographic background as second, after ORM function – the permission management system.
What can be managed?
The permission management feature of dinemic framework allows to grant permissions to:
- control who (or what entity in cluster) can modify particular objects
- which fields of objects could be accessible for read to other entites and objects in cluster
also listeners mechanism could control how particular fields of objects could be modified by unsigned updates, not authorized or authorized. By adding proper listeners application’s logic could prevent applying certain updates on local database. With this mechanism developer could filter:
- Anonymous, not signed updates
- Updates signed by keys not authorized to update modified object
- Updates signed by keys authorized to update object (i.e. to prevent allocating too much resources, however this usecase should be implemented in other way and was described in DModel)
- Anonymous/signed/authorized updates of particular fields or whole object
- Creating new objects
- Modyfying child objects
Above is done individually by each node in cluster. Due to weak consistency of dinemic clusters, it is each node’s interest to properly filter and apply database updates.
Thinking about roles
It was described in previous chapters before, however it is worth to recall how to see all objects in dinemic cluster.
Each object in dinemic database has its pair of cryptographic keys. The private key is always stored only on machine, where object was originally created. The Public key is stored on all nodes in network. Also object’s ID is generated basing on this key. This is key feature to remember, when creating logic responsible to filtering database updates.
Example: let’s say we have User object and Resource objects. User was created on host A and Resource was created on host B:
As you can see public keys of both objects are present on both hosts. Private keys are present only where objects were created. Thus, to sign update which changes object Resource we need to:
- Private key related to object Resource
- Tell whole cluster, that updates signed by some other key will be accepted in the same way as signed by Resource’s key
As important cryptographic principle, it is worth to mention, that signatures could be done only by using private keys. Anybody having public key could verify such signature. Also it is possible to create public key from private and not vice versa.
So finally in above configuration only Resource object will be able to create signed updates of itself. This is how objects are created initially in whole cluster by Dinemic framework. First step of create constructor of DModel class is to broadcast Action: CREATE notification with public key and ID of object. As second notification chained directly after CREATE is another one which adds keys to authorized objects list in object. So finally, in simplification, we got following database configuration:
Resource object authorized any changes made and signed by User object to be applied as its own changes. This is way how all privileges are handled in Dinemic ecosystem. Such list of authorized keys, which will be widely described in next chapters, is used to manage permissions to:
- accept updates on object
- encrypt data inside object to be visible only to owners of private keys
Perspective of host A and host B
It is important to remember what is visible on hosts, from perspective of this hosts. Ho host A we will have available whole object User, Resource, all public keys and secret key of User:
and on host B we will have available the same information: User and Resource objects, all public key, but only Resource’s secret key:
So once you create application that handle some updates, first logics should check if there is available secret key (object is owned) to create valid update and broadcast it to whole network. So good point of starting such logic is to get from DModel list of owned objects IDs (DModel::object_list_owned) and check if there is any ID present in authorized keys of object that we want to update.
When we are sure that instance of application has authorized key to sign notification, we should re-create object, which should be updated in proper way with caller parameter. This allows dinemic framework to select proper secret key from machine, where update is done. Remember, that such update could be done anywhere in cluster, but only in place where User’s secret key is present it will result in signed notification, which will be validated by other nodes:
User user("some_resource_id", store, sync); Resource resource("some_user_id...", store, sync, NULL, &resource); resource.size = 12;
In above example we first re-create User object. Then we can re-create Resource object with parameter caller pointing to User. Then User instance will be used to sign any notifications and encrypt/decrypt protected data of Resource object on this machine.
Of course, above re-creating could be done anywhere in cluster, just to check what data is stored in that objects. But only re-creating that objects on machine with User’s secret key will result properly signed notifications.
Last line, updating DField size will send signed by User notification to whole cluster. Due to User‘s key is authorized to sign such udpates on Resource, it should be accepted on all nodes.
Read and update authorized lists
To manage permissions you can use one of two lists predefined in DModel:
Both of them contain list of object IDs. First list, update_authorized_objects is used by Dinemic framework to verify updates made when object was modified, as described in above examples.
Second list, read_authorized_objects is used by DList and DField to encrypt and decrypt fields, which are marked as encrypted. That was described in DField and DList chapter.
Again, by adding proper IDs to this list Dinemic is able to encrypt data to be available only to objects with IDs present in read_authorized_objects. The encryption is done in two steps:
- New symmetric key is generated – this is key not correlated to object ID or above fields
- Field or list contents are encrypted with this symmetric key
- Copy of symmetric key is encrypted by each public key related to ID present in read_authorized_keys
Finally any object present in read_authorized_objects is able to find symmetric key encrypted by its public key and decrypt by its secret key. Then object is able to decrypt contents of DField or DList.
All principles related to caller are valid here too. By not setting this parameter, when re-creating object, it is possible to read data only on machine which has object’s secret key. If caller is one of read_authorized_objects, then its secret key is used to decrypt contents, if present.
Read_authorized_objects list could be used to protect particular fields from reading by unauthorized participants of cluster. Update_authorized_objects list protects whole object when proper listener, rejecting unauthorized updates is present.
Rejecting updates by listener
Last possibility to protect objects and manage permissions is to apply DAction objects to SyncInterface of Dinemic framework. DAction objects could prevent applying notifications on local database in accordance to various logics, implemented by developer in such listeners. However it is important, that such listeners should behave in the same way in each node of cluster. Otherwise state of databases across nodes in cluster will not be the same and this may lead to undefined behavior.
To reject update just throw DUpdateRejected exception with proper reason in parameter. This will be catched by notification queue in SyncInterface of Dinemic framework and update will be rejected.