Permissions¶
Overview and model¶
Permissions are rules to express what data perimeter a user is authorized to view.
Permissions are associated to a data domain and a scope.
Scopes can be DEFAULT, ALL_USERS, and USER_GROUP.
Permissions with USER_GROUP scope are associated to one user group.
All permissions contains an effect field.
Most simple permissions only have the effect SEE_ALL (user can see every rows) or SEE_NOTHING (user can't see any row).
Permissions with a CUSTOM effect have a data filter called condition.
The format of this filter comes from weaverbird's FilterStep.
See laputa/common/permission.py for details on the PermissionModel.
Application rules¶
For each data request, matching permissions are found and then applied to eventually restrict returned data.
Matching permissions are:
- the permission with the scope DEFAULT for the requested domain,
- the permission with the scope ALL_USERS for the requested domain,
- permissions with the scope USER_GROUPS for the requested domain which are associated to groups the user belong to.
Without any other matching permission, the DEFAULT permission is applied.
See
test_domain_with_default_permissionintests/api/test_data.pyfor examples.
Without any USER_GROUPS matching permission, the ALL_USERS permission is applied.
See in
tests/api/test_data.pyfor examples.
ALL_USERS and USER_GROUPS matching permissions are combined with an or rule: the user can see the union of all authorized data.
(See concat_permissions method in laputa/common/permission.py)
See
test_domain_with_all_users_permissionandtest_get_data_with_permissionsintests/api/test_data.pyfor examples.
Local Mongo queries¶
Before handing the query to Mongo connector for execution, Laputa merges it with the permission filter using MongoConnector's method apply_permissions.
This process had two steps:
- translating the data filter to a mongo filter: {'column': 'code', 'operator': 'eq', 'value': 'red'} => {'code': 'red'}
- merging it with the query using a $and operator: {'$and': [{'code': 'red', ...rest of the $match query...}]}
Combined datasets¶
Mongo queries built with the Visual Query Builder can combine different domains, using the $lookup pipeline stage.
Laputa detects all the domains used in $lookup stages and apply corresponding permission filters.
See
test_domain_with_lookup_permissionintests/api/test_data.pyfor an example.
Live data¶
ToucanConnector, base class of all connectors, does not provide a universal way to merge a filter with a query,
as it would highly depend on the underlying system and query language. In some cases, it wouldn't be possible at all.
So, for all connectors apart from MongoConnector, the data filter will be passed along with the query.
The connector will apply it after receiving the data, using pandas.query.
Query and permissions parameterization¶
A parameters field can be sent along a query by the front-end. They will be interpolated inside the query's jinja syntax elements.
Laputa adds to these parameters a user field containing:
- any attribute found in user.attributes
- the list of each group name the user belong to under the group field
See
test_domain_with_parametrized_permissionandtest_get_data_from_providerintests/api/test_data.pyfor examples.
Mongo¶
For Mongo queries, the whole query is interpolated with the parameters.
See
nosql_apply_parameters_to_queryin toucan-connectors.
As permissions' data filters are incorporated directly into the query, their parameters will be interpolated as well.
Other connectors¶
For other connectors, this interpolation could be dangerous (particularly in SQL). It's up to each connector to implement it in a safe manner.
As the permissions' data filters are applied by pandas once translated into a pandas.query format,
they get interpolated regardless of the implementation state of the used connector.