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