Merge branch 'master' into fix-set-db-read-uncommited
Conflicts: hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java Signed-off-by: Kai Zimmermann <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -18,8 +18,11 @@ import org.eclipse.hawkbit.repository.model.helper.AfterTransactionCommitExecuto
|
||||
import org.eclipse.hawkbit.repository.model.helper.CacheManagerHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SecurityTokenGeneratorHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantAwareHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
|
||||
@@ -48,14 +51,24 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
|
||||
@EnableAutoConfiguration
|
||||
public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* @return the {@link SystemSecurityContext} singleton bean which make it
|
||||
* accessible in beans which cannot access the service directly,
|
||||
* e.g. JPA entities.
|
||||
*/
|
||||
@Bean
|
||||
public SystemSecurityContextHolder systemSecurityContextHolder() {
|
||||
return SystemSecurityContextHolder.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TenantConfigurationManagement} singleton bean which
|
||||
* make it accessible in beans which cannot access the service
|
||||
* directly, e.g. JPA entities.
|
||||
*/
|
||||
@Bean
|
||||
public TenantConfigurationManagement tenantConfigurationManagement() {
|
||||
return TenantConfigurationManagement.getInstance();
|
||||
public TenantConfigurationManagementHolder tenantConfigurationManagementHolder() {
|
||||
return TenantConfigurationManagementHolder.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -90,6 +90,8 @@ public class ExceptionMappingAspectHandler implements Ordered {
|
||||
+ " || execution( * org.eclipse.hawkbit.controller.*.*(..)) "
|
||||
+ " || execution( * org.eclipse.hawkbit.rest.resource.*.*(..)) "
|
||||
+ " || execution( * org.eclipse.hawkbit.service.*.*(..)) )", throwing = "ex")
|
||||
// Exception squid:S00112 - Is aspectJ proxy
|
||||
@SuppressWarnings({ "squid:S00112" })
|
||||
public void catchAndWrapJpaExceptionsService(final Exception ex) throws Throwable {
|
||||
LOG.trace("exception occured", ex);
|
||||
Exception translatedAccessException = translateEclipseLinkExceptionIfPossible(ex);
|
||||
|
||||
@@ -20,9 +20,9 @@ import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent;
|
||||
import org.eclipse.hawkbit.eventbus.event.TargetInfoUpdateEvent;
|
||||
import org.eclipse.hawkbit.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -67,6 +67,8 @@ public class EntityChangeEventListener {
|
||||
* {@link ProceedingJoinPoint#proceed()}
|
||||
*/
|
||||
@Around("execution(* org.eclipse.hawkbit.repository.TargetInfoRepository.save(..))")
|
||||
// Exception squid:S00112 - Is aspectJ proxy
|
||||
@SuppressWarnings({ "squid:S00112" })
|
||||
public Object targetCreated(final ProceedingJoinPoint joinpoint) throws Throwable {
|
||||
final boolean isNew = isTargetInfoNew(joinpoint.getArgs()[0]);
|
||||
final Object result = joinpoint.proceed();
|
||||
@@ -92,6 +94,8 @@ public class EntityChangeEventListener {
|
||||
* {@link ProceedingJoinPoint#proceed()}
|
||||
*/
|
||||
@Around("execution(* org.eclipse.hawkbit.repository.TargetRepository.deleteByIdIn(..))")
|
||||
// Exception squid:S00112 - Is aspectJ proxy
|
||||
@SuppressWarnings({ "squid:S00112" })
|
||||
public Object targetDeletedById(final ProceedingJoinPoint joinpoint) throws Throwable {
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
final Object result = joinpoint.proceed();
|
||||
@@ -111,8 +115,9 @@ public class EntityChangeEventListener {
|
||||
* in case exception happens in the
|
||||
* {@link ProceedingJoinPoint#proceed()}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Around("execution(* org.eclipse.hawkbit.repository.TargetRepository.delete(..))")
|
||||
// Exception squid:S00112 - Is aspectJ proxy
|
||||
@SuppressWarnings({ "squid:S00112", "unchecked" })
|
||||
public Object targetDeleted(final ProceedingJoinPoint joinpoint) throws Throwable {
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
final Object result = joinpoint.proceed();
|
||||
|
||||
@@ -29,6 +29,8 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn
|
||||
private static final ThreadLocal<List<Runnable>> THREAD_LOCAL_RUNNABLES = new ThreadLocal<>();
|
||||
|
||||
@Override
|
||||
// Exception squid:S1217 - Is aspectJ proxy
|
||||
@SuppressWarnings({ "squid:S1217" })
|
||||
public void afterCommit() {
|
||||
final List<Runnable> afterCommitRunnables = THREAD_LOCAL_RUNNABLES.get();
|
||||
LOGGER.debug("Transaction successfully committed, executing {} runnables", afterCommitRunnables.size());
|
||||
@@ -60,6 +62,7 @@ public class AfterTransactionCommitDefaultServiceExecutor extends TransactionSyn
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "squid:S1217" })
|
||||
public void afterCompletion(final int status) {
|
||||
final String transactionStatus = status == STATUS_COMMITTED ? "COMMITTED" : "ROLLEDBACK";
|
||||
LOGGER.debug("Transaction completed after commit with status {}", transactionStatus);
|
||||
|
||||
@@ -199,6 +199,9 @@ public class DeploymentManagement {
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
|
||||
@CacheEvict(value = { "distributionUsageAssigned" }, allEntries = true)
|
||||
// Exception squid:S2095: see
|
||||
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
||||
@SuppressWarnings({ "squid:S2095" })
|
||||
public DistributionSetAssignmentResult assignDistributionSet(@NotNull final Long dsID, final ActionType actionType,
|
||||
final long forcedTimestamp, @NotEmpty final String... targetIDs) {
|
||||
return assignDistributionSet(dsID, Arrays.stream(targetIDs)
|
||||
|
||||
@@ -342,6 +342,8 @@ public class SystemManagement {
|
||||
*/
|
||||
private class CurrentTenantKeyGenerator implements KeyGenerator {
|
||||
@Override
|
||||
// Exception squid:S923 - override
|
||||
@SuppressWarnings({ "squid:S923" })
|
||||
public Object generate(final Object target, final Method method, final Object... params) {
|
||||
final String initialTenantCreation = createInitialTenant.get();
|
||||
if (initialTenantCreation == null) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -33,10 +34,9 @@ import org.springframework.validation.annotation.Validated;
|
||||
*/
|
||||
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
|
||||
@Validated
|
||||
@Service
|
||||
public class TenantConfigurationManagement implements EnvironmentAware {
|
||||
|
||||
private static final TenantConfigurationManagement INSTANCE = new TenantConfigurationManagement();
|
||||
|
||||
@Autowired
|
||||
private TenantConfigurationRepository tenantConfigurationRepository;
|
||||
|
||||
@@ -47,16 +47,6 @@ public class TenantConfigurationManagement implements EnvironmentAware {
|
||||
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* Get Singleton instance, needed for classes which are not managed in
|
||||
* Spring context
|
||||
*
|
||||
* @return singleton instance of TenantConfigurationManagement
|
||||
*/
|
||||
public static TenantConfigurationManagement getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a configuration value from the e.g. tenant overwritten
|
||||
* configuration values or in case the tenant does not a have a specific
|
||||
@@ -161,7 +151,8 @@ public class TenantConfigurationManagement implements EnvironmentAware {
|
||||
* if the property cannot be converted to the given
|
||||
* {@code propertyType}
|
||||
*/
|
||||
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
|
||||
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_SYSTEM_CODE)
|
||||
public TenantConfigurationValue<?> getConfigurationValue(final TenantConfigurationKey configurationKey) {
|
||||
return getConfigurationValue(configurationKey, configurationKey.getDataType());
|
||||
}
|
||||
@@ -186,7 +177,8 @@ public class TenantConfigurationManagement implements EnvironmentAware {
|
||||
* if the property cannot be converted to the given
|
||||
* {@code propertyType}
|
||||
*/
|
||||
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
|
||||
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_SYSTEM_CODE)
|
||||
public <T> T getGlobalConfigurationValue(final TenantConfigurationKey configurationKey,
|
||||
final Class<T> propertyType) {
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||
@@ -245,18 +246,21 @@ public class TargetInfo implements Persistable<Long>, Serializable {
|
||||
if (lastTargetQuery == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagement.getInstance()
|
||||
.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue());
|
||||
final Duration overdueTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagement
|
||||
.getInstance().getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)
|
||||
.getValue());
|
||||
final LocalDateTime currentDate = LocalDateTime.now();
|
||||
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery),
|
||||
ZoneId.systemDefault());
|
||||
final LocalDateTime nextPollDate = lastPollDate.plus(pollTime);
|
||||
final LocalDateTime overdueDate = nextPollDate.plus(overdueTime);
|
||||
return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate);
|
||||
return SystemSecurityContextHolder.getInstance().getSystemSecurityContext().runAsSystem(() -> {
|
||||
final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagementHolder
|
||||
.getInstance().getTenantConfigurationManagement()
|
||||
.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue());
|
||||
final Duration overdueTime = DurationHelper.formattedStringToDuration(
|
||||
TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement()
|
||||
.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)
|
||||
.getValue());
|
||||
final LocalDateTime currentDate = LocalDateTime.now();
|
||||
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery),
|
||||
ZoneId.systemDefault());
|
||||
final LocalDateTime nextPollDate = lastPollDate.plus(pollTime);
|
||||
final LocalDateTime overdueDate = nextPollDate.plus(overdueTime);
|
||||
return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.model.helper;
|
||||
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* A singleton bean which holds {@link SystemSecurityContext} service and makes
|
||||
* it accessible to beans which are not managed by spring, e.g. JPA entities.
|
||||
*/
|
||||
public final class SystemSecurityContextHolder {
|
||||
|
||||
private static final SystemSecurityContextHolder INSTANCE = new SystemSecurityContextHolder();
|
||||
|
||||
@Autowired
|
||||
private SystemSecurityContext systemSecurityContext;
|
||||
|
||||
private SystemSecurityContextHolder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the singleton {@link SystemSecurityContextHolder} instance
|
||||
*/
|
||||
public static SystemSecurityContextHolder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link SystemSecurityContext} service
|
||||
*/
|
||||
public SystemSecurityContext getSystemSecurityContext() {
|
||||
return systemSecurityContext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.model.helper;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* A singleton bean which holds {@link TenantConfigurationManagement} service
|
||||
* and makes it accessible to beans which are not managed by spring, e.g. JPA
|
||||
* entities.
|
||||
*/
|
||||
public final class TenantConfigurationManagementHolder {
|
||||
|
||||
private static final TenantConfigurationManagementHolder INSTANCE = new TenantConfigurationManagementHolder();
|
||||
|
||||
@Autowired
|
||||
private TenantConfigurationManagement tenantConfiguration;
|
||||
|
||||
private TenantConfigurationManagementHolder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the singleton {@link TenantConfigurationManagementHolder}
|
||||
* instance
|
||||
*/
|
||||
public static TenantConfigurationManagementHolder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TenantConfigurationManagement} service
|
||||
*/
|
||||
public TenantConfigurationManagement getTenantConfigurationManagement() {
|
||||
return tenantConfiguration;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,10 +66,6 @@ import cz.jirutka.rsql.parser.ast.RSQLVisitor;
|
||||
* <li>name==targetId1,description==plugAndPlay,updateStatus==UNKNOWN</li>
|
||||
* <li>name==targetId1 or description==plugAndPlay or updateStatus==UNKNOWN</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class RSQLUtility {
|
||||
|
||||
@@ -279,6 +275,9 @@ public final class RSQLUtility {
|
||||
}
|
||||
|
||||
@Override
|
||||
// Exception squid:S2095 - see
|
||||
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
||||
@SuppressWarnings({ "squid:S2095" })
|
||||
public List<Predicate> visit(final ComparisonNode node, final String param) {
|
||||
A fieldName = null;
|
||||
try {
|
||||
@@ -304,6 +303,9 @@ public final class RSQLUtility {
|
||||
return mapToPredicate(node, fieldPath, node.getArguments(), transformedValue, fieldName);
|
||||
}
|
||||
|
||||
// Exception squid:S2095 - see
|
||||
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
||||
@SuppressWarnings({ "squid:S2095" })
|
||||
private List<String> getExpectedFieldList() {
|
||||
final List<String> expectedFieldList = Arrays.stream(enumType.getEnumConstants())
|
||||
.filter(enumField -> enumField.getSubEntityAttributes().isEmpty()).map(enumField -> {
|
||||
@@ -390,7 +392,9 @@ public final class RSQLUtility {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
// Exception squid:S2095 - see
|
||||
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
||||
@SuppressWarnings({ "rawtypes", "unchecked", "squid:S2095" })
|
||||
private Object transformEnumValue(final ComparisonNode node, final String value,
|
||||
final Class<? extends Object> javaType) {
|
||||
final Class<? extends Enum> tmpEnumType = (Class<? extends Enum>) javaType;
|
||||
|
||||
@@ -14,6 +14,7 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -29,6 +30,7 @@ import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.eclipse.hawkbit.AbstractIntegrationTest;
|
||||
import org.eclipse.hawkbit.TestDataUtil;
|
||||
import org.eclipse.hawkbit.WithSpringAuthorityRule;
|
||||
import org.eclipse.hawkbit.WithUser;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
|
||||
@@ -724,4 +726,20 @@ public class TargetManagementTest extends AbstractIntegrationTest {
|
||||
assertThat(25).as("Targets with no tag").isEqualTo(targetsListWithNoTag.size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests the a target can be read with only the read target permission")
|
||||
public void targetCanBeReadWithOnlyReadTargetPermission() throws Exception {
|
||||
final String knownTargetControllerId = "readTarget";
|
||||
controllerManagament.findOrRegisterTargetIfItDoesNotexist(knownTargetControllerId, new URI("http://127.0.0.1"));
|
||||
|
||||
securityRule.runAs(WithSpringAuthorityRule.withUser("bumlux", "READ_TARGET"), () -> {
|
||||
final Target findTargetByControllerID = targetManagement.findTargetByControllerID(knownTargetControllerId);
|
||||
assertThat(findTargetByControllerID).isNotNull();
|
||||
assertThat(findTargetByControllerID.getTargetInfo()).isNotNull();
|
||||
assertThat(findTargetByControllerID.getTargetInfo().getPollStatus()).isNotNull();
|
||||
return null;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user