VAL ACL Usage Examples

VAL ACL Usage Examples

Table of Contents

Basic ACL Configuration

Identifying User ServiceID/NetworkID (NetID)

Before setting up ACLs, determine the ServiceID (also known as NetworkID or NetID) or Web Identity (WebID) by authenticating to the Virtuoso Structured Protocol And RDF Query Language (SPARQL) endpoint and hovering over the hyperlinked user account:

Or the following SPARQL query can be used to obtain the ServiceID of the authenticated user:

SELECT bif:connection_get('NetId') {}

Initial Graph Setup

  1. Add the target graph to Virtuoso Private Graph:
DB.DBA.RDF_GRAPH_GROUP_INS('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs','http://example.org');
  1. Verify that access is initially restricted, by attempted to perform a SPARQL insert query as an authenticated user:

Creating Basic ACL Rules

  1. Clear existing ACL cache:
VAL.DBA.clear_graph_acl_cache();
  1. Set up SPARQL endpoint access:
SPARQL
PREFIX acl: <http://www.w3.org/ns/auth/acl#>
PREFIX oplacl: <http://www.openlinksw.com/ontology/acl#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

WITH <http://{CNAME}/acl/graph/rules/http%3A%2F%2Fwww.openlinksw.com%2Fontology%2Facl%23DefaultRealm>
INSERT {
  <#NetIDReadAccessRule1>  
    a acl:Authorization ;
    rdfs:label "Read & Write Access Authorization for named NetIDs" ;
    acl:accessTo <urn:virtuoso:access:sparql> ;
    oplacl:hasAccessMode oplacl:Read, oplacl:Write ;
    acl:agent  {NetID} ;
    oplacl:hasRealm oplacl:DefaultRealm ;
    oplacl:hasScope oplacl:Query .
}
  1. Configure graph-specific access:
SPARQL
PREFIX oplacl: <http://www.openlinksw.com/ontology/acl#>
PREFIX acl: <http://www.w3.org/ns/auth/acl#>

WITH <http://{CNAME}/acl/graph/rules/http%3A%2F%2Fwww.openlinksw.com%2Fontology%2Facl%23DefaultRealm>
INSERT {
  <#HttpTLSPrivateNamedGraphRule1>  
    a acl:Authorization ;
    rdfs:label "Private Named Graph ACL" ;
    oplacl:hasAccessMode oplacl:Read, oplacl:Write ;
    acl:accessTo <http://example.org> ;
    acl:agent {NetID} ;
    oplacl:hasScope oplacl:PrivateGraphs ;
    oplacl:hasRealm oplacl:DefaultRealm .
}
  1. Verify successful access to graph with SPARQL insert query:

Group-Based ACL Rules

Creating Groups

  1. Create a basic static group with explicit members:
SPARQL
PREFIX acl: <http://www.w3.org/ns/auth/acl#>
PREFIX oplacl: <http://www.openlinksw.com/ontology/acl#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

WITH <http://{CNAME}/acl/graph/groups/http%3A%2F%2Fwww.openlinksw.com%2Fontology%2Facl%23DefaultRealm>
DELETE 
{ 
 <#groupBasicNetID> ?p ?o. 
} 
WHERE
{
 <#groupBasicNetID> ?p ?o. 
}
INSERT
{
  <#groupBasicNetID> a foaf:Group, oplacl:StaticGroup ;
      rdfs:label "Basic NetID Group" ;
      rdfs:comment "This ACL group contains explicitly listed NetIDs" ;
      foaf:maker <https://my.openlinksw.com/dataspace/person/hwilliams@openlinksw.com#this> ;
      foaf:member {NetID1, ... NetIDn} .
}
;
  1. Create a conditional group based on NetID pattern matching (for Google NetIDs for example):
SPARQL
PREFIX acl: <http://www.w3.org/ns/auth/acl#>
PREFIX oplacl: <http://www.openlinksw.com/ontology/acl#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

WITH <http://{CNAME}/acl/graph/groups/http%3A%2F%2Fwww.openlinksw.com%2Fontology%2Facl%23DefaultRealm>
DELETE 
{ 
 <#groupBasicGoogleNetID> ?p ?o. 
} 
WHERE
{
 <#groupBasicGoogleNetID> ?p ?o. 
}
INSERT
{
  <#groupBasicGoogleNetID> rdf:type  oplacl:ConditionalGroup ;
      rdfs:label "Google Group NetID" ;
      rdfs:comment "This ACL group is for ANY Google users NetID access" ;
      foaf:maker <https://my.openlinksw.com/dataspace/person/hwilliams@openlinksw.com#this> ; 
      oplacl:hasCondition [
         rdf:type oplacl:GroupCondition, oplacl:GenericCondition ;
         oplacl:hasCriteria  oplacl:NetID ;
         oplacl:hasComparator oplacl:Regexp ;
         oplacl:hasValue     "https://plus.google.com/.*" 
      ] .
}
;

Exclusion Group with ASK Query

  1. Create the exclusion group:
SPARQL
PREFIX acl: <http://www.w3.org/ns/auth/acl#>
PREFIX oplacl: <http://www.openlinksw.com/ontology/acl#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

WITH <http://{CNAME}/acl/graph/groups/http%3A%2F%2Fwww.openlinksw.com%2Fontology%2Facl%23DefaultRealm>
INSERT {
 <#exclusionGroup> a foaf:Group, oplacl:StaticGroup ;
  foaf:maker <http://{CNAME}/dataspace/person/dba#this> ;
  foaf:name "Exclusion Group Members" ;
  foaf:member {NetID1, ... NetIDn} .
}
  1. Create conditional rule with ASK query:
SPARQL
PREFIX oplacl: <http://www.openlinksw.com/ontology/acl#>
PREFIX acl: <http://www.w3.org/ns/auth/acl#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

WITH <http://hfw.openlinksw.com:8890/acl/graph/rules/http%3A%2F%2Fwww.openlinksw.com%2Fontology%2Facl%23DefaultRealm>
INSERT {
  <#exclusionConditionalGroup> a oplacl:ConditionalGroup ;
  foaf:maker <http://{CNAME}/dataspace/person/dba#this> ;
  foaf:name "Exclusion List Conditional ACL" ;
  oplacl:hasCondition [
    a oplacl:GroupCondition, oplacl:QueryCondition ;
    oplacl:hasQuery "ASK WHERE { <#exclusionGroup> a foaf:Group . FILTER ( NOT EXISTS { <#exclusionGroup> foaf:member ^{uri}^ . } ) . }"
  ] .
}
  1. Apply conditional ASK query rule to restrict access to resources
SPARQL
PREFIX  oplacl:  <http://www.openlinksw.com/ontology/acl#>
PREFIX     acl:  <http://www.w3.org/ns/auth/acl#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

WITH
<http://{CNAME}/acl/graph/rules/http%3A%2F%2Fwww.openlinksw.com%2Fontology%2Facl%23DefaultRealm>
DELETE 
{
 <#HttpTLSPrivateNamedGraphRule1> ?p ?o. 
} 
WHERE
{
 <#HttpTLSPrivateNamedGraphRule1> ?p ?o. 
}
INSERT
{
 <#HttpTLSPrivateNamedGraphRule1>  
   a  acl:Authorization ;
   rdfs:label "Private Named Graph ACL (HTTP Realm) for Named Graph Identified by IRI: <http://example.org>" ;
   foaf:maker <http://{CNAME}/dataspace/person/dba#this> ;
   oplacl:hasAccessMode  oplacl:Read, oplacl:Write ;
   acl:accessTo <http://example.org> ;
   acl:agent <#exclusionConditionalGroup> ; 
   oplacl:hasScope  oplacl:PrivateGraphs ;
   oplacl:hasRealm  oplacl:DefaultRealm .
} ;

Points of note when creating such ASK query ACLs:

  • The ACL rule owner must have admin privileges in the database to perform such ASK queries ie foaf:maker <http://{cname}/dataspace/person/dba#this>
  • The ASK query should check <group> foaf:member <x>, drop <x> a ?t, instead add a foaf:Group , because not every NetID is sponged or has rdf:type set. For example RMA does not have physical RDF triples for rdf:type.

Programmatic Authentication

Identity Provider (IdP) Application Access as “dba” user

  1. Create VAL application via OAuth 2.0 Authorization Framework (OAuth2) applications page https://{cname}//oauth/applications.vsp.

  1. Enable the Allow Client Credentials Grant option and save credentials.

Identity Provider (IdP) Application Access as Remote IdP NetID

