Skip to content

feature: support ODRL to configure authorisation policies#12

Draft
mirdono wants to merge 22 commits into
masterfrom
feature/odrl-configuration
Draft

feature: support ODRL to configure authorisation policies#12
mirdono wants to merge 22 commits into
masterfrom
feature/odrl-configuration

Conversation

@mirdono
Copy link
Copy Markdown
Collaborator

@mirdono mirdono commented Mar 31, 2026

Note

This functionality is being tested in the DECIDe project. I marked the PR as
draft until it has seem more mileage.

Add initial functionality to support specifying authorisation policies using
ODRL (with some SHACL), as an option next to the existing lisp ACL.

Approach

Specifying authorisation policies using ODRL and SHACL

The following table contains an overview of how the different elements in
sparql-parser's ACL are expressed using ODRL and SHACL. A more detailed
description can be found in the README's how-guide on ODRL and on the
gitbook of the DECIDe project.

ACL ODRL/SHACL
access ODRL Party collection
graph ODRL Asset collection
type-specification ODRL Asset and SHACL node shape with property shapes
grant ODRL Permission

An ODRL Party collection can be linked to a query (and parameters) in which
case it would correspond to an access-by-query, otherwise it corresponds to
always-accessible. It is currently not supported to influence this mapping
using constraints.

For example, take the following access-by-group for authenticated users:

