Note: Note: status field in LocationData might be suitable for returning a list of unfulfilled requests or at least the URI for asking what's unfulfilled.
NOTE: As of 3/27/2012 the following is out of date and needs to be rewritten...
Background
IRB-approved versions of all of the 'data access documents' :
Summary:
- Data layer access in Synapse requires one or more approval steps.
- In Synapse granting data access is synonymous with providing the URL to the stored data.
(This URL may have an embedded access token.)
- Currently (i.e. as of Jan. 2012), the backend has a representation of EULAs and of Agreements (i.e. that a particular user agrees to a EULA)
- The work flow logic for creating the agreement is embedded in the Web client, so other clients would have to maintain duplicate logic. Specifically, the web client has the following logic:
1) When a user tries to download a layer, the Web client checks whether the parent dataset has an associate EULA;
2) If there is an EULA, the web client checks whether there is an Agreement, owned by the User and referencing the dataset and EULA;
3) If there is a EULA but no Agreement, the web client prompts the User to sign the EULA, creates the Agreement, then allows the download.
...
Tier 3: (Tier 1) + (Tier 2) + User access must be requested/approved through an Access and Compliance Team (ACT).
Design
...
Database
- We add a 'Download' permission, as distinct from 'Read' permission to entity access control lists.
- In order for a user to get the location field(s) of an entity, they must have Download permission.
Workflow Model
Design Assumptions
Things the client should NOT 'know'
- what requirements need to be met to obtain a permission (e.g. you need to sign a EULA to access a Layer's location)
- what requirements have/have not been met by a User (e.g. whether a EULA has been signed)
- whether it can access a certain field of a certain entity
Things the client SHOULD 'know'
- how to fulfill a requirement (e.g. if a EULA needs to be signed, knows how to retrieve and display the EULA, get it signed, and submit the appropriate request to the repo service)
Design Approach
Field access service
- Given an entity, find out what access on what fields the user has
The permission service
- Add a new 'permission' service which (1) grants permissions if requirements are met or (2) otherwise reports what requirements need to be met. E.g. POST /layer/101/permission/Download, where '101' is an entity ID, would either (1) grant the requested permission (Download) if the user meets the requirements or (2) return a (401) response with a body of the form
Code Block |
---|
{
[ {type:EULA, params:{uri:/eula/987}, msg:status-msg}, {type:EULA, params:{uri:/eula/654}, msg:status-msg}, {type:ACT, params:{uri:/act/321}, msg:status-msg}]
}
|
listing the unmet requirements.
(Optionally, just one of multiple unmet requirements could be returned, allowing the server to control the order in which requirements are considered by the client.)
There are three parts to a requirement:
- type: from an ENUM, e.g. 'EULA', 'ACT'.
- params: a map of parameters used by the given 'type'. The client needs to know what to do for each enum, and how to use its parameters. This will be documented in the developers' API.
- msg: An optional status message, suitable for display to the user.
If a requirement has no type or params but has a message, then there is nothing for the user to do and the message helps explain why, e.g. {msg:"ACT approval pending"}
Permission Manager
The repository service will have a Permission Manager, which computes the response to the permission request from a given user for a given entity. E.g. if a Layer required EULA 987 to be signed for a user to access it, and EULA 987 is not yet signed by the user, then the Permission Manager adds this requirement to the response to thepermissions request. The unmet requirements are stored *implicitly* in the state of the repository services, and the PM determines the unment requirements upon request.
Object Model for Permission Requirements
An entity may have Requirement child entities (or should these be properties of an entity?). These entities (properties?) contain the details of what is required to obtain specific permissions on the object (e.g. <Download,EULA,/eula/987>). The PM refers to these entities (properties?) to make its assessment.
Additional Services
- requirements CRUD services: allows the owner of an object to craft requirements for an object (or should this be rolled into the current permissions management?)
Tier 1 Approval Process
Here the user signs the Tier 1 agreement upon account creation. (Omitted are the steps in which the client retrieves the schema and the current ACL to determine that the user doesn't have the necessary permissions.)
Tier 2 Approval Process
This approval requires two hurdles, the Tier 1 agreement plus a new agreement which may be specific to the requested layer.
How do you revoke approval?
1) remove the <User, Permission> from the layer's ACL.
2) delete the permission requirement from the entity.
Tier 3 Approval Process
Here we have the added complexity of an external ACT.
We have two tables, one for ACCESS_REQUIREMENT, with a foreign key to a node (object) and one for ACCESS_APPROVAL, having foreign keys to ACCESS_REQUIREMENT and principal. The first imposes a requirement for access to the node. The second fulfills the requirement, for a given principal. ACCESS_REQUIREMENT has a 'REQUIREMENT_TYPE' field along with a variable 'REQUIREMENT_PARAMETERS' blob, allowing it to be used for Tier 2 or Tier 3 requirements. (The 'parameters' field could be a Eula, a form to be filled out, or something else.) The ACCESS_APPROVAL table has an APPROVAL_TYPE and an APPROVAL_PARAMETERS blob, allowing it to be used for Tier 2 or Tier 3 approval. (The 'parameters' field could be some form contents, user's IRB information, information from the ACT, or something else.)
Below we omit the primary key and foreign key constraints for simplicity.
Code Block |
---|
CREATE TABLE `ACCESS_REQUIREMENT` (
`ID` bigint(20) NOT NULL,
`ETAG` bigint(20) NOT NULL,
`CREATED_BY` bigint(20) NOT NULL,
`CREATED_ON` bigint(20) NOT NULL,
`MODIFIED_BY` bigint(20) NOT NULL,
`MODIFIED_ON` bigint(20) NOT NULL,
`NODE_ID` bigint(20) NOT NULL,
`ACCESS_TYPE` varchar(256) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`REQUIREMENT_TYPE` varchar(256) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`REQUIREMENT_PARAMETERS` mediumblob,
)
|
Code Block |
---|
CREATE TABLE `ACCESS_APPROVAL` (
`ID` bigint(20) NOT NULL,
`ETAG` bigint(20) NOT NULL,
`CREATED_BY` bigint(20) NOT NULL,
`CREATED_ON` bigint(20) NOT NULL,
`MODIFIED_BY` bigint(20) NOT NULL,
`MODIFIED_ON` bigint(20) NOT NULL,
`REQUIREMENT_ID` bigint(20) NOT NULL,
`ACCESSOR_ID` bigint(20) NOT NULL,
`APPROVAL_TYPE` varchar(256) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`APPROVAL_PARAMETERS` mediumblob
)
|
Data Access Object (DAO)
We have DAOs for AccessRequirement and AccessApproval objects. In addition to basic CRUD operations we have:
- AccessRequirementDAO.getForNode(), which returns all the AccessRequirements associated with a Node/Entity
- AccessApprovalDAO.getForAccessRequirementsAndPrincipals() which returns the AccessApprovals for a given list of AccessRequirements and Principals. This method allows us to look up the approval of all the access requirements for a given node with a single database query.
JSON Schema
We introduce JSON schemas for AccessApproval and AccessRequirement, mirroring the tables above, BUT omitting the variable fields. This is because the json schema cannot know the a priori the schema of such variable fields, which are managed separately. We intoduce ENUMs for AccessRequirementType and AccessApprovalType (e.g. ("TOU_Agreement", "ACT_Approval").
We introduce TermsOfUseRequirementParameters to hold the Terms of Use document for an AccessRequirement whose type is TOU_Agreement.
Services
AccessRequirement: Create, Read, Update, Delete
action | uri | HTTP method | Request parameters | Schema | Authorization |
---|---|---|---|---|---|
create AccessRequirement | /accessRequirement | POST | -- | AccessRequirement.json | parent Entity's UPDATE permission or CHANGE_PERMISSION permission ??? |
read AccessRequirement | /accessRequirement | GET | AccessRequirement ID | AccessRequirement.json | parent Entity's READ permission |
retrieve paginated list of unfufilled access requirements | /unfulfilledAccessRequirements | GET | Entity ID | PaginatedResults<AccessRequirement> | parent Entity's READ permission |
update AccessRequirement | /accessRequirement | PUT | AccessRequirement ID | AccessRequirement.json | parent Entity's UPDATE permission or CHANGE_PERMISSION permission ??? |
delete AccessRequirement | /accessRequirement | DELETE | AccessRequirement ID | ---- | parent Entity's UPDATE permission or CHANGE_PERMISSION permission ??? |
create TermsOfUseRequirementParameters | /termsOfUseRequirementParameters | POST | -- | TermsOfUseRequirementParameters.json | parent Entity's UPDATE permission or CHANGE_PERMISSION permission ??? |
read TermsOfUseRequirementParameters | /termsOfUseRequirementParameters | GET | AccessRequirement ID | TermsOfUseRequirementParameters.json | parent Entity's READ permission |
update TermsOfUseRequirementParameters | /termsOfUseRequirementParameters | PUT | AccessRequirement ID | TermsOfUseRequirementParameters.json | parent Entity's UPDATE permission or CHANGE_PERMISSION permission ??? |
delete TermsOfUseRequirementParameters | /termsOfUseRequirementParameters | DELETE | AccessRequirement ID | -- | parent Entity's UPDATE permission or CHANGE_PERMISSION permission ??? |
create AccessApproval | /accessApproval | POST | -- | AccessApproval.json | parent Entity's CHANGE_PERMISSION permission ??? |
read AccessApproval | /accessApproval | GET | AccessApproval ID | AccessApproval.json | parent Entity's READ permission |
update AccessApproval | /accessApproval | PUT | AccessApproval ID | AccessApproval.json | parent Entity's CHANGE_PERMISSION permission ??? |
delete AccessApproval | /accessApproval | DELETE | AccessApproval ID | -- | parent Entity's CHANGE_PERMISSION permission ??? |
Web UI
TBD