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