(supply-allowed-group "authenticated"
  :parameters ("account")
  :query "PREFIX session: <http://mu.semte.ch/vocabularies/session/>
      SELECT DISTINCT ?account WHERE {
      <SESSION_ID> session:account ?account.
      }")

would correspond to the following ODRL Party collection:

@prefix dct: <http://purl.org/dc/terms/> .
@prefix ext: <http://mu.semte.ch/vocabularies/ext/> .
@prefix odrl: <http://www.w3.org/ns/odrl/2/> .
@prefix vcard: <http://www.w3.org/2006/vcard/ns#> .

ext:authenticatedParty a odrl:PartyCollection ;
  vcard:fn "autenticated" ;
  ext:queryParameters "account" ;
  ext:definedBy """PREFIX session: <http://mu.semte.ch/vocabularies/session/>
  SELECT DISTINCT ?account
  WHERE {
    <SESSION_ID> session:account ?account .
  }""" ;
  dct:description "This represents all logged in users of the system." .

An ODRL Asset collection describes a set of triples in a graph. Therefore,
we opted to use SHACL shapes instead of ODRL constraints to capture
type-specifications, as the former is specifically intended to express that
kind of information. ODRL constraints on the other hand are not suitable here.
A SHACL node shape (ODRL Asset) specifies a resource type as sh:targetClass
and can contain property shapes to further refine for specific predicates. For
example, a graph-specification such as

(define-graph some-graph ("http://mu.semte.ch/graphs/someGraph")
    (typeOne -> predOne
             <- predTwo))

would correspond to the following ODRL Asset collection and SHACL node shape:

@prefix ext: <http://mu.semte.ch/vocabularies/ext/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix odrl: <http://www.w3.org/ns/odrl/2/> .
@prefix vcard: <http://www.w3.org/2006/vcard/ns#> .

ext:someCollection a odrl:AssetCollection ;
    vcard:fn "some-graph" ;
    ext:graphPrefix <http://mu.semte.ch/graphs/someGraph> .

ext:someShape a odrl:Asset , sh:NodeShape ;
  odrl:partOf ext:someCollection ;
  sh:targetClass typeOne ;
  sh:property [
    sh:path predOne
  ] , [
    sh:path [ sh:inversePath predTwo ]
  ] .

An ODRL Permission grants members of party collection a given action on an asset collection. Similar to what a grant does.

For example, the following grant:

(grant (read)
       :to-graph some-graph
       :for-allowed-group "authenticated")

corresponds to the following ODRL Permission

@prefix ext: <http://mu.semte.ch/vocabularies/ext/> .
@prefix odrl: <http://www.w3.org/ns/odrl/2/> .

ext:someGraphReadPermission a odrl:Permission ;
  odrl:action odrl:read ;
  odrl:target ext:someGraph ;
  odrl:assignee ext:authenticatedParty .

Note, scopes can be defined using the ext:scope property for Permissions. This will essentially act the same as the :scopes keyword argument for grants.

ODRL model implementation

The ODRL/SHACL model explained above is implemented as a set of classes in
odrl.lisp and shacl.lisp. This allows
to internally instantiate ODRL policies read from a configuration file as well
as convert ODRL model instances to the ACL sparql-parser uses. Having this
intermediate representation should allow that the functionality to convert it to
the internal ACL can evolve independently from the functionality parsing the
input configuration file. For example, supporting another file format only
requires to implement functionality to instantiate an ODRL model from that format.

The model implementations only cover the parts of the ODRL and SHACL
specifications that are necessary to express authorisation policies. For
example, no support for ODRL offers or constraints is implemented. Furthermore,
the implemented ODRL model deviates from the specification in two ways. First,
in our implementation rules can specify multiple actions, whereas ODRL only
allows a single action1. This allows to "merge" rules that map to a single
grant thereby simplifying the actual conversion. Second, asset collections
reference their contained assets, whereas in the ODRL specification it is assets
that link to the collections they are part of via the odrl:partOf
predicate. This inversion allows to pass over all elements in a policy in a
top-down fashion, instead of having to keep track of all available assets
separately.

Conversion to ACL

Converting an ODRL model instance to the internal ACL is implemented using
generic functions, odrl-to-acl and shacl-to-acl, and their method
implementations. In summary this conversion starts from an ODRL rule-set and
passes over each contained element to convert them to their corresponding ACL
element.

Note, as the conversion starts from the rules in a policy, only party (asset)
collections that are used in at least 1 rule are converted. This is different
from configurations in lisp, where each specified access and graph is
evaluated irrelevant of whether there is a grant using it.

Input file parsing

As input a ttl file is expected, this file is read and parsed by the
functionality in parse-ttl. The load-policy-file
function reads input file and parses the content using
cl-ttl-parser. The result is a list of
lists, with each inner list representing a triple. The make-rule-set function
converts these triples to their corresponding ODRL or SHACL objects.

Open issues

ODRL policies do not yet support all features available through the lisp ACL:

  • It is not possible to explicitly specify a constraint for a party collection,
    as can be done for allowed-groups in the acl:supply-allowed-group
    macro. Consequently, the type of acl:access that will be created for each
    party collection is determined by the presence or absence of a query. It is
    thus not possible to specify a NEVER constraint, or force the creation of an
    acl:always-accessible instance despite the presence of a query.

  • Asset Collections do not support setting options on a per instance basis. Each
    Asset Collection will be translated to an acl::graph-specification with
    generate-delta-p and generate-sparql-p set to t.

  • ODRL's policy rule composition is not supported at the ttl configuration level. Adding support for this would allow to specify configurations in a slightly more condensed manner. For example, one would not have to define 2 separate rules to grant read and write rights.

Notes

  • The implementation is adapted from the
    odrl-parser-service which
    served as PoC to show the feasibility of expressing semantic.works
    authorisation in ODRL.

Related tickets

  • LBRON-719
  • LBRON-1060

Footnotes

  1. Policy rule composition is currently not supported for specifying ODRL authorisation policies.

mirdono and others added 22 commits May 12, 2026 11:51
Define simplified models for ODRL and SHACL using classes. These models only
cover the parts of the respective specifications that we need to express
authorisation policies in ODRL(+SHACL).

These models facilitate an internal representation of an ODRL policy that can
serve as an intermediary between the raw input (e.g. ODRL policy in ttl file)
and the ACL used internally by this service.
- Parse the contents of a n-triples files using `cl-ntriples`
- Convert each relevant resource to its corresponding ODRL/SHACL object. The
  `make-rule-set` function is used as the entrypoint for this conversion.
- Triples in the input that are not relevant for model instances are simply
  ignored.
- Add `./odrl/config.{nt,ttl}` as example for testing purposes.
An ODRL Set is loaded as ACL by iterating over its contained rules:
1. Each Party (Asset) Collection referenced in a rule is converted into a
   corresponding allowed-group (graph-specification). Consequently, collections
   that are not used in any rule are ignored.
2. The set of rules in the policy are "reduced" by merging rules that have the
   same assignee and target. Any merged rule has as actions the union of its
   original rules. Note, this step is necessary because ODRL only allows 1
   action per rule, whereas grants can specify multiple actions.
3. Convert the reduced rules into grants.
- Split the actual assertions to a separate function so they can be reused in
  multiple scenarios.
- Added specific functions to run the assertion tests with either ACL or ODRL
  config to allow testing these flows independently.
- Let `run-assertion-tests` execute the scenario twice, first with an ACL config
  and second with the same config in ODRL.
- Removed previous example configs in favour of config used in test scenarios
- Ensure any n-triples configuration is copied from the mounted config volume.
- Conditionally load policy from n-triples file if
  `odrl-config::*use-odrl-config-p*` is set to a non-nil value.
- The original lisp config confi is still evaluated as before to allow using to
  configure the service by setting parameters/variables. But loading an ODRL
  config first clears the ACL variables to remove any policy elements that would
  be defined in the lisp config.
This is a workaround to add the `cl-ttl-parser` as package dependency until it
is published via quicklisp.
Previously, multiple values for `ext:queryParameters` were just provided as
multiple triples. But since the order is important for sparql-parser this leads
to unpredictable behaviour.

This resolves that by supporting Turtle collections to specify multiple
values. The ttl parser will convert such a collection to an RDF
list. Sparql-parser in turn parses the triples in the RDF list to a lisp list.
Signal an error when a mandatory slot receives no (valid) value upon creating an
ODRL/SHACL object. Otherwise, missing or incorrect values would lead to
unpredictable errors during conversion to ACL.
Extend ODRL rules with a `scopes` slot that allows to provide 0..* strings as
scopes for a rule.
@mirdono mirdono force-pushed the feature/odrl-configuration branch from 8512ccd to 00397af Compare May 12, 2026 09:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant