...
The permission model will be permission-based, assigning a role vis-a-vis a specific target model (aka a “grant”“permission”);
These new permissions will still be assigned to a user (not their assignment to an organization; this has important consequences for managing rolesmodeled as an association between an Account record and any other record in the system…this is easier to implement but it means that permissions won’t be cascade deleted when the target objects are deleted, only when the account is deleted);
Organizations will principally be a means to communicate who can see whom in a multi-tenanted application. Accounts will be assignable to multiple organizations. Migrated accounts will be given permissions to the sponsored studies of that organization, and then going forward, a user will at least have the auditor role for all studies sponsored by all of their organizations (this is the only transitively assigned role we’ve identified at this time and even that is optional);
Bridge roles are hierarchical. Generally a user should have only one role vis-a-vis a model object. For example, being a study designer implies that you can read information about studies, like the auditor role. Every study designer does not also have to be an auditor. PI_Agent could be an example of an exception to this.
Currently an app-scoped developer, researcher, or admin can operate on any model in the app that requires that role (or its scoped counterpart, like study designer). WHAT SHALL WE DO ABOUT DO WE WANT TO AXE THIS?
Use Cases
Use Case | |
---|---|
Permissions changes should register for users without them having to sign out and sign back in again | If cached they need to be separate from the session in Redis. Otherwise, reading them on each request would meet this requirement. |
New admin account created with a sandbox in which studies can be created/edited that are not visible to others | When an account creates a study, it will be made the admin of that study. Searching for lists of studies will only return studies for which the caller has a role (which might be transitively assigned through an organization, effectively saying that organization membership grants visibility to studies as well). |
“Sandbox” can be converted to real study, with additional users in specific roles for that study | Admin of a study can add additional users. We have not specified how we will make a study an “evaluation” study but that would need to be removable. |
Study is extended by creating a new study | Admin of the new study would need to copy over all the permissions from the old study. Bridge’s APIs should make this straightforward to do. |
Add someone to a study’s administration team | Add a permission (a role vis-a-vis the study) to that study. |
Remove someone from a study’s administration team | Remove a permission (a role vis-a-vis the study) from that study. |
Create similar authorization model for assessments | We should be able to expand this approach to any other model object we want to secure. |
...
Note that membership in an organization is also directly modeled in the database right now via the Account.orgMembership field, and will be moved to an associative table. We may not need a “member” role though it may be more convenient. If we continue to model this in the database, it’ll become an associative table and that association could specify the roles you gain as a member of the organization—however no one is asking for this so I don’t intend that we will do it.
Implementation
We will introduce a flat table of Permission records that can be easily retrieved by user or by target model object:
Code Block | ||
---|---|---|
| ||
public class Permission { String guid; // synthetic key makes create/add/update APIs easier String appId; // this always has to be part of the query String userId; String role; // "admin", "developer" String objectType; // "study", "organization", "app", "system" String objectId; // "studyId", "orgId", "appId" boolean transitive; // e.g. true if permission comes from org membership // Suggested toString() descriptor (implicitly scoped to an app): // "2rkp3nU7p8fjUTDVIgjT6T is∈ an {organization:sage-bionetworks admin}" } |
The service (which we’ll probably access through Spring Security, see below):
...