The Sesame framework comes with a pre-packaged web service (often referred to as the Sesame server). This web service enables deployment of Sesame as an online RDF database server, with multiple SPARQL query endpoints and full update capabilities.

In the default setup of the Sesame server, however, there is no security at all: everybody can access all available Sesame repositories, can query them, add data, remove data, and even change the server configuration (e.g. creating new databases or removing existing ones). Clearly this is not a desirable setup for a server which is publicly accessible.

Fortunately, it is possible to restrict access to a Sesame server, using standard Java web application technology: the Deployment Descriptor.

In this recipe, we will look at setting up some basic security constraints for a Sesame server, using the web application’s deployment descriptor, in combination with basic HTTP authentication. For the purpose of this explanation, we assume you have a default Sesame server running on Apache Tomcat 6.

1. Sesame HTTP REST protocol

The Sesame server implements a RESTful protocol for HTTP communication (it’s a superset of SPARQL protocol). What that comes down to is that the protocol defines specific locations, reachable by a specific URL using a specific HTTP method (GET, POST, etc.), for each repository and each operation on a repository.

This is good news for our security, as it means we can easily reuse HTTP-based security restrictions: since each operation on a repository maps to a specific URL and a specific method, we can have fairly fine-grained access control by simply restricting access to particular URL patterns and/or HTTP methods.

If that sounds vague, here’s an example: suppose we have a Sesame server running at http://localhost:8080/openrdf-sesame. Retrieving statements from a repository on that server called ‘test’ is done using a HTTP GET operation on the URL http://localhost:8080/openrdf-sesame/repositories/test/statements. So if we want to restrict who can view the statements in that ‘test’ repository, all we have to do is define a security constraint on GET requests for that specific URL.

The following is an overview of the resources and HTTP methods that are available from a Sesame server (copied from section 8.1):

<SESAME_URL>
    /protocol             : protocol version (GET)
    /repositories         : overview of available repositories (GET)
        /<REP_ID>         : query evaluation on a repository (GET/POST)
            /statements   : repository statements (GET/POST/PUT/DELETE)
            /contexts     : context overview (GET)
            /size         : #statements in repository (GET)
            /namespaces   : overview of namespace definitions (GET/DELETE)
                /<PREFIX> : namespace-prefix definition (GET/PUT/DELETE)

In the REST protocol specification, you will find more detailed descriptions of what each URL and each HTTP method does, but for us right now, it is useful to know that read operations are always done via HTTP GET methods, and write operations are always POST, PUT or DELETE methods.

As said before, defining security constraints on URLs and HTTP methods can be done using deployment desciptors. In the next section, we will look at the Sesame deployment desciptor in more detail.

2. The deployment descriptor: web.xml

The deployment descriptor for the Sesame server is an XML file called web.xml. In a standard deployment, this file can be found in the directory [TOMCAT_DIR]/webapps/openrdf-sesame/WEB-INF.

As the name implies, the deployment descriptor configures how the Sesame server web application should be deployed. It contains several configuration settings that we will not touch here (such as mappings from URL patterns to servlets), but it can also contain security constraints, authentication config settings, and a collection of security roles that apply to the application.

3. Security roles

Security through Java deployment descriptors is role-based: rather than assigning permissions to specific user accounts, we define an abstract entity called a role, assign permissions to this role, and then (separately) make users members of a particular role. Typical roles are ‘Viewer’, ‘Editor’, ‘Admin’, and so on.

In this recipe, we are going to add three roles to our deployment descriptor:

  1. test-viewer – the role for users who have reading rights on the ‘test’ repository, that is, doing SPARQL queries, exporting statements, etc.
  2. test-editor – the role for users who have editing rights on the ‘test’ repository, that is, doing updates and removing data.
  3. sesame-admin – the role for users with administration rights, that is, users who can create new repositories, change configurations and remove old repositories.

Of course, this is just an example for illustration purposes: what roles you need to define for your application depends entirely on your use case. You may have roles that have access to one or more specific repositories, roles that have access to all repositories, roles that can only read, only write, and so on. Figuring out the optimal configuration for your application is up to you.

Back to our recipe: to add these roles, add the following snippet to the web.xml file (nested inside the web-app element – a good spot is somewhere after the last servlet-mapping element):

