package org.molgenis.data;
import org.mockito.ArgumentCaptor;
import org.molgenis.data.aggregation.AggregateQuery;
import org.molgenis.data.aggregation.AggregateResult;
import org.molgenis.data.meta.model.EntityType;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import static org.mockito.Mockito.*;
import static org.testng.Assert.assertEquals;
public class RepositorySecurityDecoratorTest
{
private String entityName;
private Repository<Entity> decoratedRepository;
private RepositorySecurityDecorator repositorySecurityDecorator;
@SuppressWarnings("unchecked")
@BeforeMethod
public void setUp()
{
entityName = "entity";
EntityType entityType = mock(EntityType.class);
when(entityType.getName()).thenReturn(entityName);
decoratedRepository = mock(Repository.class);
when(decoratedRepository.getName()).thenReturn(entityName);
when(decoratedRepository.getEntityType()).thenReturn(entityType);
repositorySecurityDecorator = new RepositorySecurityDecorator(decoratedRepository);
}
@Test
public void addStream()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_WRITE_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Stream<Entity> entities = Stream.empty();
when(decoratedRepository.add(entities)).thenReturn(123);
assertEquals(repositorySecurityDecorator.add(entities), Integer.valueOf(123));
}
@Test(expectedExceptions = MolgenisDataAccessException.class)
public void addStreamNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_READ_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Stream<Entity> entities = Stream.empty();
try
{
repositorySecurityDecorator.add(entities);
}
catch (MolgenisDataAccessException e)
{
verify(decoratedRepository, times(1)).getName();
verifyNoMoreInteractions(decoratedRepository);
throw e;
}
}
@Test
public void findAllPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_READ_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Stream<Object> ids = Stream.of(0, 1);
Fetch fetch = new Fetch();
Entity entity0 = mock(Entity.class);
Entity entity1 = mock(Entity.class);
Stream<Entity> entities = Stream.of(entity0, entity1);
when(decoratedRepository.findAll(ids, fetch)).thenReturn(Stream.of(entity0, entity1));
assertEquals(entities.collect(toList()), repositorySecurityDecorator.findAll(ids, fetch).collect(toList()));
verify(decoratedRepository, times(1)).findAll(ids, fetch);
}
@Test
public void deleteStream()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_WRITE_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Stream<Entity> entities = Stream.empty();
repositorySecurityDecorator.delete(entities);
verify(decoratedRepository, times(1)).delete(entities);
}
@Test(expectedExceptions = MolgenisDataAccessException.class)
public void deleteStreamNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_READ_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Stream<Entity> entities = Stream.empty();
try
{
repositorySecurityDecorator.delete(entities);
}
catch (MolgenisDataAccessException e)
{
verify(decoratedRepository, times(1)).getName();
verifyNoMoreInteractions(decoratedRepository);
throw e;
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void updateStream()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_WRITE_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Entity entity0 = mock(Entity.class);
Stream<Entity> entities = Stream.of(entity0);
ArgumentCaptor<Stream<Entity>> captor = ArgumentCaptor.forClass((Class) Stream.class);
doNothing().when(decoratedRepository).update(captor.capture());
repositorySecurityDecorator.update(entities);
assertEquals(captor.getValue().collect(Collectors.toList()), singletonList(entity0));
}
@Test(expectedExceptions = MolgenisDataAccessException.class)
public void updateStreamNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_READ_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Stream<Entity> entities = Stream.empty();
try
{
repositorySecurityDecorator.update(entities);
}
catch (MolgenisDataAccessException e)
{
verify(decoratedRepository, times(1)).getName();
verifyNoMoreInteractions(decoratedRepository);
throw e;
}
}
@Test
public void findAllStream()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_READ_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Object id0 = "id0";
Object id1 = "id1";
Entity entity0 = mock(Entity.class);
Entity entity1 = mock(Entity.class);
Stream<Object> entityIds = Stream.of(id0, id1);
when(decoratedRepository.findAll(entityIds)).thenReturn(Stream.of(entity0, entity1));
Stream<Entity> expectedEntities = repositorySecurityDecorator.findAll(entityIds);
assertEquals(expectedEntities.collect(Collectors.toList()), Arrays.asList(entity0, entity1));
}
@Test(expectedExceptions = MolgenisDataAccessException.class)
public void findAllStreamNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Object id0 = "id0";
Object id1 = "id1";
Entity entity0 = mock(Entity.class);
Entity entity1 = mock(Entity.class);
Stream<Object> entityIds = Stream.of(id0, id1);
when(decoratedRepository.findAll(entityIds)).thenReturn(Stream.of(entity0, entity1));
repositorySecurityDecorator.findAll(entityIds);
}
@Test
public void findAllStreamFetch()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_READ_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Fetch fetch = new Fetch();
Object id0 = "id0";
Object id1 = "id1";
Entity entity0 = mock(Entity.class);
Entity entity1 = mock(Entity.class);
Stream<Object> entityIds = Stream.of(id0, id1);
when(decoratedRepository.findAll(entityIds, fetch)).thenReturn(Stream.of(entity0, entity1));
Stream<Entity> expectedEntities = repositorySecurityDecorator.findAll(entityIds, fetch);
assertEquals(expectedEntities.collect(Collectors.toList()), Arrays.asList(entity0, entity1));
}
@Test(expectedExceptions = MolgenisDataAccessException.class)
public void findAllStreamFetchNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Fetch fetch = new Fetch();
Object id0 = "id0";
Object id1 = "id1";
Entity entity0 = mock(Entity.class);
Entity entity1 = mock(Entity.class);
Stream<Object> entityIds = Stream.of(id0, id1);
when(decoratedRepository.findAll(entityIds, fetch)).thenReturn(Stream.of(entity0, entity1));
repositorySecurityDecorator.findAll(entityIds, fetch);
}
@Test(expectedExceptions = MolgenisDataAccessException.class)
public void findAllNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Stream<Object> ids = Stream.of(0, 1);
Fetch fetch = new Fetch();
Stream<Entity> entities = Stream.of(mock(Entity.class), mock(Entity.class));
when(decoratedRepository.findAll(ids, fetch)).thenReturn(entities);
repositorySecurityDecorator.findAll(ids, fetch);
}
@Test
public void findOnePermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_READ_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Object id = 0;
Fetch fetch = new Fetch();
Entity entity = mock(Entity.class);
when(decoratedRepository.findOneById(id, fetch)).thenReturn(entity);
assertEquals(entity, decoratedRepository.findOneById(id, fetch));
verify(decoratedRepository, times(1)).findOneById(id, fetch);
}
@Test(expectedExceptions = MolgenisDataAccessException.class)
public void findOneNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Object id = 0;
Fetch fetch = new Fetch();
Entity entity = mock(Entity.class);
when(decoratedRepository.findOneById(id, fetch)).thenReturn(entity);
repositorySecurityDecorator.findOneById(id, fetch);
}
@Test
public void findAllAsStreamPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_READ_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Entity entity0 = mock(Entity.class);
@SuppressWarnings("unchecked")
Query<Entity> query = mock(Query.class);
when(decoratedRepository.findAll(query)).thenReturn(Stream.of(entity0));
Stream<Entity> entities = repositorySecurityDecorator.findAll(query);
assertEquals(entities.collect(Collectors.toList()), singletonList(entity0));
}
@Test(expectedExceptions = MolgenisDataAccessException.class)
public void findAllAsStreamNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Entity entity0 = mock(Entity.class);
@SuppressWarnings("unchecked")
Query<Entity> query = mock(Query.class);
when(decoratedRepository.findAll(query)).thenReturn(Stream.of(entity0));
Stream<Entity> entities = repositorySecurityDecorator.findAll(query);
assertEquals(entities.collect(Collectors.toList()), singletonList(entity0));
}
@Test
public void streamFetch()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_READ_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Fetch fetch = new Fetch();
@SuppressWarnings("unchecked")
Consumer<List<Entity>> consumer = mock(Consumer.class);
repositorySecurityDecorator.forEachBatched(fetch, consumer, 1000);
verify(decoratedRepository).forEachBatched(fetch, consumer, 1000);
}
@Test(expectedExceptions = MolgenisDataAccessException.class)
public void streamFetchNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
Fetch fetch = new Fetch();
@SuppressWarnings("unchecked")
Consumer<List<Entity>> consumer = mock(Consumer.class);
repositorySecurityDecorator.forEachBatched(fetch, consumer, 1000);
verifyZeroInteractions(decoratedRepository);
}
@Test
public void aggregate()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null,
"ROLE_ENTITY_COUNT_" + entityName);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
AggregateQuery aggregateQuery = mock(AggregateQuery.class);
AggregateResult aggregateResult = mock(AggregateResult.class);
when(repositorySecurityDecorator.aggregate(aggregateQuery)).thenReturn(aggregateResult);
assertEquals(aggregateResult, repositorySecurityDecorator.aggregate(aggregateQuery));
}
@Test(expectedExceptions = MolgenisDataAccessException.class, expectedExceptionsMessageRegExp = "No \\[COUNT\\] permission on entity \\[entity\\]")
public void aggregateNoPermission()
{
TestingAuthenticationToken authentication = new TestingAuthenticationToken("username", null);
authentication.setAuthenticated(false);
SecurityContextHolder.getContext().setAuthentication(authentication);
AggregateQuery aggregateQuery = mock(AggregateQuery.class);
repositorySecurityDecorator.aggregate(aggregateQuery);
}
}