Introduction
You may wish to control what specific user can see in your database. AllegroGraphs has a number of tools for protecting triples from users not authorized to see them, working at different levels.
Permissions can be assigned either to individual users or to roles. The mechanisms are essentially the same both (a user assigned a role simply inherits the permissions of the role just as if the user was given those permissions directly). So in this document, we mostly discuss user permissions and provide examples of those. What we say can be applied to roles as well.
Triple access can be controlled by:
Restricting read or write or read/write access to specific catalogs or to specific individual repositories.
Restricting access to all triples with a specified subject, predicate, object, or graph or any such combination.
Assigning attributes to triples and to users so the user can be prevented from viewing triples with based on the triple's and the user's attribute values.
All these methods work, and provide the desired security.
General user permission settings for security
When a user (or role) is created, that user is assigned a set of permissions which control what the user can do. Some of these permissions might allow the user to override what is restricting their access. For example, obviously if the user is made a superuser (who can access and modify all user settings) that user is not bound by any restrictions. But other permissions can also allow access to all triples in not so obvious ways. Here is the dialog that defines a user, with the permissions that might allow overriding restrictions marked up. We advise not giving users such permissions unless you trust the user and understand the implications.
Every X'ed out choice must not be enabled if the user will be restricted from seeing all triples. The X'ed out items are:
- Superuser: Obviously!
- Evaluate arbitrary code: A user who can evaluate code and can figure out the internals of AllegroGraph can figure out how to remove restrictions.
- Allow user attributes via SPARQL PREFIX franzOption_userAttributes: if attributes are used for triple security (as we describe below), a user who can specify that prefix can overwrite the prefix applied by the system.
- Allow user attributes via HTTP header: same as just above, but with the REST interface.
Some users on the machine running AllegroGraph server have effective superuser rights
The agtool program, when it is given a server spec where the server is localhost
or 127.1
or even the server name (like foo.com
if that dns resolves to the server machine) can bypass the HTTP interface to run the command and instead goes right through the hub into the service daemon (if that is supported by the command it needs to execute) and it will do so if the user calling agtool is the user with the same user id as the AllegroGraph server. That allows that user to modify user permissions and make themselves AllegroGraph superusers, like this (Jane_Smith is a user in the attributes example below):
% agtool users permissions --server localhost:10035 Jane_Smith super+
This does not work when run on a different machine (running on machine2.com while the AllegroGraph server is machine1.com):
% agtool users permissions --server machine1.com:10035 Jane_Smith super+
An error occured when trying to send http request to AllegroGraph server at http://machine1com:10035
No anonymous access allowed.
%
This access is unlikely to actually cause problems as typically the AllegroGraph server is run either by the special agraph
user or by someone with AllegroGraph superuser rights anyway.
Restricting access to an entire catalog or repo
When a new user is created, they do not have read or write permission in any catalog or repository. Such permissions are created (by the superusers adminstrator who set up the user's account) in this portion of the user setup dialog (the image is from the New Webview):
You can specify the catalog/repos that the user can access and then the user cannot access others.
The access rules are simple: you can allow access to a particular repos in a catalog, all repos in a catalog or no repos in catalog. Suppose a catalog has 20 repos, and you want user22 to have r/w access to 19 but not to the 20th. Then you have to list all 19 to allow access to them, leaving out the 20th to prevent access. (There is no way to simply deny access to a single repo.)
This works best if you organize repos into catalogs based on desired access. Consider three catalogs: root, admin, management. Every user can be given access to root; managers and administrators to admin, and managers only to management.
Restricting access triples based on subject, obejct, predicate, or graph
Lower down on the same dialog which gives access to specific catalogs and repos is this portion:
This allows setting access permission based on values of the subject, predicate, object, or graph value. For example, if the database has triples that show people's salaries, access can be restricted in this way:
(This would likely be set for roles, with the higher-management role having access and all other employment-level roles disallowed access.)
This security method works best for fairly simple security schemes where classes of users are easily categorized into a few sets that can or cannot see a few things (where things means all triples with this predicate or that subject).
If the graph is not used for any other purpose, it can provide secuity at the triple level, assigning distinctive graph values for triples that groups can or cannot see, but if access gets at all complex, you need too many graph values and too many security value entries to make conveniently. And the graph slot is rarely available for a single purpose.
Restricting access triples based on attributes
Finally, you can use attribute for triple security. AllegroGraph has long support triple-level security using triple attributes but until release 8.0.0 it was necessary to have queries managed by an external program which would take a query, examine the user attributes which the external program maintained, and construct a suitable query prefix with would filter the query results based on the triple attributes stored by AllegroGraph and the user attribute values known to the external program, filtering the results using a stored static filter associated with the repo. This was (and is) an effective system from triple security but needing an external controlling program which placed a burden on users and administrators.
That system has now been moved into AllegroGraph. There are now per-repo user-specific attributes which can be used with repo-specific attributes to filter query results so the user will only see appropriate triples. User attributes can be set in various ways, the easiest being with agtool define-attribute.
This method is by far the most powerful and the most flexible. Almost any security scheme you can think of can be implemented. Because it depends on filters of arbitrary complexity, which can be changed at any time; on user attributes, which too can be changed at any time; and triple attributes (which are admittedly harder to change but can be changed), you are provided with very fine control over what triples can be accesed and by whom.
We will describe triple security using attributes in detail in the remainder of this document.
Triple security using attributes introduction
Triple attributes are described in the Triple Attributes document. They have many uses aside from security and no one use interferes with other uses (unlike, say, using the graph for security suggested above).
Attributes can be assigned to triples (when the triple is loaded), to users and roles (at any time by a superuser administrator). User attributes are on a per-repo basis (triple attributes are obviously per repo as triples exist in only one repo). There can also be a repo static filter (again defined by a superuser administrator and modifiable at any time). When a user tries to access a triple, the system compares the user's attributes with the triple's attributes using the static filter and grants access or denies it beased on the results. ("Denies access" means that from the user's point of view, the triple does not exist. The user is not informed that they have been denied access.)
Attributes must be defined before they can be assigned to a triple or a user. Triples can only be assigned attribute values when they are created. If the attributes of a triple need to be changed, the triple must be written out, deleted, and reloaded. As said above, user attributes can be assigned at any time. See Data Import for information on specifying attributes in nqx files (NQuad files including attributes).
See the agtool General Command Utility document for information on defining attributes with agtool and assigning them to users. Attributes and static filters can also be defined from menus in New WebView and Traditional WebView.
Attribute definitions (that is, name, type, and possible values) and static filters are attributes of repos. Every repo can have it own set of attributes and excepting Multimaster replication and FedShard (tm), repos do not inherit attribute or static filter values from other repos.
A triple security example
Suppose we have a single repo and we have these attributes defined:
employee-type
with values:science
,admin
,manager
science-level
with ordered values:1
,2
,3
admin-level
with ordered values:1
,2
,3
At first our desired rules are (we do not use ordering at first):
- Everyone can see any triple with (
science-level 1
) or (admin-level 1
). - Admin employees (administrators) can see any admin-level triple.
- Science employees can see any science-level triple.
- Managers can see every triple.
There are 5 users:
- Jane_Smith is a manager
- Bill_Jones is a scientist
- Bobby_Smith is an intern
- Fred_Hernandez is an administrator
- Vijay_Singh is both an administrator and a scientist
We have a company
repo.
Here are the attribute definitions:
% agtool define-attribute --allowed-values 1,2,3 --ordered true \
--maximum-number 1 super:pass@myhost:10035/company science-level
% agtool define-attribute --allowed-values 1,2,3 --ordered true \
--maximum-number 1 super:pass@myhost:10035/company admin-level
% agtool define-attribute --allowed-values science,admin,manager \
--minimum-number 1 super:pass@myhost:10035/company employee-type
And here is the NQX file
<http://www.company.com/Jane_Smith> <http://www.company.com/salary> "100000" {"admin-level": "3"} .
<http://www.company.com/Fred_Hernandez> <http://www.company.com/position> "Accountant" {"admin-level": "1"} .
<http://www.company.com/Vijay_Singh> <http://www.company.com/position> "SA" {"admin-level": "1"} .
<http://www.company.com/Vijay_Singh> <http://www.company.com/position> "Chemist" {"admin-level": "1"} .
<http://www.company.com/water> <http://www.company.com/isa> <http://www.company.com/liquid> {"science-level": "1"} .
<http://www.company.com/secret-sauce> <http://www.company.com/made-from> <http://www.company.com/mulberry> {"science-level": "3"} .
<http://www.company.com/special-additive> <http://www.company.com/made-from> <http://www.company.com/calcium> {"science-level": "4"} .
Now we give attribute values to our users (only a superuser can set the attributes for a user):
% agtool users set-attributes --server super:pass@host:10035 Jane_Smith :company '{"employee-type": "manager"}'
done
% agtool users set-attributes --server super:pass@host:10035 Fred_Hernandez :company '{"employee-type": "admin"}'
done
% agtool users set-attributes --server super:pass@host:10035 Vijay_Singh :company '{"employee-type": ["science","admin"]}'
done
% agtool users set-attributes --server super:pass@host:10035 Bill_Jones :company '{"employee-type": "science"}'
done
%
Note that Bobby_Smith did not get any attribute values.
Finally we set a static filter:
(or (equal triple.admin-level "1") (equal triple.science-level "1") (equal user.employee-type "manager") (and (or (equal triple.science-level "1") (equal triple.science-level "2") (equal triple.science-level "3")) (subset "science" user.employee-type)) (and (attribute-contains-one-of ("1" "2" "3") triple.admin-level) (subset "admin" user.employee-type)))
Now let us see who can see what:
Bill Jones can see
Fred_Hernandez position "Accountant"
Vijay_Singh position "SA"
Vijay_Singh position "Chemist"
water isa liquid
secret-sauce made-from mulberry
Vijay Singh sees all of those (because he is in science
) and also
Jane_Smith salary "100000"
because he is also in admin
. Jane Smith also sees all those because she is a maneger. Fred Hernadez does not see the secret-sauce
triple but does see Jane Smith's salary
. Finally, Bobby Smith see these (any user can see those):
Fred_Hernandez position "Accountant"
Vijay_Singh position "SA"
Vijay_Singh position "Chemist"
water isa liquid
Triples without attributes
We add the following triple to company
:
<http://www.company.com/company> <http://www.company.com/hq> "California"
So who can see that triple? It has no attributes to compare so you might think everyone, but in fact, only Jane_Smith can see it (a user with employee-type
"manager" can see every triple. But the rest of the rules compare the triple attributes with user attributes and the comparicon fails because the triple does not have any attributes.
If you want all users to see all triples without attributes, add this to the security filter (after the or
):
(empty triple.security-level)
Attributes and SPARQL INSERT
You typically assign attributes at load time or when a triple is added using the WebView interface. Attributes must be specified when a triple is added. Here are the current triples in the repo:
s p o attributes
data1 pred 22 {"att1": "yes"}
data2 pred 44 {"att2": "yes"}
Triples can be added during a SPARQL INSERT operation. Here is a SPARQL INSERT command:
Here is a simple INSERT query:
insert {
?s <www.franz.com/newpred> ?o . }
where {
?s <www.franz.com/pred> ?o }
That will insert two new triples
data1 newpred 22
data2 newpred 44
but those triples will not have attributes.
This is a problem if you want to protect the new triples similarly to the triples they we created from. You can however cause the new triples to get the same attributes as the triples which caused them to be inserted with the following revised SPARQL INSERT query:
PREFIX attr: <http://franz.com/ns/allegrograph/6.2.0/>
INSERT {
attribute ?attr { ?s <www.franz.com/newpred> ?o . }
} WHERE {
?attr attr:attributes (?s <www.franz.com/pred> ?o )
results in
s p o attributes
data01 pred 22 {"att1": "yes"}
data02 pred 44 {"att2": "yes"}
data02 newpred 44 {"att2": "yes"}
data01 newpred 22 {"att1": "yes"}