blob: 69f8b2196e5bc1ebbbd555f0b2ea89d869a0e975 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Apache Jena - Jena Permissions - Design</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/css/bootstrap-icons.css" rel="stylesheet" media="screen"><link rel="stylesheet" type="text/css" href="https://jena.apache.org/sass/jena.1b17c39a117e22b46db4c66f6395dc27c134a60377d87d2d5745b8600eb69722.css" integrity="sha256-GxfDmhF&#43;IrRttMZvY5XcJ8E0pgN32H0tV0W4YA62lyI=">
<link rel="shortcut icon" href="/images/favicon.ico" />
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary" role="navigation">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="/index.html">
<img class="logo-menu" src="/images/jena-logo/jena-logo-notext-small.png" alt="jena logo">Apache Jena</a>
</div>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li id="homepage" class="nav-item"><a class="nav-link" href="/index.html"><span class="bi-house"></span> Home</a></li>
<li id="download" class="nav-item"><a class="nav-link" href="/download/index.cgi"><span class="bi-download"></span> Download</a></li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal"></span> Learn <b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="dropdown-header">Tutorials</li>
<li><a class="dropdown-item" href="/tutorials/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/fuseki2/index.html">Fuseki Triplestore</a></li>
<li><a class="dropdown-item" href="/documentation/notes/index.html">How-To's</a></li>
<li><a class="dropdown-item" href="/documentation/query/manipulating_sparql_using_arq.html">Manipulating SPARQL using ARQ</a></li>
<li><a class="dropdown-item" href="/tutorials/rdf_api.html">RDF core API tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/sparql.html">SPARQL tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/using_jena_with_eclipse.html">Using Jena with Eclipse</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">References</li>
<li><a class="dropdown-item" href="/documentation/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/query/index.html">ARQ (SPARQL)</a></li>
<li><a class="dropdown-item" href="/documentation/io/">RDF I/O</a></li>
<li><a class="dropdown-item" href="/documentation/assembler/index.html">Assembler</a></li>
<li><a class="dropdown-item" href="/documentation/tools/index.html">Command-line tools</a></li>
<li><a class="dropdown-item" href="/documentation/rdfs/">Data with RDFS Inferencing</a></li>
<li><a class="dropdown-item" href="/documentation/geosparql/index.html">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/inference/index.html">Inference API</a></li>
<li><a class="dropdown-item" href="/documentation/ontology/">Ontology API</a></li>
<li><a class="dropdown-item" href="/documentation/permissions/index.html">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/extras/querybuilder/index.html">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/rdf/index.html">RDF API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfconnection/">RDF Connection - SPARQL API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfstar/index.html">RDF-star</a></li>
<li><a class="dropdown-item" href="/documentation/shacl/index.html">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/shex/index.html">ShEx</a></li>
<li><a class="dropdown-item" href="/documentation/tdb/index.html">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/tdb2/index.html">TDB2</a></li>
<li><a class="dropdown-item" href="/documentation/query/text-query.html">Text Search</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal-code"></span> Javadoc <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/documentation/javadoc.html">All Javadoc</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/arq/">ARQ</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/fuseki2/">Fuseki</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/geosparql/">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/jena/">Jena Core</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/permissions/">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/extras/querybuilder/">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/shacl/">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/tdb/">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/text/">Text Search</a></li>
</ul>
</li>
</ul>
<form class="d-flex" role="search" action="/search" method="GET">
<div class="input-group">
<input class="form-control border-end-0 border m-0" type="search" name="q" id="search-query" placeholder="Search...." aria-label="Search" style="width: 10rem;">
<button class="btn btn-outline-secondary border-start-0 border" type="submit">
<i class="bi-search"></i>
</button>
</div>
</form>
<ul class="navbar-nav">
<li id="ask" class="nav-item"><a class="nav-link" href="/help_and_support/index.html" title="Ask"><span class="bi-patch-question"></span><span class="text-body d-none d-xxl-inline"> Ask</span></a></li>
<li class="nav-item dropdown">
<a href="#" title="Get involved" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-megaphone"></span><span class="text-body d-none d-xxl-inline"> Get involved </span><b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/getting_involved/index.html">Contribute</a></li>
<li><a class="dropdown-item" href="/help_and_support/bugs_and_suggestions.html">Report a bug</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">Project</li>
<li><a class="dropdown-item" href="/about_jena/about.html">About Jena</a></li>
<li><a class="dropdown-item" href="/about_jena/architecture.html">Architecture</a></li>
<li><a class="dropdown-item" href="/about_jena/citing.html">Citing</a></li>
<li><a class="dropdown-item" href="/about_jena/team.html">Project team</a></li>
<li><a class="dropdown-item" href="/about_jena/contributions.html">Related projects</a></li>
<li><a class="dropdown-item" href="/about_jena/roadmap.html">Roadmap</a></li>
<li><a class="dropdown-item" href="/about_jena/security-advisories.html">Security Advisories</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">ASF</li>
<li><a class="dropdown-item" href="https://www.apache.org/">Apache Software Foundation</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Become a Sponsor</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/licenses/LICENSE-2.0">License</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/security/">Security</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
</ul>
</li>
<li class="nav-item" id="edit"><a class="nav-link" href="https://github.com/apache/jena-site/edit/main/source/documentation/permissions/design.md" title="Edit this page on GitHub"><span class="bi-pencil-square"></span><span class="text-body d-none d-xxl-inline"> Edit this page</span></a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="breadcrumbs">
<ol class="breadcrumb mt-4 p-2 bg-body-tertiary">
<li class="breadcrumb-item"><a href='/documentation'>DOCUMENTATION</a></li>
<li class="breadcrumb-item"><a href='/documentation/permissions'>PERMISSIONS</a></li>
<li class="breadcrumb-item active">DESIGN.HTML</li>
</ol>
</div>
<h1 class="title">Jena Permissions - Design</h1>
<main class="d-flex flex-xl-row flex-column">
<aside class="text-muted align-self-start mb-3 p-0 d-xl-none d-block">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#securityevaluatorfuture">SecurityEvaluator.FUTURE</a></li>
<li><a href="#securityevaluatorvariable">SecurityEvaluator.VARIABLE</a></li>
</ul>
<ul>
<li><a href="#secured-listeners">Secured Listeners</a></li>
</ul>
</nav>
</aside>
<article class="flex-column me-lg-4">
<p>Jena Permissions is designed to allow integrators to implement almost any security policy. Fundamentally it works by implementing dynamic proxies on top of the Jena Graph and Model interfaces as well as objects returned by those interfaces. The proxy verifies that the actions on those objects are permitted by the policy before allowing the actions to proceed.</p>
<p>The graph or model is created by the <code>org.apache.jena.permissions.Factory</code> object by wrapping a Graph or Model implementation and associating it with a URI (<code>graphIRI</code>) and a SecurityEvaluator implementation. The <code>graphIRI</code> is the URI that will be used to identify the graph/model to the security evaluator.</p>
<p>The SecurityEvaluator is an object implemented by the integrator to perform the necessary permission checks. A discussion of the SecurityEvaluator implementation can be found in the <a href="evaluator.html">Security Evaluator</a> documentation.</p>
<p>Access to methods in secured objects are determined by the CRUD (Create, Read, Update and Delete) permissions assigned to the user.</p>
<p>The system is designed to allow shallow (graph/model level) or deep (triple/statement level) decisions.</p>
<p>When a secured method is called the system performs the following checks in order:</p>
<ul>
<li>
<p>Determines if the user has proper access to the underlying graph/model. Generally the required permission is Update (for add or delete methods), or Read.</p>
</li>
<li>
<p>If the user has access to the graph/model determine if the user has permission to execute the method against <strong>all</strong> triples/statements in the graph/model. This is performed by calling <code>SecurityEvaluator.evaluate(principal, action, graphIRI, Triple.ANY)</code>. If the evaluator returns <code>true</code> then the action is permitted. This is general case for shallow permission systems. For deep permissions systems <code>false</code> may be returned.</p>
</li>
<li>
<p>if the user does not have permission to execute the method against <strong>all</strong> triples/statements the <code>SecurityEvaluator.evaluate(principal, action, graphIRI, triple)</code> method is called with the specific triple (note special cases below). If the evaluator returns <code>true</code> the action is permitted, otherwise a properly detailed PermissionDeniedException is thrown.</p>
</li>
</ul>
<h1 id="special-cases">Special Cases</h1>
<h2 id="securityevaluatorfuture">SecurityEvaluator.FUTURE</h2>
<p>There are a couple of special cases where the Node/Resource is not known when the permission check is made. An example is the creation of a RDF List object. For example to create an empty list the following triple/statement must be constructed:</p>
<pre><code>_:b1 rdf:first rdf:nil .
</code></pre>
<p>However, the permissions system can not know the value of <code>_:b1</code> until after the triple/statement is constructed and added to the graph/model. To handle this situation the permissions system asks the evaluator to evaluate the triple: <code>(SecurityEvaluator.FUTURE, RDF.first, RDF.nill)</code> Similar situations are found when adding to a list, creating reified statements, RDF alt objects, RDF sequences, or RDF anonymous resources of a specific type.</p>
<h2 id="securityevaluatorvariable">SecurityEvaluator.VARIABLE</h2>
<p>The <code>Node.ANY</code> node is used to identify the case where any node may be returned. Specifically it asks if the user can perform the action on <strong>All</strong> the nodes in this position in the triple. For example:</p>
<pre><code> Node.ANY RDF:type FOAF:Person
</code></pre>
<p>Asks if the operation can be performed on all of the nodes of type FOAF:Person.</p>
<p>The <code>SecurityEvaluator.VARIABLE</code> differs from <code>Node.ANY</code> in that the system is asking if there are any prohibitions, and not if the user may perform. Thus queries with the <code>VARIABLE</code> type node should return <code>true</code> where <code>ANY</code>
returns <code>false</code>. In general this type is used in query evaluation to determine if triple level filtering of results must be performed. Thus:</p>
<pre><code> SecurityEvaluator.VARIABLE RDF:type FOAF:Person
</code></pre>
<p>Asks if there are any restrictions against the user performing the action against all triples of type FOAF:Person. The assumption is that checking for restrictions may be a faster check than checking for all access. Note that by returning <code>true</code> the permissions system will check each explicit triple for access permissions. So if the system can not determine if there are access restrictions it is safe to return <code>true</code>.</p>
<h1 id="objects-returned-from-secured-objects">Objects Returned from Secured Objects</h1>
<p>Models and Graphs often return objects from methods. For example the <code>model.createStatement()</code> returns a <code>Statement</code> object. That object holds a reference to the model and performs operations against the model (for example <code>Statement.changeLiteralObject()</code>). Since permissions provides a dynamic wrapper around the base model to create the secured model, returning the model <code>Statement</code> would return an object that no longer has any permissions applied. Therefore the permissions system creates a <code>SecuredStatement</code> that applies permission checks to all operations before calling the base <code>Statement</code> methods.</p>
<p>All secured objects return secured objects if those objects may read or alter the underlying graph/model.</p>
<p>All secured objects are defined as interfaces and are returned as dynamic proxies.</p>
<p>All secured objects have concrete implementations. These implementations must remain concrete to ensure that we handle all cases where returned objects may alter the underlying graph/model.</p>
<h2 id="secured-listeners">Secured Listeners</h2>
<p>Both the Graph and the Model interfaces provide a listener framework. Listeners are attached to the graph/model and changes to the graph/model are reported to them. In order to ensure that listeners do not leak information, the principal that was active when the listener was attached is preserved in a <code>CachedSecurityEvaluator</code> instance. This security evaluator implementation, wraps the original implementation and retains the current user. Thus when the listener performs the permission checks the original user is used not the current user. This is why the SecurityEvaluator <strong>must</strong> use the <code>principal</code> parameters and not call <code>getPrincipal()</code> directly during evaluation calls.</p>
<h1 id="proxy-implementation">Proxy Implementation</h1>
<p>The proxy implementation uses a reflection <code>InvocationHandler</code> strategy. This strategy results in a proxy that implements all the interfaces of the original object. The original object along with its <code>InvocationHandler</code> instance are kept together in an <code>ItemHolder</code> instance variable in the secured instance. When the invoker is called it determines if the called method is on the secured interface or not. If the method is on the secured interface the invocation handler method is called, otherwise the method on the base class is called.</p>
</article>
<aside class="text-muted align-self-start mb-3 mb-xl-5 p-0 d-none d-xl-flex flex-column sticky-top">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#securityevaluatorfuture">SecurityEvaluator.FUTURE</a></li>
<li><a href="#securityevaluatorvariable">SecurityEvaluator.VARIABLE</a></li>
</ul>
<ul>
<li><a href="#secured-listeners">Secured Listeners</a></li>
</ul>
</nav>
</aside>
</main>
</div>
</div>
</div>
<footer class="bd-footer py-4 py-md-5 mt-4 mt-lg-5 bg-body-tertiary">
<div class="container" style="font-size:80%" >
<p>
Copyright &copy; 2011&ndash;2024 The Apache Software Foundation, Licensed under the
<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
</p>
<p>
Apache Jena, Jena, the Apache Jena project logo, Apache and the Apache feather logos are trademarks of
The Apache Software Foundation.
<br/>
<a href="https://privacy.apache.org/policies/privacy-policy-public.html"
>Apache Software Foundation Privacy Policy</a>.
</p>
</div>
</footer>
<script src="/js/popper.min.js.js" type="text/javascript"></script>
<script src="/js/bootstrap.min.js" type="text/javascript"></script>
<script src="/js/improve.js" type="text/javascript"></script>
<script type="text/javascript">
(function() {
'use strict'
const links = document.querySelectorAll(`a[href="${window.location.pathname}"]`)
if (links !== undefined && links !== null) {
for (const link of links) {
link.classList.add('active')
let parentElement = link.parentElement
let count = 0
const levelsLimit = 4
while (['UL', 'LI'].includes(parentElement.tagName) && count <= levelsLimit) {
if (parentElement.tagName === 'LI') {
parentElement.querySelector('a:first-child').classList.add('active')
}
parentElement = parentElement.parentElement
count++
}
}
}
})()
</script>
</body>
</html>