001/*
002 * The contents of this file are subject to the license and copyright
003 * detailed in the LICENSE and NOTICE files at the root of the source
004 * tree.
005 */
006package org.fcrepo.auth.webac;
007
008import static java.util.Collections.singletonList;
009import static org.apache.jena.graph.NodeFactory.createURI;
010import static org.apache.jena.rdf.model.ModelFactory.createDefaultModel;
011import static org.apache.jena.riot.Lang.TTL;
012import static org.fcrepo.auth.webac.URIConstants.FOAF_AGENT_VALUE;
013import static org.fcrepo.auth.webac.URIConstants.VCARD_GROUP;
014import static org.fcrepo.auth.webac.URIConstants.WEBAC_MODE_READ_VALUE;
015import static org.fcrepo.auth.webac.URIConstants.WEBAC_MODE_WRITE_VALUE;
016import static org.fcrepo.kernel.api.FedoraTypes.FEDORA_ID_PREFIX;
017import static org.fcrepo.kernel.api.RdfLexicon.BASIC_CONTAINER;
018import static org.fcrepo.kernel.api.RdfLexicon.FEDORA_RESOURCE;
019import static org.junit.Assert.assertEquals;
020import static org.junit.Assert.assertNull;
021import static org.junit.Assert.assertTrue;
022import static org.mockito.Mockito.when;
023import static org.springframework.test.util.ReflectionTestUtils.setField;
024
025import java.net.URI;
026import java.nio.file.Paths;
027import java.util.ArrayList;
028import java.util.Collection;
029import java.util.List;
030import java.util.Map;
031import java.util.Optional;
032
033import org.fcrepo.config.AuthPropsConfig;
034import org.fcrepo.kernel.api.RdfStream;
035import org.fcrepo.kernel.api.Transaction;
036import org.fcrepo.kernel.api.auth.ACLHandle;
037import org.fcrepo.kernel.api.exception.PathNotFoundException;
038import org.fcrepo.kernel.api.exception.RepositoryException;
039import org.fcrepo.kernel.api.identifiers.FedoraId;
040import org.fcrepo.kernel.api.models.FedoraResource;
041import org.fcrepo.kernel.api.models.ResourceFactory;
042import org.fcrepo.kernel.api.rdf.DefaultRdfStream;
043
044import org.apache.jena.graph.Triple;
045import org.apache.jena.rdf.model.Model;
046import org.apache.jena.riot.Lang;
047import org.apache.jena.riot.RDFDataMgr;
048import org.junit.Before;
049import org.junit.Ignore;
050import org.junit.Rule;
051import org.junit.Test;
052import org.junit.contrib.java.lang.system.RestoreSystemProperties;
053import org.junit.runner.RunWith;
054import org.mockito.Mock;
055import org.mockito.junit.MockitoJUnitRunner;
056
057import com.github.benmanes.caffeine.cache.Cache;
058import com.github.benmanes.caffeine.cache.Caffeine;
059
060/**
061 * @author acoburn
062 * @since 9/3/15
063 */
064@RunWith(MockitoJUnitRunner.Silent.class)
065public class WebACRolesProviderTest {
066
067    private WebACRolesProvider roleProvider;
068
069    private static final String FEDORA_PREFIX = "info:fedora";
070    private static final String FEDORA_URI_PREFIX = "file:///rest";
071    private static final URI FEDORA_RESOURCE_URI = URI.create(FEDORA_RESOURCE.getURI());
072
073    @Mock
074    private Transaction mockTransaction;
075
076    @Mock
077    private ResourceFactory mockResourceFactory;
078
079    @Mock
080    private FedoraResource mockResource, mockParentResource;
081
082    @Mock
083    private FedoraResource mockAclResource;
084
085    @Mock
086    private FedoraResource mockAgentClassResource;
087
088    @Rule
089    public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
090
091    private AuthPropsConfig propsConfig;
092
093    private Cache<String, Optional<ACLHandle>> authHandleCache;
094
095    @Before
096    public void setUp() throws RepositoryException {
097        authHandleCache = Caffeine.newBuilder().build();
098        propsConfig = new AuthPropsConfig();
099        roleProvider = new WebACRolesProvider();
100        setField(roleProvider, "resourceFactory", mockResourceFactory);
101        setField(roleProvider, "authPropsConfig", propsConfig);
102        setField(roleProvider, "authHandleCache", authHandleCache);
103
104        when(mockResource.getDescribedResource()).thenReturn(mockResource);
105        when(mockResource.getDescription()).thenReturn(mockResource);
106
107        when(mockResource.getOriginalResource()).thenReturn(mockResource);
108        when(mockResource.getInteractionModel()).thenReturn(BASIC_CONTAINER.getURI());
109    }
110
111    private void assertOnlyDefaultAgentInRoles(final Map<String, Collection<String>> roles) {
112        assertEquals(1, roles.size());
113        assertTrue(roles.keySet().contains(FOAF_AGENT_VALUE));
114    }
115
116    @Test
117    public void noAclTest() throws RepositoryException {
118        final String accessTo = "/dark/archive/sunshine";
119
120        when(mockResource.getAcl()).thenReturn(null);
121        when(mockParentResource.getAcl()).thenReturn(null);
122
123        when(mockResource.getId()).thenReturn(accessTo);
124        when(mockResource.getContainer()).thenReturn(mockParentResource);
125        when(mockResource.getTriples())
126                .thenReturn(new DefaultRdfStream(createURI("subject")));
127        when(mockResource.getOriginalResource()).thenReturn(mockResource);
128
129        when(mockParentResource.getOriginalResource()).thenReturn(mockParentResource);
130        when(mockParentResource.getId()).thenReturn(null);
131
132        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
133
134        assertOnlyDefaultAgentInRoles(roles);
135    }
136
137    @Ignore // TODO FIX THIS TEST
138    @Test
139    public void acl01ParentTest() throws RepositoryException {
140        final String agent = "user01";
141        final String parentPath = "/webacl_box1";
142        final String accessTo = parentPath + "/foo";
143        final String acl = "/acls/01/acl.ttl";
144
145        when(mockResource.getAcl()).thenReturn(null);
146        when(mockParentResource.getAcl()).thenReturn(mockAclResource);
147
148        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
149        when(mockResource.getContainer()).thenReturn(mockParentResource);
150        when(mockResource.getOriginalResource()).thenReturn(mockResource);
151        when(mockResource.getAcl()).thenReturn(mockAclResource);
152
153        when(mockParentResource.getId()).thenReturn(addPrefix(parentPath));
154        when(mockParentResource.getAcl()).thenReturn(mockAclResource);
155        when(mockAclResource.isAcl()).thenReturn(true);
156        when(mockAclResource.getId()).thenReturn(addPrefix(parentPath) + "/fcr:acl");
157
158        when(mockAclResource.getTriples())
159                .thenReturn(getRdfStreamFromResource(acl, TTL));
160
161        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
162
163        assertEquals("There should be exactly one agent in the role map", 1, roles.size());
164        assertEquals("The agent should have exactly two modes", 2, roles.get(agent).size());
165        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
166        assertTrue("The agent should be able to write", roles.get(agent).contains(WEBAC_MODE_WRITE_VALUE));
167    }
168
169    @Test
170    public void acl21NoDefaultACLStatementTest() throws RepositoryException {
171        final String agent = "user21";
172        final String parentPath = "/resource_acl_no_inheritance";
173        final String accessTo = parentPath + "/foo";
174        final String acl = "/acls/21/acl.ttl";
175
176        when(mockResource.getAcl()).thenReturn(null);
177        when(mockParentResource.getAcl()).thenReturn(mockAclResource);
178        when(mockAclResource.hasProperty("acl:default")).thenReturn(false);
179
180        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
181        when(mockResource.getContainer()).thenReturn(mockParentResource);
182        when(mockResource.getOriginalResource()).thenReturn(mockResource);
183        when(mockResource.getAcl()).thenReturn(mockAclResource);
184
185        when(mockParentResource.getId()).thenReturn(addPrefix(parentPath));
186        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
187        when(mockParentResource.getAcl()).thenReturn(null);
188
189
190        when(mockAclResource.getTriples())
191                .thenReturn(getRdfStreamFromResource(acl, TTL));
192
193        propsConfig.setRootAuthAclPath(Paths.get("./target/test-classes/test-root-authorization2.ttl"));
194
195        // The default root ACL should be used for authorization instead of the parent ACL
196        final String rootAgent = "user06a";
197        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
198        assertEquals("Contains no agents in the role map!", 1, roles.size());
199        assertNull("Contains agent " + agent + " from ACL in parent node!", roles.get(agent));
200        assertEquals("Should have agent " + rootAgent + " from the root ACL!", 1, roles.get(rootAgent).size());
201        assertTrue("Should have read mode for agent " + rootAgent + " from the root ACL!",
202                roles.get(rootAgent).contains(WEBAC_MODE_READ_VALUE));
203    }
204
205    @Test
206    public void acl01Test1() throws RepositoryException, PathNotFoundException {
207        final String agent = "user01";
208        final String accessTo = "/webacl_box1";
209        final String acl = "/acls/01/acl.ttl";
210
211        when(mockResource.getAcl()).thenReturn(mockAclResource);
212        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(acl)))
213                .thenReturn(mockAclResource);
214        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
215        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
216        when(mockResource.getOriginalResource()).thenReturn(mockResource);
217        when(mockAclResource.getTriples())
218            .thenReturn(getRdfStreamFromResource(acl, TTL));
219        when(mockAclResource.isAcl()).thenReturn(true);
220        when(mockAclResource.getId()).thenReturn(addPrefix(accessTo) + "/fcr:acl");
221
222
223        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
224
225        assertEquals("There should be exactly one agent in the role map", 1, roles.size());
226        assertEquals("The agent should have exactly two modes", 2, roles.get(agent).size());
227        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
228        assertTrue("The agent should be able to write", roles.get(agent).contains(WEBAC_MODE_WRITE_VALUE));
229    }
230
231    @Ignore // TODO FIX THIS TEST
232    @Test
233    public void acl01Test2() throws RepositoryException, PathNotFoundException {
234        final String accessTo = "/webacl_box2";
235        final String acl = "/acls/01/acl.ttl";
236
237        when(mockResource.getAcl()).thenReturn(mockAclResource);
238        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(acl))).thenReturn(
239                mockAclResource);
240        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
241        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
242        when(mockResource.getOriginalResource()).thenReturn(mockResource);
243        when(mockAclResource.getTriples())
244            .thenReturn(getRdfStreamFromResource(acl, TTL));
245
246        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
247
248        assertOnlyDefaultAgentInRoles(roles);
249    }
250
251    @Test
252    public void acl02Test() throws RepositoryException {
253        final String agent = "Editors";
254        final String accessTo = "/box/bag/collection";
255        final String acl = "/acls/02/acl.ttl";
256
257        when(mockResource.getAcl()).thenReturn(mockAclResource);
258        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
259        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
260        when(mockAclResource.getTriples())
261            .thenReturn(getRdfStreamFromResource(acl, TTL));
262        when(mockAclResource.isAcl()).thenReturn(true);
263        when(mockAclResource.getId()).thenReturn(addPrefix(accessTo) + "/fcr:acl");
264
265        when(mockResource.getOriginalResource()).thenReturn(mockResource);
266
267
268        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
269
270        assertEquals("There should be exactly one agent in the role map", 1, roles.size());
271        assertEquals("The agent should have exactly two modes", 2, roles.get(agent).size());
272        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
273        assertTrue("The agent should be able to write", roles.get(agent).contains(WEBAC_MODE_WRITE_VALUE));
274    }
275
276    @Test
277    public void acl03Test1() throws RepositoryException, PathNotFoundException {
278        final String agent = "http://xmlns.com/foaf/0.1/Agent";
279        final String accessTo = "/dark/archive/sunshine";
280        final String acl = "/acls/03/acl.ttl";
281
282        when(mockResource.getAcl()).thenReturn(mockAclResource);
283        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(acl))).thenReturn(
284                mockAclResource);
285        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
286        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
287        when(mockResource.getOriginalResource()).thenReturn(mockResource);
288        when(mockAclResource.getTriples())
289            .thenReturn(getRdfStreamFromResource(acl, TTL));
290        when(mockAclResource.isAcl()).thenReturn(true);
291        when(mockAclResource.getId()).thenReturn(addPrefix(accessTo) + "/fcr:acl");
292
293        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
294
295        assertEquals("There should be exactly one agent in the roles map", 1, roles.size());
296        assertEquals("The agent should have exactly one mode", 1, roles.get(agent).size());
297        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
298    }
299
300    @Test
301    public void acl03Test2() throws RepositoryException, PathNotFoundException {
302        final String agent = "Restricted";
303        final String accessTo = "/dark/archive";
304        final String acl = "/acls/03/acl.ttl";
305
306        when(mockResource.getAcl()).thenReturn(mockAclResource);
307        when(mockAclResource.isAcl()).thenReturn(true);
308        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(acl))).thenReturn(
309                mockAclResource);
310        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
311        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
312        when(mockResource.getOriginalResource()).thenReturn(mockResource);
313        when(mockAclResource.getTriples())
314            .thenReturn(getRdfStreamFromResource(acl, TTL));
315
316        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
317
318        assertEquals("There should be exactly one agent", 1, roles.size());
319        assertEquals("The agent should have one mode", 1, roles.get(agent).size());
320        assertTrue("The agent should be able to read", roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
321    }
322
323    @Test
324    public void foafAgentTest() throws RepositoryException, PathNotFoundException {
325        final String agent = "http://xmlns.com/foaf/0.1/Agent";
326        final String accessTo = "/foaf-agent";
327        final String acl = "/acls/03/foaf-agent.ttl";
328
329        when(mockResource.getAcl()).thenReturn(mockAclResource);
330        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(acl)))
331                .thenReturn(mockAclResource);
332        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
333        when(mockAclResource.isAcl()).thenReturn(true);
334        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
335        when(mockResource.getOriginalResource()).thenReturn(mockResource);
336        when(mockAclResource.getTriples())
337            .thenReturn(getRdfStreamFromResource(acl, TTL));
338
339        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
340
341        assertEquals("There should be only one valid role", 1, roles.size());
342        assertEquals("The foaf:Agent should have exactly one valid mode", 1,
343                     roles.get(agent).size());
344        assertTrue("The foaf:Agent should be able to write",
345                   roles.get(agent).contains(WEBAC_MODE_READ_VALUE));
346    }
347
348    @Test
349    public void authenticatedAgentTest() throws RepositoryException, PathNotFoundException {
350        final String aclAuthenticatedAgent = "http://www.w3.org/ns/auth/acl#AuthenticatedAgent";
351        final String accessTo = "/authenticated-agent";
352        final String acl = "/acls/03/authenticated-agent.ttl";
353
354        when(mockResource.getAcl()).thenReturn(mockAclResource);
355        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(acl))).thenReturn(
356                mockAclResource);
357        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
358        when(mockAclResource.isAcl()).thenReturn(true);
359        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
360        when(mockResource.getOriginalResource()).thenReturn(mockResource);
361        when(mockAclResource.getTriples()).thenReturn(getRdfStreamFromResource(acl, TTL));
362
363        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
364
365        assertEquals("There should be only one valid role", 1, roles.size());
366        assertEquals("The acl:AuthenticatedAgent should have exactly one valid mode", 1,
367                     roles.get(aclAuthenticatedAgent).size());
368        assertTrue("The acl:AuthenticatedAgent should be able to write",
369                   roles.get(aclAuthenticatedAgent).contains(WEBAC_MODE_READ_VALUE));
370    }
371
372    @Test
373    public void acl04Test() throws RepositoryException, PathNotFoundException {
374        final String agent1 = "http://xmlns.com/foaf/0.1/Agent";
375        final String agent2 = "Editors";
376        final String accessTo = "/public_collection";
377        final String acl = "/acls/04/acl.ttl";
378
379        when(mockResource.getAcl()).thenReturn(mockAclResource);
380        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(acl))).thenReturn(
381                mockAclResource);
382        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
383        when(mockAclResource.isAcl()).thenReturn(true);
384        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
385        when(mockResource.getOriginalResource()).thenReturn(mockResource);
386        when(mockAclResource.getTriples()).thenReturn(getRdfStreamFromResource(acl, TTL));
387
388        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
389
390        assertEquals("There should be exactly two agents", 2, roles.size());
391        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
392        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
393        assertEquals("The agent should have two modes", 2, roles.get(agent2).size());
394        assertTrue("The agent should be able to read", roles.get(agent2).contains(WEBAC_MODE_READ_VALUE));
395        assertTrue("The agent should be able to write", roles.get(agent2).contains(WEBAC_MODE_READ_VALUE));
396    }
397
398    @Test
399    public void acl05Test() throws RepositoryException, PathNotFoundException {
400        final String agent1 = "http://xmlns.com/foaf/0.1/Agent";
401        final String agent2 = "Admins";
402        final String accessTo = "/mixedCollection";
403        final String acl = "/acls/05/acl.ttl";
404
405        when(mockResource.getAcl()).thenReturn(mockAclResource);
406        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(addPrefix(acl)))).thenReturn(
407                mockAclResource
408        );
409        when(mockResource.getTypes()).thenReturn(singletonList(URI.create("http://example.com/terms#publicImage")));
410        when(mockAclResource.isAcl()).thenReturn(true);
411        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
412        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
413        when(mockResource.getOriginalResource()).thenReturn(mockResource);
414        when(mockAclResource.getTriples()).thenReturn(getRdfStreamFromResource(acl, TTL));
415
416        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
417
418        assertEquals("There should be exactly two agents", 2, roles.size());
419        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
420        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
421        assertEquals("The agent should have one mode", 1, roles.get(agent2).size());
422        assertTrue("The agent should be able to read", roles.get(agent2).contains(WEBAC_MODE_READ_VALUE));
423    }
424
425    @Test
426    public void acl05Test2() throws RepositoryException, PathNotFoundException {
427        final String agent1 = "http://xmlns.com/foaf/0.1/Agent";
428        final String accessTo = "/someOtherCollection";
429        final String acl = "/acls/05/acl.ttl";
430
431        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(addPrefix(acl))))
432                .thenReturn(mockAclResource);
433        when(mockResource.getAcl()).thenReturn(mockAclResource);
434        when(mockResource.getTypes()).thenReturn(singletonList(URI.create("http://example.com/terms#publicImage")));
435        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
436        when(mockResource.getOriginalResource()).thenReturn(mockResource);
437        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
438        when(mockAclResource.isAcl()).thenReturn(true);
439        when(mockAclResource.getTriples()).thenReturn(getRdfStreamFromResource(acl, TTL));
440
441        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
442
443        assertEquals("There should be exactly one agent", 1, roles.size());
444        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
445        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
446    }
447
448    /* (non-Javadoc)
449     * Test that an in-repository resource used as a target for acl:agentGroup has
450     * the rdf:type of vcard:Group. This test mocks a vcard:Group resource and should
451     * therefore retrieve two agents.
452     */
453    @Test
454    public void acl09Test1() throws RepositoryException, PathNotFoundException {
455        final String agent1 = "person1";
456        final String accessTo = "/anotherCollection";
457
458        final String groupResource = "/group/foo";
459        final String aclDir = "/acls/09";
460        final String acl = aclDir + "/acl.ttl";
461        final String group = aclDir + "/group.ttl";
462
463        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(addPrefix(acl))))
464                .thenReturn(mockAclResource);
465        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(addPrefix(groupResource))))
466                .thenReturn(mockAgentClassResource);
467        when(mockResource.getAcl()).thenReturn(mockAclResource);
468        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
469        when(mockResource.getOriginalResource()).thenReturn(mockResource);
470        when(mockAclResource.getTriples()).thenReturn(getRdfStreamFromResource(acl, TTL));
471        when(mockAclResource.isAcl()).thenReturn(true);
472        when(mockAclResource.getId()).thenReturn(addPrefix(accessTo) + "/fcr:acl");
473
474        when(mockAgentClassResource.getTypes()).thenReturn(singletonList(VCARD_GROUP));
475        when(mockAgentClassResource.getId()).thenReturn(addPrefix(groupResource));
476        when(mockAgentClassResource.getTriples()).thenReturn(getRdfStreamFromResource(group, TTL));
477
478
479        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
480
481        assertEquals("There should be exactly two agents", 2, roles.size());
482        assertEquals("The agent should have two modes", 2, roles.get(agent1).size());
483        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
484        assertTrue("The agent should be able to write", roles.get(agent1).contains(WEBAC_MODE_WRITE_VALUE));
485    }
486
487    /* (non-Javadoc)
488     * Test that an in-repository resource used as a target for acl:agentClass has
489     * the rdf:type of foaf:Group. This test mocks a resource that is not of the type
490     * foaf:Group and therefore should retrieve zero agents.
491     */
492    @Ignore // TODO FIX THIS TEST
493    @Test
494    public void acl09Test2() throws RepositoryException, PathNotFoundException {
495        final String accessTo = "/anotherCollection";
496
497        final String groupResource = "/group/foo";
498        final String acl = "/acls/09/acl.ttl";
499        final String group = "/acls/09/group.ttl";
500
501        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(addPrefix(acl)))).thenReturn(
502                mockAclResource);
503        when(mockResourceFactory.getResource(mockTransaction,
504                FedoraId.create(addPrefix(groupResource)))).thenReturn(mockAgentClassResource);
505        when(mockResource.getAcl()).thenReturn(mockAclResource);
506        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
507        when(mockResource.getOriginalResource()).thenReturn(mockResource);
508        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
509        when(mockAclResource.getTriples()).thenReturn(getRdfStreamFromResource(acl, TTL));
510
511        when(mockAgentClassResource.getTypes()).thenReturn(new ArrayList<>());
512        when(mockAgentClassResource.getId()).thenReturn(addPrefix(groupResource));
513        when(mockAgentClassResource.getTriples())
514            .thenReturn(getRdfStreamFromResource(group, TTL));
515
516        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
517
518        assertOnlyDefaultAgentInRoles(roles);
519    }
520
521    @Test
522    public void acl17Test1() throws RepositoryException, PathNotFoundException {
523        final String foafAgent = "http://xmlns.com/foaf/0.1/Agent";
524        final String accessTo = "/dark/archive/sunshine";
525        final String acl = "/acls/17/acl.ttl";
526
527        when(mockResource.getAcl()).thenReturn(mockAclResource);
528        when(mockResourceFactory.getResource(mockTransaction, FedoraId.create(addPrefix(acl))))
529                .thenReturn(mockAclResource);
530        when(mockAclResource.getId()).thenReturn(addPrefix(acl));
531        when(mockAclResource.isAcl()).thenReturn(true);
532        when(mockResource.getId()).thenReturn(addPrefix(accessTo));
533        when(mockResource.getOriginalResource()).thenReturn(mockResource);
534        when(mockAclResource.getTriples())
535            .thenReturn(getRdfStreamFromResource(acl, TTL));
536
537        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
538
539        assertEquals("There should be only one valid role", 1, roles.size());
540        assertEquals("The foafAgent should have exactly one valid mode", 1, roles.get(foafAgent).size());
541        assertTrue("The foafAgent should be able to write", roles.get(foafAgent).contains(WEBAC_MODE_WRITE_VALUE));
542    }
543
544    @Test
545    public void noAclTest1() {
546        final String agent1 = "http://xmlns.com/foaf/0.1/Agent";
547
548        when(mockResource.getAcl()).thenReturn(null);
549
550        when(mockResource.getId()).thenReturn(FEDORA_ID_PREFIX);
551        when(mockResource.getTypes()).thenReturn(
552                singletonList(FEDORA_RESOURCE_URI));
553        when(mockResource.getOriginalResource()).thenReturn(mockResource);
554        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
555
556        assertEquals("There should be exactly one agent", 1, roles.size());
557        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
558    }
559
560    @Test(expected = RuntimeException.class)
561    public void noAclTestMalformedRdf2() {
562
563        when(mockResource.getAcl()).thenReturn(null);
564
565        when(mockResource.getId()).thenReturn(FEDORA_ID_PREFIX);
566        when(mockResource.getTypes()).thenReturn(
567                singletonList(FEDORA_RESOURCE_URI));
568        when(mockResource.getOriginalResource()).thenReturn(mockResource);
569
570        propsConfig.setRootAuthAclPath(Paths.get("./target/test-classes/logback-test.xml"));
571        roleProvider.getRoles(mockResource, mockTransaction);
572    }
573
574    @Test
575    public void noAclTestOkRdf3() {
576        final String agent1 = "testAdminUser";
577
578        when(mockResource.getAcl()).thenReturn(null);
579        when(mockResource.getId()).thenReturn(FEDORA_ID_PREFIX);
580        when(mockResource.getTypes()).thenReturn(
581                singletonList(FEDORA_RESOURCE_URI));
582
583        propsConfig.setRootAuthAclPath(Paths.get("./target/test-classes/test-root-authorization.ttl"));
584        final Map<String, Collection<String>> roles = roleProvider.getRoles(mockResource, mockTransaction);
585
586        assertEquals("There should be exactly one agent", 1, roles.size());
587        assertEquals("The agent should have one mode", 1, roles.get(agent1).size());
588        assertTrue("The agent should be able to read", roles.get(agent1).contains(WEBAC_MODE_READ_VALUE));
589    }
590
591    private static RdfStream getRdfStreamFromResource(final String resourcePath, final Lang lang) {
592        final Model model = createDefaultModel();
593
594        RDFDataMgr.read(model, WebACRolesProviderTest.class.getResourceAsStream(resourcePath), lang);
595
596        final List<Triple> triples = new ArrayList<>();
597        model.listStatements().forEachRemaining(x -> {
598            final Triple t = x.asTriple();
599            if (t.getObject().isURI() && t.getObject().getURI().startsWith(FEDORA_URI_PREFIX)) {
600                triples.add(new Triple(t.getSubject(), t.getPredicate(),
601                        createURI(FEDORA_PREFIX + t.getObject().getURI().substring(FEDORA_URI_PREFIX.length()))));
602            } else {
603                triples.add(t);
604            }
605        });
606
607        return new DefaultRdfStream(createURI("subject"), triples.stream());
608    }
609
610    private String addPrefix(final String id) {
611        final String cleanId = id.replaceFirst("^/", "");
612        if (!cleanId.startsWith(FEDORA_ID_PREFIX)) {
613            return FEDORA_ID_PREFIX + "/" + cleanId;
614        }
615        return cleanId;
616    }
617
618}