Introduction

Attributes are name/value pairs that can be associated with triples. Names and values must be strings. Attributes can only be associated with a triple at the time the triple is added to the triple store (with tools such as add-triple or agload). Once a triple is in the store, its attributes, if any, cannot be modified.

There are many potential uses of triples attributes, including access control. Attributes can specify which users can access which triples. Users can also be given attributes, which can be compared to the triple attributes. Suppose for example there is an attribute name "security-level" with values "high", "medium" and "low". Then a user with "security-level" attribute "medium" can be prevented from viewing triples with "security-level" attribute "high".

Because triples can have as many attributes as desired and attributes can have as many values as desired (there are configurable limits but the defaults are much larger than any conceivable application), access control can be as finely tuned as desired.

Attributes can be associated with triples when adding them one statement at a time, or via file import. Once a triple has been added to a repository, its associated attributes cannot be changed or removed.

Attribute characteristics

An attribute is a name/value pair where both the name and the value are strings. Attributes are assoicated with specific triples. While the theoretical maximum size of an attribute value is approximately one terabyte, the pratical maximum size will be limited by the amount of available virtual memory and address space.

There are restrictions on the characters allowable in an attribute name. An attribute name may be composed of characters of the following types:

That is, standard 7-bit ASCII characters are restricted to letters and digits and two additional characters (- and _) but anything outside the standard 7-bit ASCII range is allowed.

Associating attributes with triples: NQX files

A new format has been designed, called Extended N-Quad format (NQX, for short) which extends the N-Quads format to allow the specification of attributes for each triple in the file.

Each line of an NQX file has the following format:

[An N-Quad line without the ending .] [attributes] . 

N-Quad lines are defined here. The attributes can be absent. If present, it must be in JSON format:

{ "pet": "dog", "key2": [ "red", "blue" ] } 

Here we specify three attribute name/value pairs:

"pet"/"dog"  
"key2"/"red"  
"key2"/"blue" 

Here are some sample lines from an NQX file:

_:b0EF918FCx100 <http://example.org/ontology/infractions> <http://example.org/ontology/Infraction#ExcessiveTardiness> {"securityLevel": "high", "department": "hr", "accessToken": ["E", "D"]} .  
_:b0EF918FCx100 <http://example.org/ontology/salary> "100000"^^<http://www.w3.org/2001/XMLSchema#int> {"securityLevel": "medium", "department": ["accounting", "hr"], "accessToken": "A"} .  
_:b0EF918FCx100 <http://example.org/ontology/department> <http://example.org/ontology/ops> {"securityLevel": "low", "department": ["sales", "accounting", "hr", "devel"], "accessToken": "A"} .  
_:b0EF918FCx100 <http://example.org/ontology/name> "Joe Smith" {"securityLevel": "low", "department": ["sales", "accounting", "hr", "devel"], "accessToken": "A"} . 

