001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.auth.webac;
019
020import static java.util.Collections.singletonList;
021import static org.apache.jena.graph.NodeFactory.createURI;
022import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
023import static org.apache.jena.riot.Lang.TTL;
024import static org.fcrepo.auth.webac.URIConstants.FOAF_AGENT_VALUE;
025import static org.fcrepo.auth.webac.URIConstants.VCARD_GROUP;
026import static org.fcrepo.auth.webac.URIConstants.WEBAC_MODE_READ_VALUE;
027import static org.fcrepo.auth.webac.URIConstants.WEBAC_MODE_WRITE_VALUE;
028import static org.fcrepo.http.api.FedoraAcl.ROOT_AUTHORIZATION_PROPERTY;
029import static org.fcrepo.kernel.api.RdfLexicon.REPOSITORY_NAMESPACE;
030import static org.fcrepo.kernel.api.RequiredRdfContext.PROPERTIES;
031import static org.junit.Assert.assertEquals;
032import static org.junit.Assert.assertNull;
033import static org.junit.Assert.assertTrue;
034import static org.mockito.ArgumentMatchers.any;
035import static org.mockito.ArgumentMatchers.anyObject;
036import static org.mockito.ArgumentMatchers.eq;
037import static org.mockito.Mockito.when;
038import static org.springframework.test.util.ReflectionTestUtils.setField;
039
040import java.net.URI;
041import java.util.ArrayList;
042import java.util.Collection;
043import java.util.List;
044import java.util.Map;
045import javax.jcr.Node;
046import javax.jcr.Property;
047import javax.jcr.RepositoryException;
048import javax.jcr.Session;
049
050import org.apache.jena.graph.Triple;
051import org.apache.jena.rdf.model.Model;
052import org.apache.jena.riot.Lang;
053import org.apache.jena.riot.RDFDataMgr;
054import org.fcrepo.http.commons.session.SessionFactory;
055import org.fcrepo.kernel.api.FedoraSession;
056import org.fcrepo.kernel.api.RdfStream;
057import org.fcrepo.kernel.api.models.FedoraResource;
058import org.fcrepo.kernel.api.rdf.DefaultRdfStream;
059import org.fcrepo.kernel.api.services.NodeService;
060import org.fcrepo.kernel.modeshape.FedoraResourceImpl;
061import org.fcrepo.kernel.modeshape.FedoraSessionImpl;
062import org.junit.Before;
063import org.junit.Rule;
064import org.junit.Test;
065import org.junit.contrib.java.lang.system.RestoreSystemProperties;
066import org.junit.runner.RunWith;
067import org.mockito.Mock;
068import org.mockito.junit.MockitoJUnitRunner;
069
070/**
071 * @author acoburn
072 * @since 9/3/15
073 */
074@RunWith(MockitoJUnitRunner.Silent.class)
075public class WebACRolesProviderTest {
076
077    private WebACRolesProvider roleProvider;
078
079    private static final String FEDORA_PREFIX = "info:fedora";
080    private static final String FEDORA_URI_PREFIX = "file:///rest";
081
082    @Mock
083    private Node mockNode, mockAclNode, mockParentNode;
084
085    @Mock
086    private FedoraSessionImpl mockSession;
087
088    @Mock
089    private SessionFactory mockSessionFactory;
090
091    @Mock
092    private Session mockJcrSession;
093
094    @Mock
095    private NodeService mockNodeService;
096
097    @Mock
098    private FedoraResourceImpl mockResource, mockParentResource;
099
100    @Mock
101    private FedoraResourceImpl mockAclResource;
102
103    @Mock
104    private FedoraResource mockAgentClassResource;
105
106    @Mock
107    private Property mockProperty;
108
109    @Rule
110    public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
111
112    @Before
113    public void setUp() throws RepositoryException {
114
115        roleProvider = new WebACRolesProvider();
116        setField(roleProvider, "nodeService", mockNodeService);
117        setField(roleProvider, "sessionFactory", mockSessionFactory);
118
119        when(mockNode.getSession()).thenReturn(mockJcrSession);
120        when(mockSessionFactory.getInternalSession()).thenReturn(mockSession);
121        when(mockSession.getJcrSession()).thenReturn(mockJcrSession);
122
123        when(mockResource.getNode()).thenReturn(mockNode);
124        when(mockAclResource.getNode()).thenReturn(mockAclNode);
125
126        when(mockResource.getOriginalResource()).thenReturn(mockResource);
127        when(mockNode.getDepth()).thenReturn(0);
128    }
129
130    private void assertOnlyDefaultAgentInRoles(final Map<String, Collection<String>> roles) {
131        assertEquals(1, roles.size());
132        assertTrue(roles.keySet().contains(FOAF_AGENT_VALUE));
133    }
134
135    @Test
136    public void noAclTest() throws RepositoryException {
137        final String accessTo = "/dark/archive/sunshine";
138
139        when(mockResource.getAcl()).thenReturn(null);
140        when(mockParentResource.getAcl()).thenReturn(null);
141
142        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
143        when(mockNode.getPath()).thenReturn(accessTo);
144
145        when(mockResource.getPath()).thenReturn(accessTo);
146        when(mockResource.getContainer()).thenReturn(mockParentResource);
147        when(mockResource.getTriples(anyObject(), eq(PROPERTIES)))
148                .thenReturn(new DefaultRdfStream(createURI("subject")));
149        when(mockResource.getOriginalResource()).thenReturn(mockResource);
150        when(mockNode.getDepth()).thenReturn(1);
151
152        when(mockParentResource.getNode()).thenReturn(mockParentNode);
153        when(mockParentResource.getOriginalResource()).thenReturn(mockParentResource);
154        when(mockParentNode.getDepth()).thenReturn(0);
155
156        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
157
158        assertOnlyDefaultAgentInRoles(roles);
159    }
160
161    @Test
162    public void acl01ParentTest() throws RepositoryException {
163        final String agent = "user01";
164        final String parentPath = "/webacl_box1";
165        final String accessTo = parentPath + "/foo";
166        final String acl = "/acls/01/acl.ttl";
167
168        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
169        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
170        when(mockNode.getPath()).thenReturn(accessTo);
171        when(mockAclNode.getPath()).thenReturn(acl);
172
173        when(mockResource.getAcl()).thenReturn(null);
174        when(mockParentResource.getAcl()).thenReturn(mockAclResource);
175
176        when(mockResource.getPath()).thenReturn(accessTo);
177        when(mockResource.getContainer()).thenReturn(mockParentResource);
178        when(mockResource.getPath()).thenReturn(accessTo);
179        when(mockResource.getOriginalResource()).thenReturn(mockResource);
180        when(mockNode.getDepth()).thenReturn(1);
181
182        when(mockParentResource.getNode()).thenReturn(mockParentNode);
183        when(mockParentResource.getPath()).thenReturn(parentPath);
184        when(mockParentResource.getAcl()).thenReturn(mockAclResource);
185        when(mockAclResource.isAcl()).thenReturn(true);
186        when(mockAclResource.getPath()).thenReturn(parentPath + "/fcr:acl");
187
188        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
189                .thenReturn(getRdfStreamFromResource(acl, TTL));
190
191        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
192
193        assertEquals("There should be exactly one agent in the role map", 1, roles.size());
194        assertEquals("The agent should have exactly two modes", 2, roles.get(agent).size());
195        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
196        assertTrue("The agent should be able to write", roles.get(agent).contains(WEBAC_MODE_WRITE_VALUE));
197    }
198
199    @Test
200    public void acl21NoDefaultACLStatementTest() throws RepositoryException {
201        final String agent = "user21";
202        final String parentPath = "/resource_acl_no_inheritance";
203        final String accessTo = parentPath + "/foo";
204        final String acl = "/acls/21/acl.ttl";
205
206        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
207        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
208        when(mockNode.getPath()).thenReturn(accessTo);
209        when(mockAclNode.getPath()).thenReturn(acl);
210
211        when(mockResource.getAcl()).thenReturn(null);
212        when(mockParentResource.getAcl()).thenReturn(mockAclResource);
213        when(mockAclResource.hasProperty("acl:default")).thenReturn(false);
214
215        when(mockResource.getPath()).thenReturn(accessTo);
216        when(mockResource.getContainer()).thenReturn(mockParentResource);
217        when(mockResource.getPath()).thenReturn(accessTo);
218        when(mockResource.getOriginalResource()).thenReturn(mockResource);
219        when(mockNode.getDepth()).thenReturn(1);
220
221        when(mockParentResource.getNode()).thenReturn(mockParentNode);
222        when(mockParentResource.getPath()).thenReturn(parentPath);
223        when(mockAclResource.getPath()).thenReturn(acl);
224        when(mockParentNode.getDepth()).thenReturn(0);
225
226
227        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
228                .thenReturn(getRdfStreamFromResource(acl, TTL));
229
230        System.setProperty(ROOT_AUTHORIZATION_PROPERTY, "./target/test-classes/test-root-authorization2.ttl");
231
232        // The default root ACL should be used for authorization instead of the parent ACL
233        final String rootAgent = "user06a";
234        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
235        assertEquals("Contains no agents in the role map!", 1, roles.size());
236        assertNull("Contains agent " + agent + " from ACL in parent node!", roles.get(agent));
237        assertEquals("Should have agent " + rootAgent + " from the root ACL!", 1, roles.get(rootAgent).size());
238        assertTrue("Should have read mode for agent " + rootAgent + " from the root ACL!",
239                roles.get(rootAgent).contains(WEBAC_MODE_READ_VALUE));
240    }
241
242    @Test
243    public void acl01Test1() throws RepositoryException {
244        final String agent = "user01";
245        final String accessTo = "/webacl_box1";
246        final String acl = "/acls/01/acl.ttl";
247
248        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
249        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
250        when(mockNode.getPath()).thenReturn(accessTo);
251        when(mockAclNode.getPath()).thenReturn(acl);
252        when(mockResource.getAcl()).thenReturn(mockAclResource);
253        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
254        when(mockAclResource.getPath()).thenReturn(acl);
255        when(mockResource.getPath()).thenReturn(accessTo);
256        when(mockResource.getOriginalResource()).thenReturn(mockResource);
257        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
258            .thenReturn(getRdfStreamFromResource(acl, TTL));
259        when(mockAclResource.isAcl()).thenReturn(true);
260        when(mockAclResource.getPath()).thenReturn(accessTo + "/fcr:acl");
261
262
263        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
264
265        assertEquals("There should be exactly one agent in the role map", 1, roles.size());
266        assertEquals("The agent should have exactly two modes", 2, roles.get(agent).size());
267        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
268        assertTrue("The agent should be able to write", roles.get(agent).contains(WEBAC_MODE_WRITE_VALUE));
269    }
270
271    @Test
272    public void acl01Test2() throws RepositoryException {
273        final String accessTo = "/webacl_box2";
274        final String acl = "/acls/01/acl.ttl";
275
276        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
277        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo ))).thenReturn(mockResource);
278        when(mockNode.getPath()).thenReturn(accessTo);
279        when(mockAclNode.getPath()).thenReturn(acl);
280        when(mockResource.getAcl()).thenReturn(mockAclResource);
281        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
282        when(mockAclResource.getPath()).thenReturn(acl);
283        when(mockResource.getPath()).thenReturn(accessTo);
284        when(mockResource.getOriginalResource()).thenReturn(mockResource);
285        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
286            .thenReturn(getRdfStreamFromResource(acl, TTL));
287
288        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
289
290        assertOnlyDefaultAgentInRoles(roles);
291    }
292
293    @Test
294    public void acl02Test() throws RepositoryException {
295        final String agent = "Editors";
296        final String accessTo = "/box/bag/collection";
297        final String acl = "/acls/02/acl.ttl";
298
299        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
300        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
301        when(mockNode.getPath()).thenReturn(accessTo);
302        when(mockAclNode.getPath()).thenReturn(acl);
303
304        when(mockResource.getAcl()).thenReturn(mockAclResource);
305        when(mockProperty.getString()).thenReturn(acl);
306        when(mockAclResource.getPath()).thenReturn(acl);
307        when(mockResource.getPath()).thenReturn(accessTo);
308        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
309            .thenReturn(getRdfStreamFromResource(acl, TTL));
310        when(mockAclResource.isAcl()).thenReturn(true);
311        when(mockAclResource.getPath()).thenReturn(accessTo + "/fcr:acl");
312
313        when(mockResource.getOriginalResource()).thenReturn(mockResource);
314
315
316        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
317
318        assertEquals("There should be exactly one agent in the role map", 1, roles.size());
319        assertEquals("The agent should have exactly two modes", 2, roles.get(agent).size());
320        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
321        assertTrue("The agent should be able to write", roles.get(agent).contains(WEBAC_MODE_WRITE_VALUE));
322    }
323
324    @Test
325    public void acl03Test1() throws RepositoryException {
326        final String agent = "http://xmlns.com/foaf/0.1/Agent";
327        final String accessTo = "/dark/archive/sunshine";
328        final String acl = "/acls/03/acl.ttl";
329
330        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
331        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo ))).thenReturn(mockResource);
332        when(mockNode.getPath()).thenReturn(accessTo);
333        when(mockAclNode.getPath()).thenReturn(acl);
334        when(mockResource.getAcl()).thenReturn(mockAclResource);
335        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
336        when(mockAclResource.getPath()).thenReturn(acl);
337        when(mockResource.getPath()).thenReturn(accessTo);
338        when(mockResource.getOriginalResource()).thenReturn(mockResource);
339        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
340            .thenReturn(getRdfStreamFromResource(acl, TTL));
341        when(mockAclResource.isAcl()).thenReturn(true);
342        when(mockAclResource.getPath()).thenReturn(accessTo + "/fcr:acl");
343
344        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
345
346        assertEquals("There should be exactly one agent in the roles map", 1, roles.size());
347        assertEquals("The agent should have exactly one mode", 1, roles.get(agent).size());
348        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
349    }
350
351    @Test
352    public void acl03Test2() throws RepositoryException {
353        final String agent = "Restricted";
354        final String accessTo = "/dark/archive";
355        final String acl = "/acls/03/acl.ttl";
356
357        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
358        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo ))).thenReturn(mockResource);
359        when(mockNode.getPath()).thenReturn(accessTo);
360        when(mockAclNode.getPath()).thenReturn(acl);
361        when(mockResource.getAcl()).thenReturn(mockAclResource);
362        when(mockAclResource.isAcl()).thenReturn(true);
363        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
364        when(mockAclResource.getPath()).thenReturn(acl);
365        when(mockResource.getPath()).thenReturn(accessTo);
366        when(mockResource.getOriginalResource()).thenReturn(mockResource);
367        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
368            .thenReturn(getRdfStreamFromResource(acl, TTL));
369
370        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
371
372        assertEquals("There should be exactly one agent", 1, roles.size());
373        assertEquals("The agent should have one mode", 1, roles.get(agent).size());
374        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
375    }
376
377    @Test
378    public void foafAgentTest() throws RepositoryException {
379        final String agent = "http://xmlns.com/foaf/0.1/Agent";
380        final String accessTo = "/foaf-agent";
381        final String acl = "/acls/03/foaf-agent.ttl";
382
383        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
384        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
385        when(mockNode.getPath()).thenReturn(accessTo);
386        when(mockAclNode.getPath()).thenReturn(acl);
387        when(mockResource.getAcl()).thenReturn(mockAclResource);
388        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
389        when(mockAclResource.getPath()).thenReturn(acl);
390        when(mockAclResource.isAcl()).thenReturn(true);
391        when(mockResource.getPath()).thenReturn(accessTo);
392        when(mockResource.getOriginalResource()).thenReturn(mockResource);
393        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
394            .thenReturn(getRdfStreamFromResource(acl, TTL));
395
396        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
397
398        assertEquals("There should be only one valid role", 1, roles.size());
399        assertEquals("The foaf:Agent should have exactly one valid mode", 1,
400                     roles.get(agent).size());
401        assertTrue("The foaf:Agent should be able to write",
402                   roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
403    }
404
405    @Test
406    public void authenticatedAgentTest() throws RepositoryException {
407        final String aclAuthenticatedAgent = "http://www.w3.org/ns/auth/acl#AuthenticatedAgent";
408        final String accessTo = "/authenticated-agent";
409        final String acl = "/acls/03/authenticated-agent.ttl";
410
411        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
412        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
413        when(mockNode.getPath()).thenReturn(accessTo);
414        when(mockAclNode.getPath()).thenReturn(acl);
415        when(mockResource.getAcl()).thenReturn(mockAclResource);
416        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
417        when(mockAclResource.getPath()).thenReturn(acl);
418        when(mockAclResource.isAcl()).thenReturn(true);
419        when(mockResource.getPath()).thenReturn(accessTo);
420        when(mockResource.getOriginalResource()).thenReturn(mockResource);
421        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
422            .thenReturn(getRdfStreamFromResource(acl, TTL));
423
424        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
425
426        assertEquals("There should be only one valid role", 1, roles.size());
427        assertEquals("The acl:AuthenticatedAgent should have exactly one valid mode", 1,
428                     roles.get(aclAuthenticatedAgent).size());
429        assertTrue("The acl:AuthenticatedAgent should be able to write",
430                   roles.get(aclAuthenticatedAgent).contains(WEBAC_MODE_READ_VALUE));
431    }
432
433    @Test
434    public void acl04Test() throws RepositoryException {
435        final String agent1 = "http://xmlns.com/foaf/0.1/Agent";
436        final String agent2 = "Editors";
437        final String accessTo = "/public_collection";
438        final String acl = "/acls/04/acl.ttl";
439
440        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
441        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
442        when(mockNode.getPath()).thenReturn(accessTo);
443        when(mockAclNode.getPath()).thenReturn(acl);
444        when(mockResource.getAcl()).thenReturn(mockAclResource);
445        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
446        when(mockAclResource.getPath()).thenReturn(acl);
447        when(mockAclResource.isAcl()).thenReturn(true);
448        when(mockResource.getPath()).thenReturn(accessTo);
449        when(mockResource.getOriginalResource()).thenReturn(mockResource);
450        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
451            .thenReturn(getRdfStreamFromResource(acl, TTL));
452
453        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
454
455        assertEquals("There should be exactly two agents", 2, roles.size());
456        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
457        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
458        assertEquals("The agent should have two modes", 2, roles.get(agent2).size());
459        assertTrue("The agent should be able to read", roles.get(agent2).contains(WEBAC_MODE_READ_VALUE));
460        assertTrue("The agent should be able to write", roles.get(agent2).contains(WEBAC_MODE_READ_VALUE));
461    }
462
463    @Test
464    public void acl05Test() throws RepositoryException {
465        final String agent1 = "http://xmlns.com/foaf/0.1/Agent";
466        final String agent2 = "Admins";
467        final String accessTo = "/mixedCollection";
468        final String acl = "/acls/05/acl.ttl";
469
470        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
471        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
472        when(mockNode.getPath()).thenReturn(accessTo);
473        when(mockAclNode.getPath()).thenReturn(acl);
474        when(mockResource.getAcl()).thenReturn(mockAclResource);
475        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
476        when(mockResource.getTypes()).thenReturn(singletonList(URI.create("http://example.com/terms#publicImage")));
477        when(mockAclResource.isAcl()).thenReturn(true);
478        when(mockAclResource.getPath()).thenReturn(acl);
479        when(mockResource.getPath()).thenReturn(accessTo);
480        when(mockResource.getOriginalResource()).thenReturn(mockResource);
481        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
482            .thenReturn(getRdfStreamFromResource(acl, TTL));
483
484        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
485
486        assertEquals("There should be exactly two agents", 2, roles.size());
487        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
488        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
489        assertEquals("The agent should have one mode", 1, roles.get(agent2).size());
490        assertTrue("The agent should be able to read", roles.get(agent2).contains(WEBAC_MODE_READ_VALUE));
491    }
492
493    @Test
494    public void acl05Test2() throws RepositoryException {
495        final String agent1 = "http://xmlns.com/foaf/0.1/Agent";
496        final String accessTo = "/someOtherCollection";
497        final String acl = "/acls/05/acl.ttl";
498
499        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
500        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
501        when(mockNode.getPath()).thenReturn(accessTo);
502        when(mockAclNode.getPath()).thenReturn(acl);
503        when(mockResource.getAcl()).thenReturn(mockAclResource);
504        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
505        when(mockResource.getTypes()).thenReturn(singletonList(URI.create("http://example.com/terms#publicImage")));
506        when(mockAclResource.getPath()).thenReturn(acl);
507        when(mockAclResource.isAcl()).thenReturn(true);
508        when(mockResource.getPath()).thenReturn(accessTo);
509        when(mockResource.getOriginalResource()).thenReturn(mockResource);
510        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
511            .thenReturn(getRdfStreamFromResource(acl, TTL));
512
513        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
514
515        assertEquals("There should be exactly one agent", 1, roles.size());
516        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
517        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
518    }
519
520    /* (non-Javadoc)
521     * Test that an in-repository resource used as a target for acl:agentGroup has
522     * the rdf:type of vcard:Group. This test mocks a vcard:Group resource and should
523     * therefore retrieve two agents.
524     */
525    @Test
526    public void acl09Test1() throws RepositoryException {
527        final String agent1 = "person1";
528        final String accessTo = "/anotherCollection";
529
530        final String groupResource = "/group/foo";
531        final String aclDir = "/acls/09";
532        final String acl = aclDir + "/acl.ttl";
533        final String group = aclDir + "/group.ttl";
534
535        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
536        when(mockNodeService.find(mockSession, groupResource)).thenReturn(mockAgentClassResource);
537        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
538        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
539        when(mockNode.getPath()).thenReturn(accessTo);
540        when(mockAclNode.getPath()).thenReturn(acl);
541        when(mockResource.getAcl()).thenReturn(mockAclResource);
542        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
543        when(mockAclResource.getPath()).thenReturn(acl);
544        when(mockResource.getPath()).thenReturn(accessTo);
545        when(mockResource.getOriginalResource()).thenReturn(mockResource);
546        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
547            .thenReturn(getRdfStreamFromResource(acl, TTL));
548        when(mockAclResource.isAcl()).thenReturn(true);
549        when(mockAclResource.getPath()).thenReturn(accessTo + "/fcr:acl");
550
551        when(mockAgentClassResource.getTypes()).thenReturn(singletonList(VCARD_GROUP));
552        when(mockAgentClassResource.getPath()).thenReturn(groupResource);
553        when(mockAgentClassResource.getTriples(anyObject(), eq(PROPERTIES)))
554                .thenReturn(getRdfStreamFromResource(group, TTL));
555
556
557        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
558
559        assertEquals("There should be exactly two agents", 2, roles.size());
560        assertEquals("The agent should have two modes", 2, roles.get(agent1).size());
561        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
562        assertTrue("The agent should be able to write", roles.get(agent1).contains(WEBAC_MODE_WRITE_VALUE));
563    }
564
565    /* (non-Javadoc)
566     * Test that an in-repository resource used as a target for acl:agentClass has
567     * the rdf:type of foaf:Group. This test mocks a resource that is not of the type
568     * foaf:Group and therefore should retrieve zero agents.
569     */
570    @Test
571    public void acl09Test2() throws RepositoryException {
572        final String accessTo = "/anotherCollection";
573
574        final String groupResource = "/group/foo";
575        final String acl = "/acls/09/acl.ttl";
576        final String group = "/acls/09/group.ttl";
577
578        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
579        when(mockNodeService.find(mockSession, groupResource)).thenReturn(mockAgentClassResource);
580        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
581        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
582        when(mockNode.getPath()).thenReturn(accessTo);
583        when(mockAclNode.getPath()).thenReturn(acl);
584        when(mockResource.getAcl()).thenReturn(mockAclResource);
585        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
586        when(mockAclResource.getPath()).thenReturn(acl);
587        when(mockResource.getPath()).thenReturn(accessTo);
588        when(mockResource.getOriginalResource()).thenReturn(mockResource);
589        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
590            .thenReturn(getRdfStreamFromResource(acl, TTL));
591
592        when(mockAgentClassResource.getTypes()).thenReturn(new ArrayList<>());
593        when(mockAgentClassResource.getPath()).thenReturn(groupResource);
594        when(mockAgentClassResource.getTriples(anyObject(), eq(PROPERTIES)))
595            .thenReturn(getRdfStreamFromResource(group, TTL));
596
597        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
598
599        assertOnlyDefaultAgentInRoles(roles);
600    }
601
602    @Test
603    public void acl17Test1() throws RepositoryException {
604        final String foafAgent = "http://xmlns.com/foaf/0.1/Agent";
605        final String accessTo = "/dark/archive/sunshine";
606        final String acl = "/acls/17/acl.ttl";
607
608        when(mockNodeService.find(any(FedoraSession.class), eq(acl))).thenReturn(mockAclResource);
609        when(mockNodeService.find(any(FedoraSession.class), eq(accessTo))).thenReturn(mockResource);
610        when(mockNode.getPath()).thenReturn(accessTo);
611        when(mockAclNode.getPath()).thenReturn(acl);
612        when(mockResource.getAcl()).thenReturn(mockAclResource);
613        when(mockNodeService.find(mockSession, acl)).thenReturn(mockAclResource);
614        when(mockAclResource.getPath()).thenReturn(acl);
615        when(mockAclResource.isAcl()).thenReturn(true);
616        when(mockResource.getPath()).thenReturn(accessTo);
617        when(mockResource.getOriginalResource()).thenReturn(mockResource);
618        when(mockAclResource.getTriples(anyObject(), eq(PROPERTIES)))
619            .thenReturn(getRdfStreamFromResource(acl, TTL));
620
621        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
622
623        assertEquals("There should be only one valid role", 1, roles.size());
624        assertEquals("The foafAgent should have exactly one valid mode", 1, roles.get(foafAgent).size());
625        assertTrue("The foafAgent should be able to write", roles.get(foafAgent).contains(WEBAC_MODE_WRITE_VALUE));
626    }
627
628    @Test
629    public void noAclTest1() {
630        final String agent1 = "http://xmlns.com/foaf/0.1/Agent";
631
632        when(mockNodeService.find(any(FedoraSession.class), any())).thenReturn(mockResource);
633        when(mockResource.getAcl()).thenReturn(null);
634
635        when(mockResource.getPath()).thenReturn("/");
636        when(mockResource.getTypes()).thenReturn(
637                singletonList(URI.create(REPOSITORY_NAMESPACE + "Resource")));
638        when(mockResource.getOriginalResource()).thenReturn(mockResource);
639        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
640
641        assertEquals("There should be exactly one agent", 1, roles.size());
642        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
643    }
644
645    @Test(expected = RuntimeException.class)
646    public void noAclTestMalformedRdf2() {
647
648        when(mockNodeService.find(any(FedoraSession.class), any())).thenReturn(mockResource);
649        when(mockResource.getAcl()).thenReturn(null);
650
651        when(mockResource.getPath()).thenReturn("/");
652        when(mockResource.getTypes()).thenReturn(
653                singletonList(URI.create(REPOSITORY_NAMESPACE + "Resource")));
654        when(mockResource.getOriginalResource()).thenReturn(mockResource);
655
656        System.setProperty(ROOT_AUTHORIZATION_PROPERTY, "./target/test-classes/logback-test.xml");
657        roleProvider.getRoles(mockNode);
658    }
659
660    @Test
661    public void noAclTestOkRdf3() {
662        final String agent1 = "testAdminUser";
663
664        when(mockNodeService.find(any(FedoraSession.class), any())).thenReturn(mockResource);
665        when(mockResource.getAcl()).thenReturn(null);
666        when(mockResource.getPath()).thenReturn("/");
667        when(mockResource.getTypes()).thenReturn(
668                singletonList(URI.create(REPOSITORY_NAMESPACE + "Resource")));
669
670        System.setProperty(ROOT_AUTHORIZATION_PROPERTY, "./target/test-classes/test-root-authorization.ttl");
671        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockNode);
672        System.clearProperty(ROOT_AUTHORIZATION_PROPERTY);
673
674        assertEquals("There should be exactly one agent", 1, roles.size());
675        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
676        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
677    }
678
679    private static RdfStream getRdfStreamFromResource(final String resourcePath, final Lang lang) {
680        final Model model = createDefaultModel();
681
682        RDFDataMgr.read(model, WebACRolesProviderTest.class.getResourceAsStream(resourcePath), lang);
683
684        final List<Triple> triples = new ArrayList<>();
685        model.listStatements().forEachRemaining(x -> {
686            final Triple t = x.asTriple();
687            if (t.getObject().isURI() && t.getObject().getURI().startsWith(FEDORA_URI_PREFIX)) {
688                triples.add(new Triple(t.getSubject(), t.getPredicate(),
689                        createURI(FEDORA_PREFIX + t.getObject().getURI().substring(FEDORA_URI_PREFIX.length()))));
690            } else {
691                triples.add(t);
692            }
693        });
694
695        return new DefaultRdfStream(createURI("subject"), triples.stream());
696    }
697
698}