Read Permissions

Read Permissions are facts that govern whether facts are readable.

Permission Basics

The default permission for accessing any fact is restricted to agents representing the login that created the fact.

Permissions can be granted to any agent pattern using the permission API call.

Example:

POST /permission {
    "targetNodeId": "00000000FCDF978BA9BFAE5D1DEC365B59A249A6B01E3987",
    "policy": {
        "effect": "Allow",
        "granteeId": "00000000301D1F22157CE46BAAB422C13F0F368218027D50",
        "applicationId": "00000000DAB38B0E3390E09DFF52EF2AED6833F11BBC8896",
        "actions": ["Read"]
    }
}

sets a permission on target node having id "00000000FCDF978BA9BFAE5D1DEC365B59A249A6B01E3987". The permission allows read of the target node by the login with id "00000000301D1F22157CE46BAAB422C13F0F368218027D50" using the application with id "00000000DAB38B0E3390E09DFF52EF2AED6833F11BBC8896".

The login part of the agent making the permission call must match the login part of the fact corresponding to the targetNodeId. That is, only the creator of the target fact can set a permission on it.

The permission policy is the core of the permission.

Permission Policy Properties

Property Optional Description
effect false Whether to allow or deny permission
actions false The kind of actions the permission is addressing. The value must be Read for read permissions
granteeId true The group, login or entity requesting permission
applicationId true The application with which the permitted grantee is requesting permission
requestInterfaceId true The interface that is responsible for allowing the permission
scopeId true The scope of the nodes covered by this permission

Permission Effect

Effect Description
Allow Allow the given action
Deny Deny the given action

Permission Checking using the FacternAgent

Every fact in Factern has an associated agent that created the fact. Similarly, every API call has an associated agent. It is a comparison between the agent making the API call and the agent associated with the fact that determines whether the calling agent has access to the fact.

By default, if the calling agent login/application is identical to the fact's login/application, the calling agent has permission to read the fact. Otherwise, access to the fact from the calling agent is governed by any permissions associated with the fact.

The table details how the specification of a granteeId and/or applicationId in a permission applies to a calling agent's access to the node or nodes targeted by the permission.

granteeId applicationId Effect Accessibility by agents
unspecified unspecified Allow Allow access to any agent
unspecified unspecified Deny Deny access to every agent
specified unspecified Allow Allow access to any agent having the specified login using any application
specified unspecified Deny Deny access to any agent having the specified login using any application
unspecified specified Allow Allow access to any agent using the specified application from any login
unspecified specified Deny Deny access to any agent using the specified application from any login
specified specified Allow Allow access to the agent having the specified login and application
specified specified Deny Deny access to the agent having the specified login and application

Permission Precedence

There are occasions where two contradictory permissions target the same node. How do we determine which policy wins?

  • Prefer permissions that target a node rather than permissions that target the node's associated entity

If both permissions target the same node, then

  • Prefer permissions that specify a grantee/application rather than a permission that does not

If both permissions either specify a grantee/application or do not specify, then

  • Prefer a permission that has a DENY effect over one that has an ALLOW effect

Scopes

Rather than individual nodes or entities, a permission can be specified to cover a whole class of nodes using a scope. A scope is a fact that brings together multiple templates and filters. When a scope is specified on a permission, the scope's templates and filters are applied to the permission's target node, and any nodes covered by those templates and filters are covered by the permission.

For example consider the template:

POST /createtemplate
{
    "parentId": "00000000C320A7BFD903745851915F6C33D20634E36C37C6",
    "name": "PersonProfile",
    "description": "A person's relevant data",
    "memberIds": [
        "FullName",
        "FullAddress"
    ]
}

and scope including the template:

POST /createscope {
    "parentId": "00000000C320A7BFD903745851915F6C33D20634E36C37C6",
    "name": "ProfileScope",
    "templateIds": [
        "PersonProfile"
    ]
}

A permission defined as:

POST /permission {
    "targetNodeId": "00000000FCDF978BA9BFAE5D1DEC365B59A249A6B01E3987",
    "policy": {
        "effect": "Allow",
        "granteeId": "00000000301D1F22157CE46BAAB422C13F0F368218027D50",
        "applicationId": "00000000DAB38B0E3390E09DFF52EF2AED6833F11BBC8896",
        "actions": ["Read"],
        "scopeId": "ProfileScope"
    }
}

would allow read access for the given granteeId and applicationId to the FullName and FullAddress fields of the entity having id "00000000FCDF978BA9BFAE5D1DEC365B59A249A6B01E3987".

Requestable Permissions

Factern allows an additional layer of checking in permissions. Permissions specified with a requestInterfaceId are called Requestable Permissions. If an agent otherwise matches the permission policy, then the status code returned when reading the target node will be the special status code 477. The requestpermission API call can be used subsequently for requesting the permission to be granted.

In the case that a node has more than one associated Requestable Permission the most specific matching requestable permission is used. If there is more than one such requestable permission, then the requestable permission used is arbitrary.

Example:

In this example we use a requestable permissions to get access to the FullName field of the "Bob Watson" entity having Factern Id "0000000079C27D120B58F74C683639EE72EA2E33B93293CB". The "Bob Watson" entity and fields were created by the HumanResources login, having Factern Id "00000000F101AB12CC65E5CE2F42E0C9FEC9CBEEEEC03AA3".

We start by attempting to read the FullName field from the Payroll login, having Factern Id "00000000B04BCB6670E3E4F35EDCE6CD8AF77111C74150AE".

POST /read {
    "template": ["frn:field:00000000F101AB12CC65E5CE2F42E0C9FEC9CBEEEEC03AA3:FullName"],
    "nodeId": "0000000079C27D120B58F74C683639EE72EA2E33B93293CB"
}

The response is 403, Forbidden, since the Payroll login has no permission on the "Bob Watson" entity.

We want to make personnel entities available if the reading login is Payroll, but only on a case-by-case basis approved by the Hunam Resources director. They have set up a webservice for receiving permission requests that translates the request to an email to the director. If approved, the requested permission will be created.

We first register the webservice with Factern.

POST /createinterface {
    ...
    "name": "PermissionApproval",
    "addData": {"url": "https://hr.acme.com/permapprove"},
    ...
}

We now create the requestable permission, indicating that Read requests from the Payroll login will be sent to the approval webservice.

POST /permission {
    "targetNodeId": "0000000079C27D120B58F74C683639EE72EA2E33B93293CB",
    "policy": {
        "effect": "Allow",
        "grantee": "00000000B04BCB6670E3E4F35EDCE6CD8AF77111C74150AE",
        "requestInterfaceId": "PermissionApproval",
        "actions": ["Read"]
    }
}

Now, when the Payroll login attempts a Read, the response is the special Http status code 477, indicating that the permission is requestable.

The Payroll login now requests the permission.

POST /requestpermission {
    "nodeId": "0000000079C27D120B58F74C683639EE72EA2E33B93293CB"
}

The Human Resources webservice is called with a payload indicating the permission request.

POST https://hr.acme.com/permapprove?nodeId=0000000001290F75C24695FA55F40D85843EA40FCB5B49F2
{
    "targetNodeId": "0000000079C27D120B58F74C683639EE72EA2E33B93293CB",
    "policy": {
        "effect": "Allow",
        "grantee": "00000000B04BCB6670E3E4F35EDCE6CD8AF77111C74150AE",
        "applicationId": "00000000DAB38B0E3390E09DFF52EF2AED6833F11BBC8896",
        "actions": ["Read"]
    }
}

Assuming the director approves, the Human Resources app is used to create the permission. The app might make the following API call to set the permission:

POST /permission {
    "targetNodeId": "0000000079C27D120B58F74C683639EE72EA2E33B93293CB",
    "policy": {
        "effect": "Allow",
        "grantee": "00000000B04BCB6670E3E4F35EDCE6CD8AF77111C74150AE",
        "applicationId": "00000000DAB38B0E3390E09DFF52EF2AED6833F11BBC8896",
        "actions": ["Read"]
    }
}

Here they used the exact payload that was POSTed to their webservice by Factern, but they could have made any request, or no request.

Now, the Payroll login can make the requested read getting the following response:

Response
[{
    "status": 200,
    "readItem": {
        "fieldId": "000000008BFE6BB9A2A3F80F23DC6E738470F24B95E5102A",
        "nodeId": "0000000043F912B92911FFE2A52E31066E8B653D3F7E8DE7",
        "data": "Bob Watson"
    }
}]