@@ -166,53 +166,60 @@ public Resource authorize(ContainerRequestContext request, Resource agent, Resou
166166 {
167167 Resource accessTo = ResourceFactory .createResource (request .getUriInfo ().getAbsolutePath ().toString ());
168168
169- QuerySolutionMap docTypeQsm = new QuerySolutionMap ();
170- docTypeQsm .add (SPIN .THIS_VAR_NAME , accessTo );
171- ResultSetRewindable docTypes = loadResultSet (getApplication ().getService (), getDocumentTypeQuery (), docTypeQsm );
169+ // special case where the agent is the owner of the requested document - automatically grant acl:Read/acl:Append/acl:Write access
170+ if (agent != null && isOwner (accessTo , agent ))
171+ {
172+ log .debug ("Agent <{}> is the owner of <{}>, granting acl:Read/acl:Append/acl:Write access" , agent , accessTo );
173+ return createOwnerAuthorization (accessTo , agent );
174+ }
175+
176+ QuerySolutionMap thisQsm = new QuerySolutionMap ();
177+ thisQsm .add (SPIN .THIS_VAR_NAME , accessTo );
172178
179+ ResultSetRewindable docTypesResult = loadResultSet (getApplication ().getService (), getDocumentTypeQuery (), thisQsm );
173180 try
174181 {
175- // special case where the agent is the owner of the requested document - automatically grant acl:Read/acl:Append/acl:Write access
176- if (isOwner (docTypes , agent ))
177- {
178- log .debug ("Agent <{}> is the owner of <{}>, granting acl:Read/acl:Append/acl:Write access" , agent , accessTo );
179- return createOwnerAuthorization (accessTo , agent );
180- }
181-
182- if (!docTypes .hasNext ()) // if the document resource has no types, we assume the document does not exist
182+ if (!docTypesResult .hasNext ()) // if the document resource has no types, we assume the document does not exist
183183 {
184184 // special case for PUT requests to non-existing document: allow if the agent has acl:Write acess to the *parent* URI
185185 if (request .getMethod ().equals (HttpMethod .PUT ) && accessMode .equals (ACL .Write ))
186186 {
187187 URI parentURI = URI .create (accessTo .getURI ()).resolve (".." );
188188 log .debug ("Requested document <{}> not found, falling back to parent URI <{}>" , accessTo , parentURI );
189189 accessTo = ResourceFactory .createResource (parentURI .toString ());
190-
191- docTypeQsm = new QuerySolutionMap ();
192- docTypeQsm .add (SPIN .THIS_VAR_NAME , accessTo );
193- docTypes .close ();
194- docTypes = loadResultSet (getApplication ().getService (), getDocumentTypeQuery (), docTypeQsm );
195-
196- Set <Resource > parentTypes = new HashSet <>();
197- docTypes .forEachRemaining (qs -> parentTypes .add (qs .getResource ("Type" )));
198-
199- // only root and containers allow child documents
200- if (Collections .disjoint (parentTypes , Set .of (Default .Root , DH .Container ))) return null ;
201-
202- docTypes .reset (); // rewind result set to the beginning
203-
190+
191+ thisQsm = new QuerySolutionMap ();
192+ thisQsm .add (SPIN .THIS_VAR_NAME , accessTo );
193+
204194 // special case where the agent is the owner of the requested document - automatically grant acl:Read/acl:Append/acl:Write access
205- if (isOwner (docTypes , agent ))
195+ if (agent != null && isOwner (accessTo , agent ))
206196 {
207197 log .debug ("Agent <{}> is the owner of <{}>, granting acl:Read/acl:Append/acl:Write access" , agent , accessTo );
208198 return createOwnerAuthorization (accessTo , agent );
209199 }
200+
201+ docTypesResult .close ();
202+ docTypesResult = loadResultSet (getApplication ().getService (), getDocumentTypeQuery (), thisQsm );
203+ try
204+ {
205+ Set <Resource > parentTypes = new HashSet <>();
206+ docTypesResult .forEachRemaining (qs -> parentTypes .add (qs .getResource ("Type" )));
207+
208+ // only root and containers allow child documents
209+ if (Collections .disjoint (parentTypes , Set .of (Default .Root , DH .Container ))) return null ;
210+
211+ docTypesResult .reset (); // rewind result set to the beginning
212+ }
213+ finally
214+ {
215+ docTypesResult .close ();
216+ }
210217 }
211218 else return null ;
212219 }
213220
214221 ParameterizedSparqlString pss = getApplication ().canAs (EndUserApplication .class ) ? getACLQuery () : getOwnerACLQuery ();
215- Query query = new SetResultSetValues ().apply (pss .asQuery (), docTypes );
222+ Query query = new SetResultSetValues ().apply (pss .asQuery (), docTypesResult );
216223 pss = new ParameterizedSparqlString (query .toString ()); // make sure VALUES are now part of the query string
217224 assert pss .toString ().contains ("VALUES" );
218225
@@ -221,7 +228,7 @@ public Resource authorize(ContainerRequestContext request, Resource agent, Resou
221228 }
222229 finally
223230 {
224- docTypes .close ();
231+ docTypesResult .close ();
225232 }
226233 }
227234
@@ -248,21 +255,47 @@ public Resource getAuthorizationByMode(Model authModel, Resource accessMode)
248255 /**
249256 * Checks if the given agent is the <code>acl:owner</code> of the document.
250257 *
251- * @param docTypes The result set containing document metadata.
252- * @param agent The agent whose ownership is checked.
258+ * @param accessTo the document URI
259+ * @param agent the agent whose ownership is checked.
253260 * @return true if the agent is the owner, false otherwise.
254261 */
255- protected boolean isOwner (ResultSetRewindable docTypes , Resource agent )
262+ protected boolean isOwner (Resource accessTo , Resource agent )
256263 {
264+ QuerySolutionMap qsm = new QuerySolutionMap ();
265+ qsm .add (SPIN .THIS_VAR_NAME , accessTo );
266+
267+ ResultSetRewindable docOwnerResult = loadResultSet (getApplication ().getService (), getDocumentOwnerQuery (), qsm ); // could use ASK query in principle
268+ try
269+ {
270+ return isOwner (docOwnerResult , agent );
271+ }
272+ finally
273+ {
274+ docOwnerResult .close ();
275+ }
276+ }
277+
278+ /**
279+ * Checks if the given agent is the <code>acl:owner</code> of the document.
280+ *
281+ * @param docOwnerResult the result set containing document metadata
282+ * @param agent the agent whose ownership is checked
283+ * @return true if the agent is the owner, false otherwise.
284+ */
285+ protected boolean isOwner (ResultSetRewindable docOwnerResult , Resource agent )
286+ {
287+ if (docOwnerResult == null ) throw new IllegalArgumentException ("ResultSet cannot be null" );
288+ if (agent == null ) throw new IllegalArgumentException ("Agent resource cannot be null" );
289+
257290 Resource owner = null ;
258291
259- while (docTypes .hasNext ())
292+ while (docOwnerResult .hasNext ())
260293 {
261- QuerySolution qs = docTypes .next ();
294+ QuerySolution qs = docOwnerResult .next ();
262295 if (owner == null && qs .contains ("owner" )) owner = qs .getResource ("owner" );
263296 }
264297
265- docTypes .reset ();
298+ docOwnerResult .reset ();
266299
267300 return owner != null && owner .equals (agent );
268301 }
@@ -363,6 +396,17 @@ public ParameterizedSparqlString getDocumentTypeQuery()
363396 return documentTypeQuery .copy ();
364397 }
365398
399+ public ParameterizedSparqlString getDocumentOwnerQuery ()
400+ {
401+ return new ParameterizedSparqlString ("PREFIX acl: <http://www.w3.org/ns/auth/acl#>\n " +
402+ "\n " +
403+ "SELECT ?owner\n " +
404+ "WHERE\n " +
405+ " { GRAPH $this\n " +
406+ " { $this acl:owner $owner }\n " +
407+ " }" );
408+ }
409+
366410 /**
367411 * Returns the SPARQL service for agent data.
368412 *
0 commit comments