For a remote IdP NetID user account, a special VAL ACL needs to be created to allow the NetID(s) access to the VAL application via OAuth 2.0 Authorization Framework (OAuth2) applications page https://{cname}/oauth/applications.vsp (enable Client Credentials Grant), to enable a VAL application owned by it to be created for use in generating a bearer token from the client id and secret.

  1. Create ACL rule for applications page access:
SPARQL
PREFIX acl: <http://www.w3.org/ns/auth/acl#>
PREFIX oplacl: <http://www.openlinksw.com/ontology/acl#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX oplres: <http://www.openlinksw.com/ontology/restrictions#>

WITH <$U{RULES}>
INSERT {
  <#rulePublicApps> a acl:Authorization ;
            foaf:maker <#dba> ;
            oplacl:hasAccessMode oplacl:Read, oplacl:Write ;
            oplacl:hasScope oplacl:OAuth;
            acl:accessTo <urn:virtuoso:access:oauth:apps> ;
            acl:agent <#groupNetID> ;
            oplacl:hasRealm oplacl:DefaultRealm .
}
  1. Create VAL application for NetID user:

  1. Generate client id and secret credentials:

Bearer Token Authentication

  1. Generate bearer token from the client id and secret generated in one of the two methods previously:
curl --request POST \
     --data "client_id=$CLIENT_ID&client_secret=$CLI_SECRET&redirect_uri=http://127.0.0.1&grant_type=client_credentials" \
     https://{cname}/OAuth2/token
  1. Use token for SPARQL queries:
curl -H "Authorization: Bearer <bearer-token-value>" \
     --request POST "https://{cname}/sparql/?" \
     --data-urlencode "format=csv" \
     --data-urlencode "query=<sparql-query>"
  1. Refresh expired tokens:
curl -X POST https://{cname}/OAuth2/token \
     -d "grant_type=refresh_token" \
     -d "refresh_token=<refresh-token-value>" \
     -d "client_id=<client-id-value>" \
     -d "client_secret=<client-secret-value>"

SSO and DPoP Authentication Examples

Single Page Application (SPA) Authentication

Initial Setup

The git Data-Entry-Form-AuthV2 SPA uses the Solid Client Library which issues SPARQL INSERT requests using the client-supplied authenticated-fetch routine. The latter sends POST requests to a ~/sparql endpoint which includes a DPoP-bound access token. The test uses DPoP tokens obtained from an issuer on an another host to the target SPARQL endpoint.

  1. Clone the git repo under the ~/vsp folder for your Virtuoso installation to make it accessing from the hosted Virtuoso instance:
cd <vsp folder>
git clone https://github.com/OpenLinkSoftware/Data-Entry-Form-AuthV2.git SPA
cd SPA
git checkout develop
  1. Access the SPA interface at https://{cname}/SPA/index.html:

  1. Select authentication method from list available. Or the URL of the OIDC/OAuth2 server can be provided which can be another or the same Virtuoso instance ie https://{cname} for example or another 3rd Party OIDC server :

  1. Complete authorization:

Data Entry Form Example

  1. Set up ACLs for accessing private graph called urn:private_graph.20231012_val_write_perm_checks:
-- Create and populate a private graph
DB.DBA.RDF_GRAPH_GROUP_INS ('http://www.openlinksw.com/schemas/virtrdf#PrivateGraphs','urn:private_graph.20231012_val_write_perm_checks');

SPARQL CLEAR GRAPH <urn:private_graph.20231012_val_write_perm_checks>;
SPARQL INSERT INTO GRAPH <urn:private_graph.20231012_val_write_perm_checks> { <urn:s1> <urn:p1> <urn:o1> };

-- Setup ACL for read access
SPARQL
PREFIX oplacl: <http://www.openlinksw.com/ontology/acl#>
PREFIX acl: <http://www.w3.org/ns/auth/acl#>

WITH <http://{CNAME}/acl/graph/rules/http%3A%2F%2Fwww.openlinksw.com%2Fontology%2Facl%23DefaultRealm>
INSERT {
  <#AclRdefaultSprivategraphsMrTtestgraph1>  
    a acl:Authorization ;
    rdfs:label "ACL (default realm) for private graph" ;
    foaf:maker <urn:id:cblakeley> ;
    oplacl:hasRealm oplacl:DefaultRealm ;
    oplacl:hasScope oplacl:PrivateGraphs ;
    acl:accessTo <urn:private_graph.20231012_val_write_perm_checks> ;
    oplacl:hasAccessMode oplacl:Read ;
    acl:agent {NetID} .
}
;