N-Quad format supports optionally specifying a graph. Those example lines do not includes graphs. Here is a line with a graph (<http://ex#trans@@1142684573200001>):

<http://dbpedia.org/resource/Arif_Babayev> <http://dbpedia.org/property/placeOfDeath> <http://dbpedia.org/resource/Baku> <http://ex#trans@@1142684573200001> {"color": "red"} . 

The system distinguishes between a graph and an attribute specification because attributes are specified in JSON format and graphs are not.

Attributes must be defined before a file using them can be loaded. Attributes cannot be defined in a NQX file or in any triple format file. See the Defining Attributes section for information on defining attributes.

For all other supported triple file formats (N-Quad, N-Triple, Turtle, etc.), a set of default attributes can be specified at import time. These default attributes will be attached to each triple imported from the source. When NQX files are loaded, they too can have default attributes specified and those will be associated with any triple in the file that does not have individual attributes specified. See the Data Loading document.

Defining attributes

Attributes must be defined before they can be used. Defining an attribute establishes the name of an attribute and any constraints that should be placed on its use. Attributes can be defined in various ways. The Java interface uses methods in the AGRepositoryConnection.AttributeDefinition class (see the Javadoc index). There is a complete example in java-tutorial/AttributesExample.java. The REST/HTTP interface can also be used to define attributes. See the Attributes section in the REST/HTTP interface document. AGWebView has a Define attributes definitions choice on the Repository page. The Lisp function define-attribute (the definition appears in the Lisp Reference document) also can be used to define attributes.

The arguments to define-attribute are

name  &key  db  allowed-values  ordered  minimum-number  maximum-number 

db is the triple store. name is the attribute name. name must be a string made up of letters, digits, the characters #\- and #_, or characters with code point 128 or greater (that is, letters, digits, hyphen, and underscore among 7-bit ASCII characters and any character that cannot be represented in 7-bit ASCII).

allowed-values, if specified, must be a list. It restricts attribute values to members of the list. The values must be strings. If attributes are ordered, then they can be compared with predicates like attribute>=.

For example, if there is a "securityLevel" attribute, it can be ordered. Suppose the allowed-values are ("low" "medium" "high"). The ordering comes from the position in the list (and not from alphabetical or other orderings, so "low" is less than "high" and so on). Each triple with attribute "securityLevel" will have a value from that list. Users can also have a "securityLevel" attribute. A filter can be set up that allows only users with a security level equal to or higher than the triple security level to access the triple.

Attribute definitions are transactional. They do not persist unless committed. Attempting to commit a definition for a name which is already committed (presumably by another authorized user) will result in a conflict, which is detected at commit time. The second committer must then roll back.

The Lisp function define-attribute can be used to define attributes. The functon add-triple has an :attributes keyword argument where the attributes of the new triple can be specified (attributes can be associated with a triple only when it is added or loaded). The various triple loading functions like load-nquads have an :attributes keyword argument which specifies the attributes to be added to all triples being loaded. The function load-nqx and load-nqx-from-string will load NQX files which allow attributes to be specified for individual triples. (Only NQX files can have attributes for individual triples specified.)

Static filters

A static filter using an S-expression-based query can be established on a given triple store. This filter will be applied to all queries. Only triples which match the filter will be returned by any query against the store.

Users can also have attributes. Therefore, the attributes of the users performing the query can be compared to the triple attributes and if the user attributes are not appropriate, the triple will be invisible to the user. User attributes can be supplied in HTTP requests using the x-user-attributes header. When supplied, the header must contain a JSON object representing attributes, for example:

{ "color": "red" }  
{ "color": ["red"] }  
{ "color": ["red", "blue"] } 

Static filter definitions are transactional. They do not persist unless committed. Attempting to commit a definition when a static filter is already committed (presumably by another authorized user) will result in a conflict, which is detected at commit time. The second committer must then roll back.

Static filter expressions

The syntax of static filters is as follows:

EXPR = (operator ARG*)  
EXPR = (and EXPR*)  
 
ARG  = BAGSPEC.ATTRIBUTE 

BAGSPEC may be "user" to indicate attributes from the x-user-attributes HTTP header, or "triple" to indicate attributes of the triple being considered for filtering.

ATTRIBUTE is the name of a defined attribute.

Operators:

attribute>=               BAGSPEC.ATTRIBUTE BAGSPEC.ATTRIBUTE 

True if the first attribute is greater than or equal to the second attribute. attribute>= is only appropriate for comparing two ordered attributes of the same type.

attribute-contains-all-of BAGSPEC.ATTRIBUTE BAGSPEC.ATTRIBUTE 

True if the first argument contains all of the attributes in the second argument. If the second argument is empty, this operater will always return true.

attribute-contains-one-of BAGSPEC.ATTRIBUTE BAGSPEC.ATTRIBUTE 

True if the first argument contains at least one of the attributes in the second argument. False if either argument is empty.

Example filter expressions:

;; Accessing user must have an access level greater than  
;; or equal to that of the triple.  
(attribute>= user.access-level triple.access-level)  
 
;; Accessing user must be a member of all of the departments  
;; indicated by the triple.  
(attribute-contains-all-of user.department triple.department)  
 
;; Accessing user must be a member of at least one of the departments  
;; indicated by the triple.  
(attribute-contains-one-of user.department triple.department)  
 
;; Accessing user must have a sufficient access level and  
;; be a member of at least one of the triple's departments:  
(and  
 (attribute>= user.access-level triple.access-level)  
 (attribute-contains-one-of user.department triple.department)) 

Attributes example

There is a complete example of using attributes and a static filter in [AllegroGraph directory]/doc/java-tutorial/AttributesExample.java. Please look at the Java code for precise details. Here we will discuss the example in general.

The example defines three attributes: "securityLevel", "department" and "accessToken". The Java code defines these. Here are the details of their definitions:

Name: "securityLevel"  
Minimum number: 1  
Maximum number: 1  
Values: "low","medium","high"  
Ordered: Yes  
 
Name: "department"  
Values: "hr","devel","sales","accounting"  
Ordered: No  
 
Name: "acessToken"  
Values: "A","B","C","D","E""  
Ordered: No  

Because securityLevel has min and max 1, there must be exactly one of these attributes for every added triple.

We add a static filter. Again, see the Java code. Here is the filter expression:

(and (attribute>= user.securityLevel triple.securityLevel)  
     (attribute-contains-one-of user.department triple.department)  
     (attribute-contains-all-of user.accessToken triple.accessToken)) 

The filter requires that the user.securityLevel be greater than or equal to the triple security level, the user.department is in the list of triple departments, and the list of user.accessTokens contains all the triple accessTokens. Unless these conditions are met, the triple will be invisible to the user.

In the current implementation, individual users cannot be assigned attributes. A static filter can be defined for a repository but in order to use attributes to control which triples are visible, you must write a program which does its own authentication of the user and preparation of user attributes. The program then calls out to AllegroGraph, passing in the user's attributes, to get the visible triples.

In the future, we intend to allow attributes to be assigned to AllegroGraph users and roles. Then the AllegroGraph user can access the database directly, with the static filter comparing the user's attributes with the triple attributes and returning or not returning triples according to the filter.