<security-role>
	<description>
		The role that is required for read access to the test repository
	</description>
	<role-name>test-viewer</role-name>
</security-role>
	<description>
		The role that is required for write access to the test repository
	</description>
	<role-name>test-editor</role-name>
</security-role>
<security-role>
	<description>
		The role that is required to change the Sesame server configuration
	</description>
	<role-name>sesame-admin</role-name>
</security-role>

By the way, some advice to avoid losing your work: do not edit the web.xml file while Tomcat is running, and make sure you keep a backup copy of your changes somewhere, in case the file accidentally gets overwritten with the default deployment descriptor (unlikely, but not impossible).

4. Authentication configuration

To enable basic HTTP authentication for the Sesame server, we add the following to our deployment descriptor:

<login-config>
	<auth-method>BASIC</auth-method>
	<realm-name>Sesame</realm-name>
</login-config>

Once we have set this up, we can start defining security constraints for our Sesame server.

5. Security constraints

A security constraint minimally consists of a collection of web resources (defined in terms of URL patterns and HTTP methods) and an authorization constraint (the role name that has access to the resource collection).

So, let’s have a look at what we need to do to restrict access. We have first of all defined a role ‘test-viewer’, that is, users who have read access to the test repository. Read access means access to operations such as SPARQL querying, as well as exporting statements, reading namespaces, contexts, and so on.

5.1. Defining read access: the test-viewer role

First, let us define a security constraint that allows viewers to do SPARQL queries. If we look at the summary of the Sesame REST protocol specification again we see that queries on a repository are always done via either GET or POST methods on the url pattern repositories/[REP_ID]. Since we are looking at defining a restriction for a repository with id ‘test’, the security constraint will look like this:

<security-constraint>
	<web-resource-collection>
		<web-resource-name>Sesame test repository: SPARQL query access</web-resource-name>
		<url-pattern>/repositories/test</url-pattern>
		<http-method>GET</http-method>
		<http-method>POST</http-method>
	</web-resource-collection>
	<auth-constraint>
		<role-name>test-viewer</role-name>
		<role-name>test-editor</role-name>
	</auth-constraint>
</security-constraint>

As you can see, the security constraint consists of two parts: the web-resource-collection, which defines on which URLs and HTTP methods the constraint applies, and the auth-constraint, which assigns the constraint to one or more roles.

The above constraint specifies that any authenticated user with the role ‘test-viewer’ or ‘test-editor’ may perform HTTP GET and POST operations on the URL http://localhost:8080/openrdf-sesame/test.

Hang on, didn’t I just say that read operations always correspond to GET methods? What is that POST method doing here then? This is the proverbial exception that confirms the rule. The exception is necessary because of practical considerations: some HTTP servers have limits on the length of parameter values for GET requests, so in order to avoid running into that limitation when doing large SPARQL queries, POST is also allowed.

Now, as said above, SPARQL querying is not the only kind of read access. The Sesame REST protocol defines several other read operations on a repository. In the summary we can see that we can do GET operations on various the URLs nested under /repositories/test, such as /statements, /size, /contexts, etc. However, we can also see that several of these patterns, for example /statements, also allow other methods, such as POST, PUT and DELETE. We want our viewer role to be able to perform read operations, but not write operations, so we define the following constraint:

