Access Control Specification #1
marco-brandizi
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This is a draft to define how access control should work across the whole KnetMiner infrastructure, including KnetSpace, KnetMiner, client and server code for KnetSpace and KnetMiner, API publishers and API clients for KnetSpace and KnetMiner.
Due to this cross-cutting scope, we're going to describe the new API at an abstract and conceptual level, independently of any programming language or access layer (eg, code vs HTTP API).
Summary
Table of contents generated with markdown-toc
References
==> this is based on this draft document, describing use cases and KnetMiner components being developed.
The Javascript code for the current KnetMiner about permission management.
Data model
To manage the various use cases mentioned in the Google doc above, we envisage the following entities.
Resource Role
A resource role is the role that the resource has with respect to the permissions that users have about that resource.
For the time being, we plan to have only the resource roles: 'public resource', 'paid resource', 'any resource'. We might have more in future, eg, "no-profit access resource".
'any resource' is a virtual role, which captures permissions that apply to all the resources (eg, admin-related permissions). See below for examples.
"Dataset" is a synonym for resource.
"Resource Type", or "Dataset Type" are synonyms for "Resource Role" (and of course, "Dataset Role" too).
User Role
In general, a user role is the role that a user has with respect to a resource.
The user roles we currently plan to have are: guest, signed-in (or registered), subscribed (to a paid resource), admin.
In general, a role for a user must depend on a resource. This is to cover the case where a user has the 'paid' role, such a role only makes sense when referred to the resource (s)he has paid for (subscribed).
Other roles depend on the resource role/type only. This more relaxed case can be managed by the business rules implemented in the permission query API, eg, when the API is asked for the 'access' permission to a 'public' resource, the corresponding decision rules check the resource, then checks its role and return true/false if the resource is public/paid. Similarly, if a user role is 'admin', the decision rules decide the user has access to anything without restrictions, without having to check any resource.
When a permission depends on the user role only, ie, 'admin', then it is defined/stored like:
(perm = 'canRegisterUser', requiredRole = 'admin', applyToResourceType = 'any')Permission
A permission is a value associated to a permission name. A Permission name is associated to a data type. As mentioned above, a permission value depends primarily on two parameters: a resource role combined with a user role.
Examples:
resourceAccessboolean value,userInputGenesint value,savedNetworkLimitsa permission which of values are objects like:{ nodes: 100, edges: 500 }. This is a very hypothetical example, just to show the flexibility of the approach.Here we are generalising permissions to data values of any type, while they're commonly intended as boolean types (you can/can't do something). This doesn't appear to be a big deal (TODO: or does it? Open to discussion).
When a permission is queried for these two parameters, both the resource role and the user role are intended as referring to the same resource. For instance, if a query is like: `getPerm ( perm = 'userInputGenesLimit', userRole = 'subscribed', resourceRole = 'paid'), it's implicit that we're asking how many genes the user can filter for a resource (s)he is subscribed.
This will be the base to implement other API queries that will be more specific on the user and resource parameters, eg,
getPerm ( 'access', userId = u123, resourceId = 'cereals' )Roles have a rank
Both user and resource roles are intended as ranked, having a priority, or being hierarchical. That, is if the permission to access a public resource is available for a 'guest' user, then the same permission is available to registered, paying and admin users, even when that isn't specified explicitly.
This must be taken account in the query API implementation, eg, `getPerm ( 'access', 'registered', 'paid' ) must check if 'access' is a permission that is available for user having 'registered' or higher role, and for resources having 'paid' or lower role.
As said above, 'any' is a resource type of highest rank (with resource role ordering).
'admin' (or 'root', or alike) is the highest role within user roles.
TODO: the alternative is telling permissions for each role, possibly with many repetitions. This is open to discussion, but I (MB) don't think we want it.
TODO: Do we need partial order? That is, could two roles have the same rank? Hypothetical example: a user might pay to save networks within a paid resource, but not for exporting data, or vice versa (they pay to export, not to save). We have two roles (
subscribedSave,subscribedExport) and potentially, none is superior to the other. If we want to support use cases like this, then we need to be able to associate multiple roles to a user (same for resource roles). I (MB) would say not needed for now, but I prefer to raise the point hereby.Query Interfaces
In the follow, we report the main access control queries we expect to need from the clients.
Note that we adopt these conventions:
UserRoleis assumed to be an enumeration, eg, it holds values likeUserRole.GUEST,UserRole.SIGNEDUP. It also has role-specific methods, such asUserRole.can ( UserRole otherRole ), which is supposed to tell if the current role has the same power ofotherRoleor if it's more powerful (ie, has a higher rank). TODO: define this more precisely.ResourceRole, it's just another enumeration (both derived from the same top class or interface).<T>is to mean a generic type T (taken from the Java or C++ syntax). A signature like:<T> T foo ( T param )meansfoo()is taking a parameter of type T and is returning a value of the same type. The exact type for T is established at invocations, eg,int x = foo ( 2 )binds T to an int,String s = foo ( 2 )an error (since bothparamand the return value must be of the same type).<T> T getPermission ( String permissionName, UserRole userRole, ResourceRole resourceRole )Returns the value for the named permission, when applied to a user having the specified role within a resource with the specified resource role.
As said above, in general, a permission value depends on the user role within a given resource.
This will be the function containing the core of the business logic to establish user permissions, many other methods will invoke this one to resolve different parameters, such as user ID or resource ID.
Such business logic will apply the priority/ranking rules mentioned above, eg, if
UserRole = REGISTERED, ResourceRole = PUBLIC, the business logic may grant the access permission, based on the fact this is granted for the lower-rank role 'GUEST' (ie, doesn't need to be re-defined for REGISTERED).Note about security: when client code (eg, KnetMiner API) needs to check a permission for the current user and a dataset, the safest way to do so is that they invoke the access control API with a valid session ID (or authentication token, or equivalent), so that the API provider (eg, KnetSpace) can verify the authentication information is valid. Without this server-side checking, access control code may be circumvented by technically-savy users, eg, if some Javascript holds a variable for the current user (or its current role), that can be changed (into admin...) from a browser console.
Examples:
Example 1:
Example 2:
<T> T getPermission ( String permissionName, User user, Resource resource )Resolves a permission for a user and a resource. Internally, it will call the flavour with role parameters.
<T> T getPermission ( String permissionName, String sessionId )Resolves a permission by taking the current user and dataset (and hence the corresponding roles) from the current authenticated session. As said above, this is the safe method to use to enforce access restrictions.
References
Beta Was this translation helpful? Give feedback.
All reactions