-- Setup ACL for write access  
SPARQL
PREFIX oplacl: <http://www.openlinksw.com/ontology/acl#>
PREFIX acl: <http://www.w3.org/ns/auth/acl#>

WITH <http://{CNAME}/acl/graph/rules/http%3A%2F%2Fwww.openlinksw.com%2Fontology%2Facl%23DefaultRealm>
INSERT {
  <#AclRdefaultSprivategraphsMwTtestgraph6>  
    a acl:Authorization ;
    rdfs:label "ACL (default realm) for private graph" ;
    foaf:maker <urn:id:cblakeley> ;
    oplacl:hasRealm oplacl:DefaultRealm ;
    oplacl:hasScope oplacl:PrivateGraphs ;
    acl:accessTo <urn:private_graph.20231012_val_write_perm_checks> ;
    oplacl:hasAccessMode oplacl:Write ;
    acl:agent {NetID} .
}
;
  1. Temporarily disable graph caching with the SQL command:
__dbf_set ('enable_g_in_sec', 0);
  1. Change Document Name value to the target graph urn:private_graph.20231012_val_write_perm_checks:

  1. View existing data by clicking on the All Data button:

  1. Add new triple data entering the Subject, Predicate, Object values and click the Add button:

  1. Verify the triple is added by clicking on the All Data button:

Script-Based VAL DPoP SSO Authentication

This example demonstrates how to perform VAL SSO authentication using a DPoP JWT token generated from application client credentials.

  1. Create a VAL application for a local or remote IdP account via https://{cname}/oauth/applications.vsp UI.

  2. Download and configure the script:

    • Unzip dpop_jwt_ec.zip
    • Edit dpop_jwt_ec.sh and set:
      HOST="hostname of VAL auth server"
      CLIENT_ID="your client id"
      CLIENT_SECRET="your client secret" 
      sparql_url="VAL SPARQL endpoint"
      
  3. Run the script:

bash dpop_jwt_ec.sh
  1. Example output:
DPoP: [eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6ICJFUzI1NiIsImp3ayI6...]
Token: DPoP eyJ0eXAiOiJEUG9QIiwia3R5IjoiUlNBIiwiYWxnIjoiUlMyNTYi...]

SPARQL Endpoint: [https://linkeddata.uriburner.com/sparql]

NetID: [select bif:connection_get('NetId') { }]
"callret-0"
"https://plus.google.com/111873902418933186900#this"

select * where {?s ?p ?o} limit 5
"s","p","o"
"http://dbpedia.org/resource/Maahes","http://dbpedia.org/property/cultCenter","http://dbpedia.org/resource/Taremu"
...

Note:

  • When using remote SPARQL endpoints, proper CORS configuration is required to prevent authentication failures.
  • The SPA uses Solid Client Library for SPARQL operations with Cross-Origin Resource Sharing (CORS) and DPoP authentication.
  • Authentication headers can be inspected in the browser developer tools:

Header format:

Authorization: DPoP eyJ0eXAiOiJEUG9QIiwia3R5IjoiRUMiLCJhbGciOiJFUzI1NiIsImtpZCI6ImVlODhhZmY4YTRjMjViZjQ4MjgyZTI1YmNmZGJmMDUzIn0...

DPoP: eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IkVwVk00RHBJX2psakEyWXdESkRlaFl2aXZYdjRuZHpYekRQRW5FVFZ0ZmciLCJ5Ij...

Troubleshooting

Debug Tools

  1. Enable OAuth2 debugging:
registry_set ('__debug_oauth2.0', '1')
  1. Check current user’s ServiceID:
SELECT bif:connection_get('NetId') {}
  1. Verify ACL graph IRIs:
SELECT VAL.DBA.val_acl_group_graph(VAL.DBA.get_default_realm());
SELECT VAL.DBA.val_acl_rule_graph(VAL.DBA.get_default_realm());
SELECT VAL.DBA.val_restrictions_graph(VAL.DBA.get_default_realm());
  1. This JSON Web Tokens web site can be used to decode the above tokens to confirm the NetIDand SPARQL endpoint being used for the session:

    • Decoded JWT in “Authorization: DPoP” http header
{
  "typ": "DPoP",
  "kty": "EC",
  "alg": "ES256",
  "kid": "ee88aff8a4c25bf48282e25bcfdbf053"
}
PAYLOAD:DATA

{
  "iss": "https://linkeddata.uriburner.com",
  "sub": "https://plus.google.com/111873902418933186900#this",
  "exp": 1731846492,
  "nbf": 1731842892,
  "rnd": "cc2ea097a37be5054a89b9dbfee390fc8cc0bd9a",
  "cnf": {
    "x5t#S256": "dnwGhEAaoOcDZjWw77cZ5fYYblk="
  }
}
VERIFY SIGNATURE
ECDSASHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  ,
  
)
  • Decoded JWT in “Dpop” http header
