Access Control

Many applications need to have restrictions on what information can be accessed by what users. To meet these requirements, SRCH2 provides native support of access control to set restrictions on search results.

As shown in the following figure, SRCH2 supports two types of access control:

Access Control Overview

A simple way to do record-based access control is to introduce a multi-valued attribute to a resource core to include the information about roles who can access each record. This approach is known to be slow and inefficient, and not acceptable for large amounts of information or very dynamic ACL changes. To solve this problem, SRCH2 adopts an advanced implementation to deliver higher performance.

In this documentation we use the following example to explain how to use SRCH2 to do access control:

The following are sample records in the "product" core:

product.json

{"pid" : "p501", "name" : "laptop", "description" : "Inspiron with Windows", "price" : 600, "manufacturer" : "Dell", "state" : "Texas"}
{"pid" : "p502", "name" : "phone", "description" : "Samsung Galaxy with Android", "price" : 350, "manufacturer" : "Samsung", "state" : "California"}
{"pid" : "p503", "name" : "phone", "description" : "iPhone 5", "price" : 500, "manufacturer" : "Apple", "state" : "California"}

The file is provided under the example-demo/acl folder. By doing access control, we can allow a user (specified as a string) to access certain records and certain attributes in the product table.

To submit a query as a specific user, we need to add a "roleId=XYZ" condition in the query, where "XYZ" is the id of the user. For instance, consider the following query:

Q1: curl -i "http://127.0.0.1:8081/product/search?q=phone&roleId=u26"

This query is asking for products with the keyword "phone" as a user "u26". The engine will find records that can accessed by this role with attributes accessible by the role.

2. Record-Based ACL

2.1 Configuration File

In the configuration file, we want to tell the engine to use product as the resource core. For this purpose, we use an access-control tag as shown below:

<cores>
 <core name="product">
   ...
  <access-control>
   <record-acl  datafile="record-acl-product.json" /> 
  </access-control>
 </core>

<cores>

Under the record-acl tag, there is a data file record-acl-product.json, which includes the initial ACL information to be loaded by the engine. Each line includes an primary id of the product core and an array of role ids (strings). The following are example records:

{"resourceId" : "p501" , "roleId" : ["u25", "u26"]}
{"resourceId" : "p502" , "roleId" : ["u26"]}
{"resourceId" : "p503" , "roleId" : ["u27", "u28"]}

For instance, the first line says that the product with the id "p501" can be accessed by users named "u25" and "u26". The second line says that the product with the id "p502" can be accessed by the user named "u26".

For query Q1 above, the engine returns product "p502" only. It will not return product "p503", even though it has the keyword "phone", since it cannot be accessed by this user. In general, the engine ignores records that cannot be accessed by this role. Notice that the core name "product" is case sensitive.

2.3 Insert Records with ACL

When we insert a record to the resource core product, we can optionally also include ids of roles that can access this record. For instance, consider the following query:

curl "http://127.0.0.1:8081/product/docs" -i -X PUT -d '{"pid" : "p531", "name" : "laptop", "description" : "Vaio Windows", "price" : 550, "manufacturer" : "Sony", "state" : "Utah", "roleId" : ["u26", "u28"]}'

The tag "roleId" is followed by an array of ids of roles that can access this new record. If no "roleId" is provided, then by default no role can access this new record. After the command above, the following query Q2 will not find record "p531", since this record cannot be accessed by user "u27".

Q2: curl -i "http://127.0.0.1:8081/product/search?q=utah&roleId=u27"

2.4 Replace an ACL

We can modify the ACL of a product record by using a command "aclRecordRoleReplace":

curl "http://127.0.0.1:8081/product/aclRecordRoleReplace" -i -X PUT -d '{"resourceId" : "p531", "roleId":["u27", "u28"]}'

This command will replace the existing ACL (if any) of the product "p531" with two role ids, namely "u27" and "u28". The old list of role ids for this product will be deleted. After this command, query "Q2" should be able to find record "p531".

We can also pass an array of pairs of a product id and a list of role ids, e.g.:

curl "http://127.0.0.1:8081/product/aclRecordRoleReplace" -i -X PUT -d '[{"resourceId": "p531", "roleId":["u26", "u28"]} , {"resourceId": "p502", "roleId":["u25"]}]'

2.5 Append Roles to ACL

We can add more roles to the ACL of a product record by using a command called "aclRecordRoleAppend":

curl "http://127.0.0.1:8081/product/aclRecordRoleAppend" -i -X PUT -d '{"resourceId":"p531", "roleId":["u25", "u28"]}'

This command will add "u25" and "u28" to the existing ACL of the product "p531". If the ACL did not exist, the engine will create one. We can also pass an array of pairs of a product id and a list of role ids, e.g.:

curl "http://127.0.0.1:8081/product/aclRecordRoleAppend" -i -X PUT -d '[{"resourceId": "p531", "roleId":["u25", "u28"]} , {"resourceId": "p502", "roleId":["u27"]}]'

2.6 Remove Roles from ACL

We can remove some roles from the ACL of a product record by using a command called "aclRecordRoleDelete":

curl "http://127.0.0.1:8081/product/aclRecordRoleDelete" -i -X PUT -d '{"resourceId":"p531", "roleId":["u25", "u27"]}'

This command will remove "u25" and "u27" from the ACL of the product "p531". After running this command, query Q2 will no longer find record "p531".