<security-constraint>
	<web-resource-collection>
		<web-resource-name>Sesame test repository viewer access</web-resource-name>
		<url-pattern>/repositories/test/*</url-pattern>
		<http-method>GET</http-method>
	</web-resource-collection>
	<auth-constraint>
		<role-name>test-viewer</role-name>
		<role-name>test-editor</role-name>
	</auth-constraint>
</security-constraint>

In this case, we have restricted access to just the GET method (which captures all read operations), and as you can see, we are using a wildcard to capture all resource URL patterns that hang underneath our test repository.

Note, by the way, that at this point we have not yet defined any security constraints on write operations on the test repository. This means that right now, everybody can do write operations on it. We will fix that in the next section.

5.2. Defining write access: the test-editor role

The next set of security constraints should define who is allowed to have write access to the test repository. The role we have in mind for this is test-editor We have already given this role the same read access priviliges as the test-viewer role, but we need to specifically restrict write access to the repository as well, so that only users with this role can do write operations. This is very easily achieved with the following constraint:

<security-constraint>
	<web-resource-collection>
		<web-resource-name>Sesame test repository: editor write access</web-resource-name>
		<url-pattern>/repositories/test/*</url-pattern>
		<http-method>POST</http-method>
		<http-method>PUT</http-method>
		<http-method>DELETE</http-method>
	</web-resource-collection>
	<auth-constraint>
		<role-name>test-editor</role-name>
	</auth-constraint>
</security-constraint>

As you can see, full write access to the test repository is granted to the test-editor by simply assigning it to all URL patterns underneath ‘repositories/test/’ for the methods POST, PUT, and DELETE. We do not need to specify GET here, since we have already specified that method in another security constraint.

5.3. Creating repositories: the sesame-admin role

Finally, we are also going to set up a specific role for administration purposes, the sesame-admin role. This role should be allowed to manage the repositories on the server: creating new ones and deleting old ones.

Repository management on the Sesame server is done via a special repository called SYSTEM, so we can make sure only the sesame-admin role can manage repositories by restricting access to this repository:

<security-constraint>
	<web-resource-collection>
		<web-resource-name>Sesame System Config Restricted access</web-resource-name>
		<url-pattern>/repositories/SYSTEM/statements</url-pattern>
		<url-pattern>/repositories/SYSTEM/namespaces</url-pattern>
		<url-pattern>/repositories/SYSTEM/namespaces/*</url-pattern>
		<http-method>POST</http-method>
		<http-method>PUT</http-method>
		<http-method>DELETE</http-method>
	</web-resource-collection>
	<auth-constraint>
		<role-name>sesame-admin</role-name>
	</auth-constraint>
</security-constraint>

As you can see, we do not restrict read access to the SYSTEM repository, only write access. The reason is of course that many client tools for Sesame will want to be able to read the server configuration, so they know which repositories are available.

6. User accounts

We have now defined our security constraints and the roles to which we want to apply them. However, we have not yet assigned any user accounts to roles. In fact, we haven’t even defined any users yet. This is something that happens outside the deployment descriptor, and is left to the servlet container.

In Apache Tomcat, user accounts and password management are configured via something called a ‘Realm’. We will not go into too much details here on how to configure this, instead we refer you to the Apache Tomcat Realms HowTo.

However, in a default deployment of Apache Tomcat, a default Realm called UserDatabaseRealm is active. This realm is basically just a plain XML file, called tomcat-users.xml, and can be found in [TOMCAT_DIR]/conf/. You can create user accounts and assign them to roles by simply adding lines to this. For example, let’s say we want to create three user accounts john, paul and ringo. john should only have viewing access on the test repository, paul should be allowed to edit it, and ringo should be allowed to edit the test repository as well as do repository management tasks. We can achieve this by adding the following three lines to tomcat-users.xml:

<user username="john" password="letitbe" roles="test-viewer"/>
<user username="paul" password="heyjude" roles="test-editor"/>
<user username="ringo" password="yellowsub" roles="test-editor, sesame-admin"/>

As you can see, you can assign a user to more than one role. What is also immediately apparent is that this way of specifying user accounts is not particularly secure: the passwords are defined in plain-text. Using the default UserDatabaseRealm is very useful for quick testing and debugging of your security setup, but for production deployments I would strongly recommend looking into some of the more advanced Realm configurations that Apache Tomcat offers.

7. Conclusion and further reading

In this recipe I have shown how you can configure very basic repository-based security for a Sesame server. You will need to adapt, adopt and improve this basic recipe for your specific purposes: likely you will need different roles, different security constraints. You will probably also need to configure a more secure way of managing user accounts than what is shown here, and perhaps you will also need to use something more secure than basic HTTP authentication (for example, HTTPS Client-Cert authentication).

Some useful links for further reading on these topics:

Finally, I should point out one rather lamentable fact: the OpenRDF Workbench, which is the default web-based client tool for Sesame, currently has no support for basic HTTP authentication. Fortunately, other client tools, such as the Sesame Console and the Sesame Windows Client do support HTTP authentication, so you’re not completely on your own.

Leave a Reply