Commit 8b5f7fed authored by Maxym Borodenko's avatar Maxym Borodenko Committed by Matija Obreza

KPI Executions ACL

parent f1c534b1
......@@ -16,10 +16,7 @@
package org.genesys2.server.api.v1;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
......@@ -79,7 +76,7 @@ public class KPIReadController {
ArrayNode l=objectMapper.createArrayNode();
kpiService.filterObservations(executionName, date, keys).forEach(observation -> {
l.add(toMap(observation));
});;
});
return l;
}
......
/**
* Copyright 2014 Global Crop Diversity Trust
*
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
......@@ -38,6 +38,7 @@ import javax.validation.constraints.Size;
import org.genesys.blocks.model.AuditedVersionedModel;
import org.genesys.blocks.model.SelfCleaning;
import org.genesys.blocks.security.model.AclAwareModel;
import com.fasterxml.jackson.annotation.JsonIgnore;
......@@ -49,7 +50,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/
@Entity
@Table(name = "kpiexecution")
public class Execution extends AuditedVersionedModel implements SelfCleaning {
public class Execution extends AuditedVersionedModel implements SelfCleaning, AclAwareModel {
/**
*
......
/**
* Copyright 2014 Global Crop Diversity Trust
*
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
*/
package org.genesys2.server.service.impl;
import static org.genesys2.server.model.kpi.QDimensionKey.dimensionKey;
import static org.genesys2.server.model.kpi.QExecution.execution;
import static org.genesys2.server.model.kpi.QExecutionRun.executionRun;
import static org.genesys2.server.model.kpi.QObservation.observation;
......@@ -27,6 +28,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
......@@ -39,6 +41,7 @@ import javax.validation.Valid;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.genesys2.server.model.UserRole;
import org.genesys2.server.model.kpi.Dimension;
import org.genesys2.server.model.kpi.DimensionKey;
import org.genesys2.server.model.kpi.Execution;
......@@ -53,14 +56,18 @@ import org.genesys2.server.persistence.kpi.ExecutionRepository;
import org.genesys2.server.persistence.kpi.ExecutionRunRepository;
import org.genesys2.server.persistence.kpi.KPIParameterRepository;
import org.genesys2.server.persistence.kpi.ObservationRepository;
import org.genesys2.server.security.SecurityUtils;
import org.genesys2.server.service.KPIService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
......@@ -95,6 +102,10 @@ public class KPIServiceImpl implements KPIService {
@Autowired
private ExecutionRunRepository executionRunRepository;
/** The securityUtils. */
@Autowired
private SecurityUtils securityUtils;
@Autowired
private JPAQueryFactory jpaQueryFactory;
......@@ -167,24 +178,27 @@ public class KPIServiceImpl implements KPIService {
return dimensionRepository.findAll(page);
}
@PostAuthorize("hasRole('ADMINISTRATOR') || returnObject==null || hasPermission(returnObject, 'READ')")
@Override
public Execution getExecution(long id) {
return lazyLoad(executionRepository.findOne(id));
}
@PostAuthorize("hasRole('ADMINISTRATOR') || returnObject==null || hasPermission(returnObject, 'READ')")
@Override
public Execution getExecution(String executionName) {
return lazyLoad(executionRepository.findByName(executionName));
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION') or hasPermission(#execution, 'READ')")
public ExecutionRun findLastExecutionRun(Execution execution) {
List<ExecutionRun> l = executionRunRepository.findLast(execution, new PageRequest(0, 1));
ExecutionRun lastRun = l.size() == 1 ? l.get(0) : null;
return lazyLoad(lastRun);
}
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION')")
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION') or hasPermission(#execution, 'WRITE')")
@Override
@Transactional
public Execution save(@Valid Execution execution) {
......@@ -199,10 +213,18 @@ public class KPIServiceImpl implements KPIService {
@Override
public Page<Execution> listExecutions(Pageable page) {
return executionRepository.findAll(page);
if (securityUtils.hasRole(UserRole.ADMINISTRATOR)) {
return executionRepository.findAll(page);
}
Set<Long> executionIds = new HashSet<>(securityUtils.listObjectIdentityIdsForCurrentUser(Execution.class, BasePermission.READ));
JPAQuery<Execution> query = jpaQueryFactory.selectFrom(execution).where(execution.id.in(executionIds));
long total = query.fetchCount();
List<Execution> content = query.offset(page.getOffset()).limit(page.getPageSize()).fetch();
return new PageImpl<>(content, page, total);
}
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION')")
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION') or hasPermission(#execution, 'DELETE')")
@Override
@Transactional
public Execution delete(Execution execution) {
......@@ -214,7 +236,7 @@ public class KPIServiceImpl implements KPIService {
return execution;
}
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION')")
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#executionRun.execution, 'ADMINISTRATION') or hasPermission(#executionRun.execution, 'DELETE')")
@Override
@Transactional
public void deleteObservations(ExecutionRun executionRun) {
......@@ -306,7 +328,7 @@ public class KPIServiceImpl implements KPIService {
}
// readonly mode
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION')")
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION') or hasPermission(#execution, 'READ')")
@Override
public List<Observation> execute(Execution execution) {
List<Observation> results = new ArrayList<Observation>();
......@@ -319,7 +341,7 @@ public class KPIServiceImpl implements KPIService {
return results;
}
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION')")
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'ADMINISTRATION') or hasPermission(#execution, 'WRITE')")
@Override
@Transactional
public ExecutionRun executeAndSave(Execution execution) {
......@@ -495,6 +517,7 @@ public class KPIServiceImpl implements KPIService {
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#executionRun.execution, 'READ')")
public Page<Observation> listObservations(ExecutionRun executionRun, Map<String, String> dimensionFilters, Pageable page) {
Page<Observation> res = null;
if (dimensionFilters == null || dimensionFilters.isEmpty()) {
......@@ -514,6 +537,7 @@ public class KPIServiceImpl implements KPIService {
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'READ')")
public Page<Observation> listObservations(Execution execution, long dimensionKeyId, Pageable pageable) {
DimensionKey dk = dimensionKeyRepository.findOne(dimensionKeyId);
Page<Observation> res = observationRepository.listObservationsByDimensionKey(execution, dk, pageable);
......@@ -532,7 +556,12 @@ public class KPIServiceImpl implements KPIService {
executionQuery.where(executionRun.execution.name.eq(executionName).and(executionRun.timestamp.before(date)));
executionQuery.orderBy(executionRun.timestamp.desc());
ExecutionRun executionRun = executionQuery.fetchFirst();
if (executionRun == null) {
boolean withoutRights = false;
if (!securityUtils.hasRole(UserRole.ADMINISTRATOR)) {
Set<Long> executionIds = new HashSet<>(securityUtils.listObjectIdentityIdsForCurrentUser(Execution.class, BasePermission.READ));
withoutRights = executionIds.stream().noneMatch(id -> Objects.equals(executionRun.getExecution().getId(), id));
}
if (executionRun == null || withoutRights) {
return Collections.emptyList();
}
......@@ -566,11 +595,13 @@ public class KPIServiceImpl implements KPIService {
}
@Override
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#execution, 'READ')")
public List<ExecutionRun> listExecutionRuns(Execution execution, Pageable pageable) {
return executionRunRepository.findLast(execution, pageable);
}
@Override
@PostAuthorize("hasRole('ADMINISTRATOR') or hasPermission(returnObject.execution, 'READ')")
public ExecutionRun getExecutionRun(long runId) {
return lazyLoad(executionRunRepository.findOne(runId));
}
......
/*
* Copyright 2018 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.genesys.test.server.api.v1;
import static org.hamcrest.Matchers.*;
......@@ -32,6 +48,7 @@ import org.genesys2.server.service.KPIService;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.annotation.JsonInclude;
......@@ -106,6 +123,7 @@ public class KPIReadControllerTest extends AbstractApiTest {
}
@Test
@WithMockUser(username = "user", password = "user", roles = "ADMINISTRATOR")
public void testList() throws Exception {
ExecutionRun executionRun = buildAndSave("institute.count");
assertThat(executionRun.getExecution().getName(), is("institute.count"));
......@@ -118,6 +136,7 @@ public class KPIReadControllerTest extends AbstractApiTest {
}
@Test
@WithMockUser(username = "user", password = "user", roles = "ADMINISTRATOR")
public void testFilterObservations() throws Exception {
ExecutionRun executionRun = buildAndSave("institute.count");
assertThat(executionRun.getObservations().size(), is(10));
......@@ -139,6 +158,7 @@ public class KPIReadControllerTest extends AbstractApiTest {
}
@Test
@WithMockUser(username = "user", password = "user", roles = "ADMINISTRATOR")
public void testEmptyListIfNotFound() throws Exception {
ExecutionRun executionRun = buildAndSave("institute.count");
LocalDateTime ldt = LocalDateTime.now().plusMonths(-10);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment