Access Restriction Technical Implementation
Date | Version | Name | Applied changes |
---|---|---|---|
11/04/2024 | 1.0 | Vladislav Stratonikov | First Publish |
01/07/2024 | 1.1 | Vladislav Stratonikov | Admin Group Info |
29/07/2024 | 1.2 | Beatris Bunova | Admin group to be readonly |
In order to implement the user access restriction we are going to apply restrictions on Model level. This will allow us more flexibility and we can implement this feature for multiple sections.
From here on in this scope for “rule” I will be referring to the string that we are to store and we will use to identify the Model that the access restriction should be applied to.
In the scope as “checkbox” we are reffering to the “checkbox/triple click button” from the parent scope
A single rule will look similar to this
[framework.model.hub.developer_data.developer_data_ebay.field.id](http://framework.model.hub.developerdata.developerdataebay.field.id/)
Every dot represents a different level. Levels decrease with every dot. This means that framework.model
is higher level than framework.model.hub
.
The lower the level the higher the power of the rule is. This means that if a rule says that user has no access to framework.model.hub.developer_data
, but he has access to framework.model.hub.developer_data.developer_data_ebay
then the second will be visible despite it’s higher level has been restricted and anything else from framework.model.hub.developer_data
will be restricted.
Rules are equal to the Model class in the code. And the levels are the namespaces(folders) that these models belong to. How we apply rules can be found in “Rules application” in this document.
In the rules we will have the key word field
which will be used as a separator level. This will indicate that the lower level than field
, specifies a field name for which this specific rule is to be applied.
Example:
[framework.model.hub.developer_data.developer_data_ebay.field.id](http://framework.model.hub.developerdata.developerdataebay.field.id/)
- will mean that the rule is applied only to the id
field
Storage
We will store the rules in cache files that are to be generated when a user is added to an access
group or specific rules are applied to that user. We will store them in the
{machineCacheDirectory}/{clientId}/userAccess/{userId}.json
{machineCacheDirectory}
- is the current directory we use to store cache, since this can be changed and can vary it is a framework code setting
{clientId}
- this is the hub_alpha > client > id
value of the current active client for the machines.
{userId}
- is the hub_alpha > user > id
value for the user that the rule is applied to
For storing in the cache we are to use the Cache class in the framework and the time is 50 years, if that expires without a change Simeon Spasov will handle it with his team.
In this file we are to store all rules as key and as value we will have the following integers:
“implemented” means this option will be used, “reserved” means this value will handle the described functionality but not implemented in the current version ”0" - meaning no access - implemented ”1” - means delete access - reserved ”2” - means write access - reserved ”4” - means read access - implemented ”5” - means read + delete - reserved ”6” - means read + write - reserved ”7” - means read + write + delete - implemented
These values are following similar principle to a Linux environment setup.
Group
database tables changes
For groups of access we are to store them in the database in {clientHub} > group_rights
{clientHub}
- is the name of the hub database for the specific client, since they are not always going to be hub
We will need to change the fields a bit. We will prepare form_id
and field_id
for removal and we will add the field rule
and the rights
field will have the values for access from above defined rule options. group_id
can be removed in the future as well, after we stop using the old Hub and we can use master_record_id
for the group
table.
Form_id
, field_id
and group_id
are not to be removed for now! We will have a period in which we can use both the old and new UI and we do not need to remove them for now, but we can have a query prepared for this in a separate directory in the project (for example “sqls_post_backward_compatibility”). In the period that we use them both we are to keep the values in these fields as null
for any records for the new UI Access so that they do not interfere with the other version and likewise - keep rule
, rights
and master_record_id
with values null
for any of the already existing old records.
In our new Access management we are to ignore the whole row if it has any of the three “old” fields different from null
.
For the group
table itself we are not going to use the more_actions
field.
For group_user
we are to match the user_id
field to hub_alpha > user > id
. No need for foreign key for now. We will need to add Controllers for group_rights
, because we need to overwrite the actions for edit and add to point to the new Access Controller
, that will be handling the rules setup.
Alias rules
Alias rule
is a type of rule that we can use to group certain functionalities into one rule or define specific rules that are not connected to a Model. These will be stored in a json file due to the possibility of their complexity. Use the example as reference as how an alias rule is to be stored in the file. It will be one file alias_rules.json
with all the rules in an object. In the case of alias rule
being used as a grouping of multiple rules. The logic will be applied to the models as normal, because when saving the rules for the user/group we will have those rules stored as individuals also. This can be found with more information in the storing of rules. In the case an alias rule
is used to add custom restrictions to an action. We are to apply this in the before
method of the abstract Controller
class. Alias rules will be defined per scope of every feature depending on the use case, and this may change their application, so we are to prepare a method that we can implement when needed.
{
"system.admin.threecolts":[
"framework.model.hubalpha.client",
"framework.model.hubalpha.client_user",
"framework.model.hubalpha.user",
"framework.model.hubalpha.threecolts_organization",
"framework.model.hubalpha.threecolts_app",
]
}
Interface and Controllers
For the interface we will have a separate controller for the access functionality.
We will need an action that displays all rules for adding a new access or editing an existing one. We are to display them as shown in the parent scope split per level, up until field
. For NOT alias rules we will need to have a list of namespace for a rule that needs to be ignored. This is so that we do not display the levels that are not relevant to the end user. We are not fixing it to a specific value, because we may have many other namespaces and models in the future, that will follow other structure. For the models that represent the rules we will display the hub_alpha > table > label
for that model.
For example: For rules that start with framework.model.hub.developer_data
we will ignore the first three levels in the split to display and will start with developer_data
. And we will display Developer Data
In the UI we are to follow the screens from the scope, and when an alias rule
is checked (for edit/view/no access) , that contains multiple other rules, we are to mark the other rules as checked with the same value.
When we load a view with all rules we need to check every checkbox with its value (0,4,7) for every rule that is applied. The checkbox will need to be custom with 3 options. Empty that equals to 0, checked for 4 and with an X for 7. Other options may be handled for future revisions of the functionality.
@Danail Deltchev TBD it can be changed. We are to show a checkbox for each possible action with the rule. So a checkbox for read
, write
, delete
.
For fields we will pull all fields for the specific rule once the button to open the Fields modal is clicked. We pull the fields from hub_alpha > table_field
because we will need to display their labels. And for alias rules we will be showing all fields from all models added to them, but we will add the hub_alpha > table > label
with a “>” in front of the field label. The values for the checkboxes will follow the rules that are already applied to the specific parent rule.
We will have two Actions in the code to implement the display, but they will need to use the same view and share the same display method, because it works for both cases (add and edit).
In the case of edit we will have two options, which will be identified by a URL parameter for type. Options are group
or user
. For group
we will load the applied rules from the database and we will need to have the id
of the group
from the URL. For user
, identified by the id
from the URL, we will load the rules from the json file and the group he belongs to. user
needs to restricted to one group
max. In the interface we will display the name of the group in the top right part of the screen with teal background and rounded edges. All rules applied from the group are to have background with this color that is considered a highlight. Once a rule is changed it becomes a user
rule and we are to remove the highlight.
Saving of a rule for user
When saving a user file with the rules. We need to store them in two sections. One is rules
- these are coming from the group
this user is added to and the other is called user_specific
- these are all specific rules set to that user that differentiate from his group rules. user_specific
rules have higher priority than group
rules
If there is not rule for a user it means he has no access.
When saving a rule for a user
an overlap may occur so we will always store the lowest possible value (0,4,7), this means that no is always stronger than yes. If we overwrite a rule for a user
that comes from the group
the user_specific
rule has higher priority. This priority may not come into effect until we start supporting multiple groups. Every other case this may occur is covered by the other priorities for rules
Example:
If user belong to groupA.
In groupA we give him access to orders for everything.
In his rules he has only read rules from orders.
The user will have access only to read from orders
For example of how saved rules need to look like check the attached json file.
Saving of rule for group
When saving a group
we will store the values in the database and we will trigger a cron to regenerate the user rules from this specific group. So we will need to supply the id
of the group to the cron.
The cron will select all rules for the group and apply them to every user following the logic from Saving of a rule for user
. But it needs to apply the user rules at last that overwrites all group rules, even if the rule has a lower value we are to keep the user rule as priority.
Rules application
All rules are applied per Model. How it will affect some parts will be up to implementation of the rule. We will add a separate scope for the Menu and CRUD changes with their specific implementations.
To implement the rule restriction, in the abstract common Model we need to validate by the rules by checking their levels(matching for the namespace). Since we use camel case for naming of classes and namespaces every _
is a separate word that needs to be capitalized, this includes the first letter of every level.
If the logged in user has access to them and if we find any, we need to apply them when working with the data in the model.
Rules will be applied when a Model is called. If the rules allow access, we do nothing special we continue as now. All cases below are in the case for forbidden access from the rule.
For read access rules. We have two cases:
- All fields specified - We just return empty as if no result was found
- Some fields are specified - We execute the select and after that we filter the result to return only the values for the fields, that are not specified
For write access rules. We have two cases
- All fields specified - We just return empty as if no result was found and nothing happened
- Some fields are specified - We filter only the values that the user can change, and any system once that are generated (for example
master_form_id
andmaster_record_id
)
For delete access rules. We do not support this functionality at the moment so we do nothing.
<v1.1>
Admin Group Info
We will need to create a group called Admin. This group will have access to everything. It must be created with the deployment of the interface and/or during the creating of a new hemi instance. All crons must be added to this group. We will need to have a user called “System Admin User” that is created during the same time as the group with its access already saved. This user will be used to run crons that do no have their own user, just like the cron that creates the rules for access.
<v1.2>Admin group should not be available for edit through the UI.</v1.2>
</v1.1>