HEADER:ALGORITHM & TOKEN TYPE

{
  "alg": "ES256",
  "jwk": {
    "crv": "P-256",
    "kty": "EC",
    "x": "EpVM4DpI_jljA2YwDJDehYvivXv4ndzXzDPEnETVtfg",
    "y": "Pn2tOgHRVJUdmGj0o9QElEaKad9_-fgeJMLC9RmdpQo",
    "alg": "ES256"
  },
  "typ": "dpop+jwt"
}

PAYLOAD:DATA

{
  "htu": "https://ods-qa.openlinksw.com/sparql",
  "htm": "GET",
  "jti": "adedd8b2-78b0-4528-9401-5caac55d3f2a",
  "iat": 1731707327

Important Notes

  • For Virtuoso 7.2, enable ASK queries with:
GRANT EXECUTE ON DB.DBA.SPARQL_GS_APP_CALLBACK_VAL_RULE_CONDITION TO VAL_SPARQL_ADMIN
  • Clear ACL cache after making changes:
VAL.DBA.clear_graph_acl_cache();
  • When using remote SPARQL endpoints, ensure proper CORS configuration
  • For OAuth2 implementations, bearer tokens expire after 3600 seconds (1 hour) by default
  • VAL VAD version 2.2.5_git186/ 2024-10-25 or later is required for remote IdP authentication features

Glossary {glossary}

  • Access Control List (ACL): A mechanism that implements access control for a system resource by listing the identities of the system entities that are permitted to access the resource.
  • Authentication: The process of verifying the identity of a user or system.
  • Authorization: The process of giving someone permission to do or have something.
  • Bearer Token: An opaque string that serves as the authentication credential and must be sent in the HTTP Authorization header.
  • Client Credentials: Authentication method used to obtain an access token by using the client’s ID and secret.
  • CORS (Cross-Origin Resource Sharing): A security feature implemented by web browsers that controls how web pages in one domain can request and interact with resources from another domain.
  • DBA (Database Administrator): A user with administrative privileges in the Virtuoso database.
  • DPoP (Demonstrating Proof of Possession): A security protocol that proves possession of a key associated with an access token.
  • IdP (Identity Provider): A system entity that creates, maintains, and manages identity information for principals and provides authentication services to applications.
  • JWT (JSON Web Token): A compact, URL-safe means of representing claims between two parties.
  • NetID (NetworkID): A unique identifier assigned to a user within a network or system.
  • OAuth2 (OAuth 2.0 Authorization Framework): An industry-standard protocol for authorization that enables applications to obtain limited access to user accounts.
  • OIDC (OpenID Connect) is an identity layer built on top of the OAuth 2.0 protocol. It allows clients (applications) to verify the identity of end-users based on authentication performed by an authorization server and obtain basic profile information about the user.
  • RDF (Resource Description Framework): Data Definition Language from the W3C for modeling structured data as entity relationship types.
  • Turtle: A combined notation and serialization format from the W3C for expressing and serializing RDF-based structured data.
  • ServiceID: A unique identifier that represents a service account or user service.
  • SPA (Single Page Application): A web application that loads a single HTML page and dynamically updates that page as the user interacts with the app.
  • SPARQL (SPARQL Protocol and RDF Query Language): A semantic query language for databases, able to retrieve and manipulate data stored in RDF format.
  • SSO (Single Sign-On): An authentication scheme that allows a user to log in with a single ID to any of several related systems.
  • VAL (Virtuoso Authentication Layer): The authentication and authorization system used in OpenLink Virtuoso.
  • Virtuoso: An enterprise-grade server that combines the functionality of a traditional Relational Database Management System (RDBMS), Object-Relational Database Management System (ORDBMS), virtual database, RDF Store, XML Store, web application server, and file server.
  • WebID: A unique identifier for an entity (like a person or organization) on the Web, typically represented as a URI.