We can also pass an array of pairs of a product id and a list of role ids, e.g.:

curl "http://127.0.0.1:8081/product/aclRecordRoleDelete" -i -X PUT -d '[{"resourceId": "p531", "roleId":["u25", "u27"]} , {"resourceId": "p502", "roleId":["u25"]}]'

In the rest of the documentation, we want to start with the status where user "u27" can access product "p531" by running the following command:

curl "http://127.0.0.1:8081/product/aclRecordRoleAppend" -i -X PUT -d '{"resourceId":"p531", "roleId":["u27"]}'

3. Attribute-Based ACL

The SRCH2 engine also allows developers to specify roles that can access an attribute. Here is how it works.

3.1 Configuration File

In the running example, suppose we want to do access control on the attributes name, description, and state of the product core. In the configuration file, we need to add the tag acl="true" to these three attributes:

<cores>
 ...
 <core name="product"> 
  <schema>
    <fields>
       <field name="pid" type="text"/>
       <field name="name" type="text" indexed="true" acl="true"/>
       <field name="description" type="text" indexed="true" acl="true"/>
       <field name="price" type="integer" indexed="false" required="true" refining="true"/>
       <field name="manufacturer" type="text" indexed="true" refining="true"/>
       <field name="state" type="text" refining="true" indexed="true" acl="true"/>
    </fields>
  </schema>
  ...

  <access-control>
    <attribute-acl  datafile="attribute-acl-product.json" />
  </access-control>

 </core> 
...
</cores> 

The other attributes without this tag are not ACL-attributes, i.e., they can be accessible by all roles, and we cannot do access control on them.

We can also specify a file with initial attribute ACL information for the product attributes. The data file attribute-acl-product.json under the "attribute-acl" tag has attribute ACL information for attributes. For instance:

{ "attributes": ["name", "description"], "roleId": ["u25"]}
{ "attributes": ["name", "state"], "roleId": ["u26", "u27"]}

The first line says that attributes "name" and "description" can be accessed by role "u25", while the second line says that attributes "name" and "state" can be accessed by roles "u25" and "u27".

For a role-based search, the engine will apply the conditions to those attributes that are either public (i.e., non-ACL), or accessible by this role. Consider query Q1 as an example (copied below):

Q1: curl -i "http://127.0.0.1:8081/product/search?q=phone&roleId=u26"

Since role "u26" can access attributes "name" and "description", the query will find records that have keyword "phone" in attributes "pid" (public attribute), "name" (ACL attribute), "description" (ACL), "price" (public), "manufacturer" (public), but will ignore the attribute "state" since it cannot be accessible by this role. The query will find record "p502", without showing the "description" attribute since it cannot be accessed by this role.

As another example, consider the following query for keyword "laptop", with a condition that the state of each matching record has to be "texas":

Q3: curl -i "http://127.0.0.1:8081/product/search?q=laptop&fq=state:texas&roleId=u25"

Since this role "u25" does not have the access to the "state" attribute, this "fq=state:texas" condition will be ignored by the engine. As a consequence, the engine returns one record "p501", without showing the "state" value of the record.

3.3 Replace Roles of Attributes

We can replace the ACL list of attributes using a command "aclAttributeRoleReplace". For instance:

curl "http://127.0.0.1:8081/product/aclAttributeRoleReplace" -i -X PUT -d '{"attributes": ["description", "state"], "roleId": ["u26", "u28"] }'

This command will replace the existing ACLs of attributes "descriptions" and "state" with roles "u26" and "u28". After running this command, the query Q2 above will not find record "p531" any more since user "u27" can no longer access the attribute "state", which matches the keyword "utah".

3.4 Append Accessible Attributes

We can add more attributes accessible by a role with a command "aclAttributeRoleAppend". For instance:

curl "http://127.0.0.1:8081/product/aclAttributeRoleAppend" -i -X PUT -d '{"attributes": ["description", "state"], "roleId": ["u26", "u27"]}'

This command will allow the roles "u26" and "u27" to access the attributes "description" and "state". After this command, query Q2 should be able to find record "p531" again.

3.5 Disallow Attributes

We can disallow a role from accessing attributes with a command "aclAttributeRoleDelete". For instance:

curl "http://127.0.0.1:8081/product/aclAttributeRoleDelete" -i -X PUT -d '{"attributes": ["state"], "roleId": ["u26", "u27"]}'

This command disallows the roles "u26" and "u27" from accessing the attribute "state". After running this command, query Q2 can no longer find record "p531".

3.6 Disabling Attribute ACL

We can disable attribute-based ACL in a search by passing a flag "attributeAcl=off". This flag means that the engine ignores attribute-based ACL during the search process, but still uses attribute ACL when generating the JSON results. That is, the engine accesses all attributes during the search, but does not output attributes that cannot be accessed by this role. Here is an example:

Q4: curl -i "http://127.0.0.1:8081/product/search?q=texas&roleId=u26&attributeAcl=off"

Notice that role "u26" cannot access the "state" attribute. For this query, the engine will ignore the attribute ACL for role "u26" during the search, i.e., the engine will access all available attributes. Thus it can find record "p501" with "texas" in the "state" attribute. When generating query results, the engine will not output the "state" attribute, which cannot be accessed by this role "u26". If we drop the "attributeAcl=off" condition, the query will not find any record.