Merge remote-tracking branch 'origin/master' into

fix_Introduce_consitent_button_icon_for_update_create_dialogs

Conflicts:
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetAddUpdateWindowLayout.java


Signed-off-by: Melanie Retter <melanie.retter@bosch-si.com>
This commit is contained in:
Melanie Retter
2016-06-20 15:45:24 +02:00
107 changed files with 1373 additions and 570 deletions

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.simulator.amqp;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@@ -15,6 +16,7 @@ import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -65,9 +67,12 @@ public class AmqpConfiguration {
* @return the queue
*/
@Bean
public Queue receiverConnectorQueueFromSp() {
return new Queue(amqpProperties.getReceiverConnectorQueueFromSp(), true, false, false,
getDeadLetterExchangeArgs());
public Queue receiverConnectorQueueFromHawkBit() {
final Map<String, Object> arguments = getDeadLetterExchangeArgs();
arguments.putAll(getTTLMaxArgs());
return QueueBuilder.nonDurable(amqpProperties.getReceiverConnectorQueueFromSp()).withArguments(arguments)
.build();
}
/**
@@ -89,7 +94,7 @@ public class AmqpConfiguration {
*/
@Bean
public Binding bindReceiverQueueToSpExchange() {
return BindingBuilder.bind(receiverConnectorQueueFromSp()).to(exchangeQueueToConnector());
return BindingBuilder.bind(receiverConnectorQueueFromHawkBit()).to(exchangeQueueToConnector());
}
/**
@@ -99,7 +104,7 @@ public class AmqpConfiguration {
*/
@Bean
public Queue deadLetterQueue() {
return new Queue(amqpProperties.getDeadLetterQueue(), true, false, true);
return QueueBuilder.nonDurable(amqpProperties.getDeadLetterQueue()).withArguments(getTTLMaxArgs()).build();
}
/**
@@ -145,4 +150,11 @@ public class AmqpConfiguration {
return args;
}
private static Map<String, Object> getTTLMaxArgs() {
final Map<String, Object> args = new HashMap<>();
args.put("x-message-ttl", Duration.ofDays(1).toMillis());
args.put("x-max-length", 100_000);
return args;
}
}

View File

@@ -82,21 +82,4 @@ public class MessageService {
clazz.getTypeName());
return (T) rabbitTemplate.getMessageConverter().fromMessage(message);
}
/**
* Method to verify if lwm2m header is set.
*
* @param message
* the message with the header
* @param header
* the header to verify
*/
public void checkIfLwm2mHeaderEmpty(final Message message, final String header) {
final Object headerObject = message.getMessageProperties().getHeaders().get(header);
if (null == headerObject) {
logAndThrowMessageError(message, "Header of " + header + "empty.");
}
}
}

View File

@@ -19,7 +19,6 @@
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN" />
<Logger name="org.apache.tomcat.jdbc.pool.ConnectionPool" level="DEBUG" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR" />
<!-- Security Log with hints on potential attacks -->

View File

@@ -23,7 +23,6 @@ import org.springframework.scheduling.annotation.EnableAsync;
*
*
*/
@Configuration
@EnableAsync
@ConditionalOnMissingBean(AsyncConfigurer.class)

View File

@@ -20,7 +20,7 @@ public class AsyncConfigurerThreadpoolProperties {
/**
* Max queue size for central event executor.
*/
private Integer queuesize = 250;
private Integer queuesize = 5_000;
/**
* Core processing threads for central event executor.
@@ -30,7 +30,7 @@ public class AsyncConfigurerThreadpoolProperties {
/**
* Maximum thread pool size for central event executor.
*/
private Integer maxthreads = 50;
private Integer maxthreads = 20;
/**
* When the number of threads is greater than the core, this is the maximum

View File

@@ -11,7 +11,9 @@ package org.eclipse.hawkbit.autoconfigure.scheduling;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
@@ -21,6 +23,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutor;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
@@ -39,21 +44,38 @@ public class ExecutorAutoConfiguration {
private AsyncConfigurerThreadpoolProperties asyncConfigurerProperties;
/**
* @return ExecutorService for general purpose multi threaded operations
* @return ExecutorService with security context availability in thread
* execution..
*/
@Bean
@ConditionalOnMissingBean
public Executor asyncExecutor() {
return new DelegatingSecurityContextExecutor(threadPoolExecutor());
}
/**
* @return central ThreadPoolExecutor for general purpose multi threaded
* operations. Tries an orderly shutdown when destroyed.
*/
@Bean(destroyMethod = "shutdown")
public ThreadPoolExecutor threadPoolExecutor() {
final BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(
asyncConfigurerProperties.getQueuesize());
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(asyncConfigurerProperties.getCorethreads(),
return new ThreadPoolExecutor(asyncConfigurerProperties.getCorethreads(),
asyncConfigurerProperties.getMaxthreads(), asyncConfigurerProperties.getIdletimeout(),
TimeUnit.MILLISECONDS, blockingQueue,
new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build());
threadPoolExecutor.setRejectedExecutionHandler((r, executor) -> LOGGER.warn(
"Reject runnable for centralExecutorService, reached limit of queue size {}",
executor.getQueue().size()));
return new DelegatingSecurityContextExecutor(threadPoolExecutor);
new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build(),
new PoolSizeExceededPolicy());
}
private static class PoolSizeExceededPolicy extends CallerRunsPolicy {
@Override
public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
LOGGER.warn(
"Caller has to run on its own instead of centralExecutorService, reached limit of queue size {}",
executor.getQueue().size());
super.rejectedExecution(r, executor);
}
}
/**
@@ -69,4 +91,32 @@ public class ExecutorAutoConfiguration {
return new DelegatingSecurityContextExecutor(threadPoolExecutor);
}
/**
* @return {@link TaskExecutor} for task execution
*/
@Bean
@ConditionalOnMissingBean
public TaskExecutor taskExecutor() {
return new ConcurrentTaskExecutor(asyncExecutor());
}
/**
* @return {@link ScheduledExecutorService} based on
* {@link #threadPoolTaskScheduler()}.
*/
@Bean
@ConditionalOnMissingBean
public ScheduledExecutorService scheduledExecutorService() {
return threadPoolTaskScheduler().getScheduledExecutor();
}
/**
* @return {@link ThreadPoolTaskScheduler} for scheduled operations.
*/
@Bean
@ConditionalOnMissingBean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
}

View File

@@ -0,0 +1,76 @@
/**
* 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.autoconfigure.security;
import java.util.ArrayList;
import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator;
import org.eclipse.hawkbit.im.authentication.PermissionUtils;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/**
* Auto-configuration for the in-memory-user-management.
*
*/
@Configuration
@ConditionalOnMissingBean(UserDetailsService.class)
public class InMemoryUserManagementConfiguration extends GlobalAuthenticationConfigurerAdapter {
@Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
final DaoAuthenticationProvider userDaoAuthenticationProvider = new TenantDaoAuthenticationProvider();
userDaoAuthenticationProvider.setUserDetailsService(userDetailsService());
auth.authenticationProvider(userDaoAuthenticationProvider);
}
/**
* @return the user details service to load a user from memory user manager.
*/
@Bean
@ConditionalOnMissingBean
public UserDetailsService userDetailsService() {
final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(new ArrayList<>());
inMemoryUserDetailsManager.setAuthenticationManager(null);
inMemoryUserDetailsManager.createUser(new User("admin", "admin", PermissionUtils.createAllAuthorityList()));
return inMemoryUserDetailsManager;
}
/**
* @return the multi-tenancy indicator to disallow multi-tenancy
*/
@Bean
@ConditionalOnMissingBean
public MultitenancyIndicator multiTenancyIndicator() {
return () -> false;
}
private static class TenantDaoAuthenticationProvider extends DaoAuthenticationProvider {
@Override
protected Authentication createSuccessAuthentication(final Object principal,
final Authentication authentication, final UserDetails user) {
final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
authentication.getCredentials(), user.getAuthorities());
result.setDetails(new TenantAwareAuthenticationDetails("DEFAULT", false));
return result;
}
}
}

View File

@@ -8,43 +8,17 @@
*/
package org.eclipse.hawkbit.autoconfigure.security;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator;
import org.eclipse.hawkbit.im.authentication.PermissionService;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
import org.eclipse.hawkbit.security.SpringSecurityAuditorAware;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
/**
* {@link EnableAutoConfiguration Auto-configuration} for security.
@@ -88,119 +62,4 @@ public class SecurityAutoConfiguration {
return new SpringSecurityAuditorAware();
}
/**
* Auto-configuration for the in-memory-user-management.
*
*
*
*/
@Configuration
@ConditionalOnMissingBean(value = { UserAuthenticationFilter.class })
public static class InMemoryUserManagementConfiguration extends GlobalAuthenticationConfigurerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryUserManagementConfiguration.class);
@Autowired
private AuthenticationConfiguration configuration;
/*
* (non-Javadoc)
*
* @see org.springframework.security.config.annotation.authentication.
* configurers. GlobalAuthenticationConfigurerAdapter
* #configure(org.springframework.security.config.annotation.
* authentication.builders.AuthenticationManagerBuilder)
*/
@Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
final DaoAuthenticationProvider userDaoAuthenticationProvider = new TenantDaoAuthenticationProvider();
userDaoAuthenticationProvider.setUserDetailsService(userDetailsService());
auth.authenticationProvider(userDaoAuthenticationProvider);
}
/**
* @return the user details service to load a user from memory user
* manager.
*/
@Bean
public UserDetailsService userDetailsService() {
final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(
new ArrayList<>());
inMemoryUserDetailsManager.setAuthenticationManager(null);
inMemoryUserDetailsManager.createUser(new User("admin", "admin", getAllAuthorities()));
return inMemoryUserDetailsManager;
}
/**
* @return the multi-tenancy indicator to disallow multi-tenancy
*/
@Bean
public MultitenancyIndicator multiTenancyIndicator() {
return new MultitenancyIndicator() {
@Override
public boolean isMultiTenancySupported() {
return false;
}
};
}
private Collection<SimpleGrantedAuthority> getAllAuthorities() {
final List<SimpleGrantedAuthority> allPermissions = new ArrayList<>();
final Field[] declaredFields = SpPermission.class.getDeclaredFields();
for (final Field field : declaredFields) {
if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) {
field.setAccessible(true);
try {
final String permissionName = (String) field.get(null);
allPermissions.add(new SimpleGrantedAuthority(permissionName));
} catch (final IllegalAccessException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
return allPermissions;
}
private static class TenantDaoAuthenticationProvider extends DaoAuthenticationProvider {
/*
* (non-Javadoc)
*
* @see org.springframework.security.authentication.dao.
* AbstractUserDetailsAuthenticationProvider
* #createSuccessAuthentication(java.lang.Object,
* org.springframework.security.core.Authentication,
* org.springframework.security.core.userdetails.UserDetails)
*/
@Override
protected Authentication createSuccessAuthentication(final Object principal,
final Authentication authentication, final UserDetails user) {
final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
authentication.getCredentials(), user.getAuthorities());
result.setDetails(new TenantAwareAuthenticationDetails("DEFAULT", false));
return result;
}
}
/**
* @return the {@link UserAuthenticationFilter} to include into the SP
* security configuration.
* @throws Exception
* lazy bean exception maybe if the authentication manager
* cannot be instantiated
*/
@Bean
public UserAuthenticationFilter userAuthenticationFilter() throws Exception {
return new UserAuthenticationFilterBasicAuth(configuration.getAuthenticationManager());
}
private static final class UserAuthenticationFilterBasicAuth extends BasicAuthenticationFilter
implements UserAuthenticationFilter {
private UserAuthenticationFilterBasicAuth(final AuthenticationManager authenticationManager) {
super(authenticationManager);
}
}
}
}

View File

@@ -8,6 +8,10 @@
*/
package org.eclipse.hawkbit.autoconfigure.security;
import static com.google.common.collect.Lists.newArrayList;
import static org.springframework.context.annotation.AdviceMode.ASPECTJ;
import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
import java.io.IOException;
import java.net.URI;
@@ -46,18 +50,19 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
import org.springframework.cache.Cache;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -72,6 +77,8 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
@@ -83,30 +90,49 @@ import org.vaadin.spring.security.web.VaadinRedirectStrategy;
import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler;
import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler;
import com.google.common.collect.Lists;
/**
* All configurations related to SP authentication and authorization layer.
*
*
*
* All configurations related to HawkBit's authentication and authorization
* layer.
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true)
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = ASPECTJ, proxyTargetClass = true, securedEnabled = true)
@EnableWebMvcSecurity
@Order(value = Ordered.HIGHEST_PRECEDENCE)
@Order(value = HIGHEST_PRECEDENCE)
public class SecurityManagedConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(SecurityManagedConfiguration.class);
@Autowired
private HawkbitSecurityProperties securityProperties;
@Autowired
private AuthenticationConfiguration configuration;
/**
* @return the {@link UserAuthenticationFilter} to include into the SP
* security configuration.
* @throws Exception
* lazy bean exception maybe if the authentication manager
* cannot be instantiated
*/
@Bean
@ConditionalOnMissingBean
public UserAuthenticationFilter userAuthenticationFilter() throws Exception {
return new UserAuthenticationFilterBasicAuth(configuration.getAuthenticationManager());
}
private static final class UserAuthenticationFilterBasicAuth extends BasicAuthenticationFilter
implements UserAuthenticationFilter {
private UserAuthenticationFilterBasicAuth(final AuthenticationManager authenticationManager) {
super(authenticationManager);
}
}
/**
* {@link WebSecurityConfigurer} for the internal SP controller API.
*
*
*
*/
@Configuration
@Order(300)
@@ -114,19 +140,25 @@ public class SecurityManagedConfiguration {
@Autowired
private ControllerManagement controllerManagement;
@Autowired
private TenantConfigurationManagement tenantConfigurationManagement;
@Autowired
private TenantAware tenantAware;
@Autowired
private DdiSecurityProperties ddiSecurityConfiguration;
@Autowired
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
@Autowired
private SystemSecurityContext systemSecurityContext;
@Override
protected void configure(final HttpSecurity http) throws Exception {
final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
@@ -164,16 +196,19 @@ public class SecurityManagedConfiguration {
}
if (ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled()) {
LOG.info(
"******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************");
"******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************");
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter(
"controllerAnonymousFilter", "anonymous",
Lists.newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS),
newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS),
new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE)));
anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
httpSec.requestMatchers().antMatchers("/*/controller/v1/**", "/*/controller/artifacts/v1/**").and()
.securityContext().disable().anonymous().authenticationFilter(anoymousFilter);
} else {
httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter)
.addFilter(gatewaySecurityTokenFilter).addFilter(controllerAnonymousDownloadFilter)
.antMatcher("/*/controller/**").anonymous().disable().authorizeRequests().anyRequest()
@@ -186,6 +221,7 @@ public class SecurityManagedConfiguration {
@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
ddiSecurityConfiguration.getRp().getTrustedIPs()));
}
@@ -200,6 +236,7 @@ public class SecurityManagedConfiguration {
@Bean
@Order(50)
public FilterRegistrationBean dosFilter() {
final FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
filterRegBean.setFilter(new DosFilter(securityProperties.getDos().getFilter().getMaxRead(),
@@ -207,6 +244,7 @@ public class SecurityManagedConfiguration {
securityProperties.getDos().getFilter().getWhitelist(), securityProperties.getClients().getBlacklist(),
securityProperties.getClients().getRemoteIpHeader()));
filterRegBean.addUrlPatterns("/{tenant}/controller/v1/*", "/rest/*");
return filterRegBean;
}
@@ -219,22 +257,21 @@ public class SecurityManagedConfiguration {
@Bean
@Order(100)
public FilterRegistrationBean eTagFilter() {
final FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
// eclude the URLs for downloading artifacts, so no eTag is generated in
// the
// ShallowEtagHeaderFilter, just using the SH1 hash of the artifact
// itself as 'ETag', because
// otherwise the file will be copied in memory!
// Exclude the URLs for downloading artifacts, so no eTag is generated
// in the ShallowEtagHeaderFilter, just using the SH1 hash of the
// artifact itself as 'ETag', because otherwise the file will be copied
// in memory!
filterRegBean.setFilter(new ExcludePathAwareShallowETagFilter(
"/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", "/{tenant}/controller/artifacts/**",
"/{targetid}/softwaremodules/{softwareModuleId}/artifacts/**"));
return filterRegBean;
}
/**
* Security configuration for the REST management API of the health url.
*
*
*/
@Configuration
@Order(310)
@@ -249,28 +286,34 @@ public class SecurityManagedConfiguration {
/**
* Security configuration for the REST management API.
*
*
*/
@Configuration
@Order(350)
public static class RestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private UserAuthenticationFilter userAuthenticationFilter;
@Autowired
private SystemManagement systemManagement;
@Autowired
private TenantAware tenantAware;
@Autowired
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
private SecurityProperties springSecurityProperties;
@Override
protected void configure(final HttpSecurity http) throws Exception {
final BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthEntryPoint.setRealmName(springSecurityProperties.getBasic().getRealm());
HttpSecurity httpSec = http.regexMatcher("\\/rest.*|\\/system.*").csrf().disable();
if (springSecurityProperties.isRequireSsl()) {
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
}
httpSec.addFilterBefore(new Filter() {
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
@@ -296,12 +339,13 @@ public class SecurityManagedConfiguration {
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN)
.antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/**")
.hasAnyAuthority(SpPermission.SYSTEM_DIAG);
httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint);
}
}
/**
* {@link WebSecurityConfigurer} for external (management) access.
*
*/
@Configuration
@Order(400)
@@ -311,10 +355,13 @@ public class SecurityManagedConfiguration {
private static final String XFRAME_OPTION_DENY = "DENY";
private static final String XFRAME_OPTION_SAMEORIGIN = "SAMEORIGIN";
private static final String XFAME_OPTION_ALLOW_FROM = "ALLOW-FROM";
@Autowired
private VaadinSecurityContext vaadinSecurityContext;
@Autowired
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
@Autowired
private HawkbitSecurityProperties securityProperties;
@@ -346,10 +393,13 @@ public class SecurityManagedConfiguration {
*/
@Bean
public VaadinAuthenticationSuccessHandler redirectSaveHandler() {
final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler();
handler.setRedirectStrategy(vaadinRedirectStrategy());
handler.setDefaultTargetUrl("/UI/");
handler.setTargetUrlParameter("r");
return handler;
}
@@ -371,7 +421,8 @@ public class SecurityManagedConfiguration {
// configuration xframe-option
final String confXframeOption = securityProperties.getXframe().getOption();
final String confAllowFromUri = securityProperties.getXframe().getAllowfrom();
if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri.isEmpty()) {
if (XFAME_OPTION_ALLOW_FROM.equals(confXframeOption) && confAllowFromUri.isEmpty()) {
// if allow-from option is specified but no allowFromUri throw
// exception
throw new IllegalStateException("hawkbit.server.security.xframe.option has been specified as ALLOW-FROM"
@@ -380,9 +431,8 @@ public class SecurityManagedConfiguration {
}
// workaround regex: we need to exclude the URL /UI/HEARTBEAT here
// because we bound the
// vaadin application to /UI and not to root, described in
// vaadin-forum:
// because we bound the vaadin application to /UI and not to root,
// described in vaadin-forum:
// https://vaadin.com/forum#!/thread/3200565.
HttpSecurity httpSec = http.regexMatcher("(?!.*HEARTBEAT)^.*\\/UI.*$")
// disable as CSRF is handled by Vaadin
@@ -391,8 +441,9 @@ public class SecurityManagedConfiguration {
if (springSecurityProperties.isRequireSsl()) {
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
} else {
LOG.info(
"\"******************\\n** Requires HTTPS Security has been disabled for UI, should only use for developing purposes **\\n******************\"");
"\"******************\\n** Requires HTTPS Security has been disabled for UI, should only be used for developing purposes **\\n******************\"");
}
// for UI integrator we allow frame integration on same origin
@@ -441,9 +492,6 @@ public class SecurityManagedConfiguration {
/**
* A Websecruity config to handle and filter the download ids.
*
*
*
*/
@Configuration
@EnableWebSecurity
@@ -459,6 +507,7 @@ public class SecurityManagedConfiguration {
@Override
protected void configure(final HttpSecurity http) throws Exception {
final HttpDownloadAuthenticationFilter downloadIdAuthenticationFilter = new HttpDownloadAuthenticationFilter(
downloadIdCache);
downloadIdAuthenticationFilter.setAuthenticationManager(authenticationManager());
@@ -476,32 +525,21 @@ public class SecurityManagedConfiguration {
auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
ddiSecurityConfiguration.getRp().getTrustedIPs()));
}
}
}
/**
* After a successful login on the UI we need to ensure to create the tenant
* meta data within SP.
*
*
*/
class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends VaadinUrlAuthenticationSuccessHandler {
@Autowired
private SystemManagement systemManagement;
/*
* (non-Javadoc)
*
* @see org.vaadin.spring.security.web.authentication.
* SavedRequestAwareVaadinAuthenticationSuccessHandler
* #onAuthenticationSuccess(org.springframework.security.core.
* Authentication)
*/
@Override
public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) {
systemManagement
.getTenantMetadata(((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString());
@@ -515,14 +553,13 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
// has been fixed.
systemManagement.getTenantMetadata("DEFAULT");
}
super.onAuthenticationSuccess(authentication);
}
}
/**
* Sevletfilter to create metadata after successful authentication over RESTful.
*
*
*/
class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
@@ -543,11 +580,13 @@ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException {
final String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant != null) {
// lazy initialize tenant meta data after successful authentication
systemManagement.getTenantMetadata(currentTenant);
}
chain.doFilter(request, response);
}

View File

@@ -11,4 +11,5 @@ org.eclipse.hawkbit.autoconfigure.eventbus.EventBusAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.scheduling.AsyncConfigurerAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.cache.RedisAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.scheduling.ExecutorAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration
org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.security.InMemoryUserManagementConfiguration

View File

@@ -7,6 +7,9 @@
# http://www.eclipse.org/legal/epl-v10.html
#
# Displayed basic auth realm
security.basic.realm=HawkBit
# JPA / Datasource
spring.jpa.eclipselink.eclipselink.weaving=false
spring.jpa.database=H2
@@ -27,12 +30,6 @@ vaadin.servlet.urlMapping=/UI/*
vaadin.servlet.heartbeatInterval=60
vaadin.servlet.closeIdleSessions=false
# Defines the thread pool executor
hawkbit.threadpool.corethreads=5
hawkbit.threadpool.maxthreads=20
hawkbit.threadpool.idletimeout=10000
hawkbit.threadpool.queuesize=20000
# Defines the polling time for the controllers in HH:MM:SS notation
hawkbit.controller.pollingTime=00:05:00
hawkbit.controller.pollingOverdueTime=00:05:00

View File

@@ -134,7 +134,7 @@ public class DdiArtifactStoreController implements DdiDlArtifactStoreControllerR
private Action checkAndReportDownloadByTarget(final HttpServletRequest request, final String targetid,
final LocalArtifact artifact) {
final Target target = controllerManagement.updateLastTargetQuery(targetid,
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
IpUtil.getClientIpFromRequest(request, securityProperties));
final Action action = controllerManagement
.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), artifact.getSoftwareModule());

View File

@@ -119,16 +119,14 @@ public class DdiRootController implements DdiRootControllerRestApi {
public ResponseEntity<DdiControllerBase> getControllerBase(@PathVariable("targetid") final String targetid) {
LOG.debug("getControllerBase({})", targetid);
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(targetid,
IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(),
securityProperties.getClients().getRemoteIpHeader()));
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(targetid, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
if (target.getTargetInfo().getUpdateStatus() == TargetUpdateStatus.UNKNOWN) {
LOG.debug("target with {} extsisted but was in status UNKNOWN -> REGISTERED)", targetid);
controllerManagement.updateTargetStatus(target.getTargetInfo(), TargetUpdateStatus.REGISTERED,
System.currentTimeMillis(),
IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(),
securityProperties.getClients().getRemoteIpHeader()));
System.currentTimeMillis(), IpUtil.getClientIpFromRequest(
requestResponseContextHolder.getHttpServletRequest(), securityProperties));
}
return new ResponseEntity<>(
@@ -143,9 +141,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
@PathVariable("fileName") final String fileName) {
ResponseEntity<InputStream> result;
final Target target = controllerManagement.updateLastTargetQuery(targetid,
IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(),
securityProperties.getClients().getRemoteIpHeader()));
final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId);
if (checkModule(fileName, module)) {
@@ -200,9 +197,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
public ResponseEntity<Void> downloadArtifactMd5(@PathVariable("targetid") final String targetid,
@PathVariable("softwareModuleId") final Long softwareModuleId,
@PathVariable("fileName") final String fileName) {
controllerManagement.updateLastTargetQuery(targetid,
IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(),
securityProperties.getClients().getRemoteIpHeader()));
controllerManagement.updateLastTargetQuery(targetid, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId);
@@ -228,9 +224,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
@RequestParam(value = "c", required = false, defaultValue = "-1") final int resource) {
LOG.debug("getControllerBasedeploymentAction({},{})", targetid, resource);
final Target target = controllerManagement.updateLastTargetQuery(targetid,
IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(),
securityProperties.getClients().getRemoteIpHeader()));
final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final Action action = findActionWithExceptionIfNotFound(actionId);
if (!action.getTarget().getId().equals(target.getId())) {
@@ -263,9 +258,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
@PathVariable("targetid") final String targetid, @PathVariable("actionId") @NotEmpty final Long actionId) {
LOG.debug("provideBasedeploymentActionFeedback for target [{},{}]: {}", targetid, actionId, feedback);
final Target target = controllerManagement.updateLastTargetQuery(targetid,
IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(),
securityProperties.getClients().getRemoteIpHeader()));
final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
if (!actionId.equals(feedback.getId())) {
LOG.warn(
@@ -357,9 +351,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
@Override
public ResponseEntity<Void> putConfigData(@Valid @RequestBody final DdiConfigData configData,
@PathVariable("targetid") final String targetid) {
controllerManagement.updateLastTargetQuery(targetid,
IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(),
securityProperties.getClients().getRemoteIpHeader()));
controllerManagement.updateLastTargetQuery(targetid, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
controllerManagement.updateControllerAttributes(targetid, configData.getData());
@@ -372,9 +365,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
@PathVariable("actionId") @NotEmpty final Long actionId) {
LOG.debug("getControllerCancelAction({})", targetid);
final Target target = controllerManagement.updateLastTargetQuery(targetid,
IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(),
securityProperties.getClients().getRemoteIpHeader()));
final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
final Action action = findActionWithExceptionIfNotFound(actionId);
if (!action.getTarget().getId().equals(target.getId())) {
@@ -403,9 +395,8 @@ public class DdiRootController implements DdiRootControllerRestApi {
@PathVariable("actionId") @NotEmpty final Long actionId) {
LOG.debug("provideCancelActionFeedback for target [{}]: {}", targetid, feedback);
final Target target = controllerManagement.updateLastTargetQuery(targetid,
IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(),
securityProperties.getClients().getRemoteIpHeader()));
final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil
.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties));
if (!actionId.equals(feedback.getId())) {
LOG.warn(

View File

@@ -29,11 +29,11 @@ import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
import org.junit.Test;
import org.slf4j.LoggerFactory;

View File

@@ -28,14 +28,16 @@ import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.eclipse.hawkbit.util.IpUtil;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
@@ -50,6 +52,9 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Stories("Root Poll Resource")
public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoDB {
@Autowired
private HawkbitSecurityProperties securityProperties;
@Test
@Description("Ensures that targets cannot be created e.g. in plug'n play scenarios when tenant does not exists but can be created if the tenant exists.")
@WithUser(tenantId = "tenantDoesNotExists", allSpPermissions = true, authorities = "ROLE_CONTROLLER", autoCreateTenant = false)
@@ -257,6 +262,23 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
}
@Test
@Description("Ensures that the source IP address of the polling target is not stored in repository if disabled")
public void rootRsIpAddressNotStoredIfDisabled() throws Exception {
securityProperties.getClients().setTrackRemoteIp(false);
// test
final String knownControllerId1 = "0815";
mvc.perform(get("/{tenant}/controller/v1/{controllerId}", tenantAware.getCurrentTenant(), knownControllerId1))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
// verify
final Target target = targetManagement.findTargetByControllerID(knownControllerId1);
assertThat(target.getTargetInfo().getAddress()).isEqualTo(IpUtil.createHttpUri("***"));
securityProperties.getClients().setTrackRemoteIp(true);
}
@Test
@Description("Controller trys to finish an update process after it has been finished by an error action status.")
public void tryToFinishAnUpdateProcessAfterItHasBeenFinished() throws Exception {

View File

@@ -8,21 +8,32 @@
*/
package org.eclipse.hawkbit.amqp;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.support.RetryTemplate;;
/**
* The spring AMQP configuration which is enabled by using the profile
@@ -32,14 +43,69 @@ import org.springframework.context.annotation.Bean;
@EnableConfigurationProperties({ AmqpProperties.class, AmqpDeadletterProperties.class })
public class AmqpConfiguration {
@Autowired
protected AmqpProperties amqpProperties;
private static final Logger LOGGER = LoggerFactory.getLogger(AmqpConfiguration.class);
@Autowired
protected AmqpDeadletterProperties amqpDeadletterProperties;
private AmqpProperties amqpProperties;
@Autowired
private ConnectionFactory connectionFactory;
private AmqpDeadletterProperties amqpDeadletterProperties;
@Autowired
@Qualifier("threadPoolExecutor")
private ThreadPoolExecutor threadPoolExecutor;
@Autowired
private ConnectionFactory rabbitConnectionFactory;
@Configuration
@ConditionalOnMissingBean(ConnectionFactory.class)
protected static class RabbitConnectionFactoryCreator {
@Autowired
private AmqpProperties amqpProperties;
@Autowired
@Qualifier("threadPoolExecutor")
private ThreadPoolExecutor threadPoolExecutor;
@Autowired
private ScheduledExecutorService scheduledExecutorService;
/**
* {@link ConnectionFactory} with enabled publisher confirms and
* heartbeat.
*
* @param config
* with standard {@link RabbitProperties}
* @return {@link ConnectionFactory}
*/
@Bean
public ConnectionFactory rabbitConnectionFactory(final RabbitProperties config) {
final CachingConnectionFactory factory = new CachingConnectionFactory();
factory.setRequestedHeartBeat(amqpProperties.getRequestedHeartBeat());
factory.setExecutor(threadPoolExecutor);
factory.getRabbitConnectionFactory().setHeartbeatExecutor(scheduledExecutorService);
factory.setPublisherConfirms(true);
final String addresses = config.getAddresses();
factory.setAddresses(addresses);
if (config.getHost() != null) {
factory.setHost(config.getHost());
factory.setPort(config.getPort());
}
if (config.getUsername() != null) {
factory.setUsername(config.getUsername());
}
if (config.getPassword() != null) {
factory.setPassword(config.getPassword());
}
if (config.getVirtualHost() != null) {
factory.setVirtualHost(config.getVirtualHost());
}
return factory;
}
}
/**
* Create a {@link RabbitAdmin} and ignore declaration exceptions.
@@ -49,20 +115,32 @@ public class AmqpConfiguration {
*/
@Bean
public RabbitAdmin rabbitAdmin() {
final RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
final RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitConnectionFactory);
rabbitAdmin.setIgnoreDeclarationExceptions(true);
return rabbitAdmin;
}
/**
* Method to set the Jackson2JsonMessageConverter.
*
* @return the Jackson2JsonMessageConverter
* @return {@link RabbitTemplate} with automatic retry, published confirms
* and {@link Jackson2JsonMessageConverter}.
*/
@Bean
public RabbitTemplate rabbitTemplate() {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
final RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory);
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
final RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setBackOffPolicy(new ExponentialBackOffPolicy());
rabbitTemplate.setRetryTemplate(retryTemplate);
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
LOGGER.debug("Message with {} confirmed by broker.", correlationData);
} else {
LOGGER.error("Broker is unable to handle message with {} : {}", correlationData, cause);
}
});
return rabbitTemplate;
}
@@ -159,7 +237,7 @@ public class AmqpConfiguration {
public SimpleRabbitListenerContainerFactory listenerContainerFactory() {
final SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory();
containerFactory.setDefaultRequeueRejected(false);
containerFactory.setConnectionFactory(connectionFactory);
containerFactory.setConnectionFactory(rabbitConnectionFactory);
containerFactory.setMissingQueuesFatal(amqpProperties.isMissingQueuesFatal());
return containerFactory;
}

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.amqp;
import java.util.concurrent.TimeUnit;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -38,6 +40,11 @@ public class AmqpProperties {
*/
private boolean missingQueuesFatal = false;
/**
* Requested heartbeat interval from broker in {@link TimeUnit#SECONDS}.
*/
private int requestedHeartBeat = (int) TimeUnit.SECONDS.toSeconds(60);
/**
* Is missingQueuesFatal enabled
*
@@ -102,4 +109,13 @@ public class AmqpProperties {
public void setReceiverQueue(final String receiverQueue) {
this.receiverQueue = receiverQueue;
}
public int getRequestedHeartBeat() {
return requestedHeartBeat;
}
public void setRequestedHeartBeat(final int requestedHeartBeat) {
this.requestedHeartBeat = requestedHeartBeat;
}
}

View File

@@ -109,7 +109,7 @@ public class BaseAmqpService {
}
protected final void logAndThrowMessageError(final Message message, final String error) {
LOGGER.warn("Error \"{}\" reported by message: {}", error, message);
LOGGER.warn("Warning! \"{}\" reported by message: {}", error, message);
throw new IllegalArgumentException(error);
}

View File

@@ -9,10 +9,14 @@
package org.eclipse.hawkbit.amqp;
import java.net.URI;
import java.util.UUID;
import org.eclipse.hawkbit.util.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
/**
* A default implementation for the sender service. The service sends all amqp
@@ -20,6 +24,7 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate;
* extracted from the uri.
*/
public class DefaultAmqpSenderService implements AmqpSenderService {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAmqpSenderService.class);
private final RabbitTemplate internalAmqpTemplate;
@@ -39,7 +44,16 @@ public class DefaultAmqpSenderService implements AmqpSenderService {
return;
}
internalAmqpTemplate.send(extractExchange(replyTo), null, message);
final String correlationId = UUID.randomUUID().toString();
final String exchange = extractExchange(replyTo);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Sending message {} to exchange {} with correlationId {}", message, exchange, correlationId);
} else {
LOGGER.debug("Sending message to exchange {} with correlationId {}", exchange, correlationId);
}
internalAmqpTemplate.send(exchange, null, message, new CorrelationData(correlationId));
}
}

View File

@@ -8,6 +8,14 @@
*/
package org.eclipse.hawkbit;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.eclipse.hawkbit.amqp.AmqpProperties;
import org.eclipse.hawkbit.amqp.AmqpSenderService;
import org.eclipse.hawkbit.amqp.DefaultAmqpSenderService;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
@@ -16,13 +24,22 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutor;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
/**
*
*/
@Configuration
@EnableConfigurationProperties({ AmqpProperties.class })
public class AmqpTestConfiguration {
/**
* @return the {@link SystemSecurityContext} singleton bean which make it
@@ -56,4 +73,55 @@ public class AmqpTestConfiguration {
public AmqpSenderService amqpSenderServiceBean(final RabbitTemplate rabbitTemplate) {
return new DefaultAmqpSenderService(rabbitTemplate);
}
/**
* @return ExecutorService with security context availability in thread
* execution..
*/
@Bean
@ConditionalOnMissingBean
public Executor asyncExecutor() {
return new DelegatingSecurityContextExecutor(threadPoolExecutor());
}
/**
* @return central ThreadPoolExecutor for general purpose multi threaded
* operations. Tries an orderly shutdown when destroyed.
*/
@Bean(destroyMethod = "shutdown")
public ThreadPoolExecutor threadPoolExecutor() {
final BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(10);
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 10, 1000, TimeUnit.MILLISECONDS,
blockingQueue, new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build());
return threadPoolExecutor;
}
/**
* @return {@link TaskExecutor} for task execution
*/
@Bean
@ConditionalOnMissingBean
public TaskExecutor taskExecutor() {
return new ConcurrentTaskExecutor(asyncExecutor());
}
/**
* @return {@link ScheduledExecutorService} based on
* {@link #threadPoolTaskScheduler()}.
*/
@Bean
@ConditionalOnMissingBean
public ScheduledExecutorService scheduledExecutorService() {
return threadPoolTaskScheduler().getScheduledExecutor();
}
/**
* @return {@link ThreadPoolTaskScheduler} for scheduled operations.
*/
@Bean
@ConditionalOnMissingBean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
}

View File

@@ -37,7 +37,7 @@ import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.util.AbstractIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.util.IpUtil;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

View File

@@ -16,7 +16,7 @@ import org.eclipse.hawkbit.api.UrlProtocol;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.util.AbstractIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,6 +33,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Stories("Test to generate the artifact download URL")
@SpringApplicationConfiguration(classes = { AmqpTestConfiguration.class,
org.eclipse.hawkbit.RepositoryApplicationConfiguration.class })
public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTestWithMongoDB {
private static final String HTTPS_LOCALHOST = "https://localhost:8080/";

View File

@@ -29,12 +29,12 @@ import java.util.Set;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.util.TestdataFactory;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;

View File

@@ -27,7 +27,7 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;

View File

@@ -29,7 +29,7 @@ import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;

View File

@@ -41,8 +41,8 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.util.HashGeneratorUtils;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
import org.eclipse.hawkbit.rest.util.JsonBuilder;

View File

@@ -26,7 +26,7 @@ import java.util.List;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;

View File

@@ -40,7 +40,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;

View File

@@ -0,0 +1,47 @@
# hawkBit metadata repository
The repository is in charge for managing the meta data of the update server, e.g. provisioning targets, distribution sets, software modules etc.
# Build
[indent=0]
----
$ mvn clean install
----
Note, in order to build correctly in your IDE, you have to add ./target/generated-sources/apt to your build path.
#Concepts
## Rollout
A rollout consists of the distribution set and a target-query-filter which defines the targets to be updated in this rollout. The targets within this filter are split up in configured amount of _Deployment Groups_ at creation time.
When starting a rollout, for all targets within this rollout deployment actions will be created. The deployment actions of the first group will be started immediately all other deployment actions will be scheduled.
> Due rollouts might include a large number of targets and deployment group, creation as well as starting a rollout might take some time and therefore the creation and starting of an rollout is executed asynchronously. The creation and starting progress is reflected by the rollout's status attribute
### Rollout Creation
The targets reflected by the target-query-filter is interpreted at creation time. Only targets which have been created at that time are included in the rollout. Targets which are created after the rollout creation will not be included. At rollout creation time all necessary deployment groups containing the targets will be created. Dynamically adding targets to a created or running rollout is currently not supported.
### Rollout Starting
The rollout is using the same concept based on _deployment acionts_ per target. All necessary _deployment acionts_ will be created at starting point but not all _deployment acionts_ will be set to running. Only the _deployment acionts_ of the first _deployment group_ is set to running, all other actions are created in _scheduled_ state.
If targets having not finished _deployment actions_ at rollout starting time, these action are tried to cancel (state: canceling). Scheduled actions from another rollout are canceled directly on server side because they were never running before and can be safely canceled.
>Multiple rollouts can be running at the same time, but if the rollouts effect the same targets they will interfer the targets _deployment actions_ e.g. canceling/cancel already running/scheduled _deployment actions_.
### Deployment Group Condition/Action
#### Success Condition/Action
A _success condition_ defines when a deployment group is interpreted as success and triggers the _success action_. E.g. a threshold of successfully updated targets within the group.
The _success action_ is executed if the _success_condition_ is fullfilled. Currently only the _success action_ starting the next following deployment group is available.
#### Error Condition/Action
A _error condition_ defines when a deployment group is interpreted as failure and triggers the _error action_. E.g. a threshold of update failures of targets within the group.
The _error action_ is executed if the _error condition_ is fullfilled. Currently only the _error action_ pausing the whole rollout is available, a paused rollout can be resumed by a user.
### Rollout Scheduler
The rollout is managed by a scheduler task which is checking for rollouts in _running_ state. This is done atomic by updating the row in the database, so only the rollouts are checked and processed for the current instance to avoid that multiple instances are processing a rollout.
>Due the scheduler, it might take some time until a rollouts is processed and switching is state or starting the next deployment group.

View File

@@ -0,0 +1,6 @@
# hawkBit repository API
API for repository access. Contains:
- Entity Model
- Management service API

View File

@@ -33,7 +33,7 @@ public final class Constants {
* generated by repository for every new account for "Firmware/Operating
* System" .
*/
public static final String SMT_DEFAULT_OS_NAME = "Firmware";
public static final String SMT_DEFAULT_OS_NAME = "OS";
/**
* {@link SoftwareModuleType#getName()} of a {@link SoftwareModuleType}
* generated by repository for every new account for "applications/apps".

View File

@@ -0,0 +1,3 @@
# hawkBit common implementation
Core elements that can be used by implementations.

View File

@@ -1,47 +1,3 @@
# hawkBit metadata repository
The repository is in charge for managing the meta data of the update server, e.g. provisioning targets, distribution sets, software modules etc.
# Build
[indent=0]
----
$ mvn clean install
----
Note, in order to build correctly in your IDE, you have to add ./target/generated-sources/apt to your build path.
#Concepts
## Rollout
A rollout consists of the distribution set and a target-query-filter which defines the targets to be updated in this rollout. The targets within this filter are split up in configured amount of _Deployment Groups_ at creation time.
When starting a rollout, for all targets within this rollout deployment actions will be created. The deployment actions of the first group will be started immediately all other deployment actions will be scheduled.
> Due rollouts might include a large number of targets and deployment group, creation as well as starting a rollout might take some time and therefore the creation and starting of an rollout is executed asynchronously. The creation and starting progress is reflected by the rollout's status attribute
### Rollout Creation
The targets reflected by the target-query-filter is interpreted at creation time. Only targets which have been created at that time are included in the rollout. Targets which are created after the rollout creation will not be included. At rollout creation time all necessary deployment groups containing the targets will be created. Dynamically adding targets to a created or running rollout is currently not supported.
### Rollout Starting
The rollout is using the same concept based on _deployment acionts_ per target. All necessary _deployment acionts_ will be created at starting point but not all _deployment acionts_ will be set to running. Only the _deployment acionts_ of the first _deployment group_ is set to running, all other actions are created in _scheduled_ state.
If targets having not finished _deployment actions_ at rollout starting time, these action are tried to cancel (state: canceling). Scheduled actions from another rollout are canceled directly on server side because they were never running before and can be safely canceled.
>Multiple rollouts can be running at the same time, but if the rollouts effect the same targets they will interfer the targets _deployment actions_ e.g. canceling/cancel already running/scheduled _deployment actions_.
### Deployment Group Condition/Action
#### Success Condition/Action
A _success condition_ defines when a deployment group is interpreted as success and triggers the _success action_. E.g. a threshold of successfully updated targets within the group.
The _success action_ is executed if the _success_condition_ is fullfilled. Currently only the _success action_ starting the next following deployment group is available.
#### Error Condition/Action
A _error condition_ defines when a deployment group is interpreted as failure and triggers the _error action_. E.g. a threshold of update failures of targets within the group.
The _error action_ is executed if the _error condition_ is fullfilled. Currently only the _error action_ pausing the whole rollout is available, a paused rollout can be resumed by a user.
### Rollout Scheduler
The rollout is managed by a scheduler task which is checking for rollouts in _running_ state. This is done atomic by updating the row in the database, so only the rollouts are checked and processed for the current instance to avoid that multiple instances are processing a rollout.
>Due the scheduler, it might take some time until a rollouts is processed and switching is state or starting the next deployment group.
# hawkBit JPA implementation
JPA implementation of the repository. Based on [EclipseLink](http://www.eclipse.org/eclipselink/) and [Spring Data Jpa](http://projects.spring.io/spring-data-jpa/).

View File

@@ -11,8 +11,36 @@ package org.eclipse.hawkbit;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.ReportManagement;
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.SoftwareManagement;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TagManagement;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.TenantStatsManagement;
import org.eclipse.hawkbit.repository.jpa.JpaArtifactManagement;
import org.eclipse.hawkbit.repository.jpa.JpaControllerManagement;
import org.eclipse.hawkbit.repository.jpa.JpaDeploymentManagement;
import org.eclipse.hawkbit.repository.jpa.JpaDistributionSetManagement;
import org.eclipse.hawkbit.repository.jpa.JpaEntityFactory;
import org.eclipse.hawkbit.repository.jpa.JpaReportManagement;
import org.eclipse.hawkbit.repository.jpa.JpaRolloutGroupManagement;
import org.eclipse.hawkbit.repository.jpa.JpaRolloutManagement;
import org.eclipse.hawkbit.repository.jpa.JpaSoftwareManagement;
import org.eclipse.hawkbit.repository.jpa.JpaSystemManagement;
import org.eclipse.hawkbit.repository.jpa.JpaTagManagement;
import org.eclipse.hawkbit.repository.jpa.JpaTargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.jpa.JpaTargetManagement;
import org.eclipse.hawkbit.repository.jpa.JpaTenantConfigurationManagement;
import org.eclipse.hawkbit.repository.jpa.JpaTenantStatsManagement;
import org.eclipse.hawkbit.repository.jpa.aspects.ExceptionMappingAspectHandler;
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
@@ -26,6 +54,7 @@ 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.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@@ -35,6 +64,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
@@ -50,6 +80,7 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableScheduling
public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
/**
* @return the {@link SystemSecurityContext} singleton bean which make it
@@ -173,4 +204,170 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
public PlatformTransactionManager transactionManager() {
return new MultiTenantJpaTransactionManager();
}
/**
* {@link JpaSystemManagement} bean.
*
* @return a new {@link SystemManagement}
*/
@Bean
@ConditionalOnMissingBean
public SystemManagement systemManagement() {
return new JpaSystemManagement();
}
/**
* {@link JpaReportManagement} bean.
*
* @return a new {@link ReportManagement}
*/
@Bean
@ConditionalOnMissingBean
public ReportManagement reportManagement() {
return new JpaReportManagement();
}
/**
* {@link JpaDistributionSetManagement} bean.
*
* @return a new {@link DistributionSetManagement}
*/
@Bean
@ConditionalOnMissingBean
public DistributionSetManagement distributionSetManagement() {
return new JpaDistributionSetManagement();
}
/**
* {@link JpaTenantStatsManagement} bean.
*
* @return a new {@link TenantStatsManagement}
*/
@Bean
@ConditionalOnMissingBean
public TenantStatsManagement tenantStatsManagement() {
return new JpaTenantStatsManagement();
}
/**
* {@link JpaTenantConfigurationManagement} bean.
*
* @return a new {@link TenantConfigurationManagement}
*/
@Bean
@ConditionalOnMissingBean
public TenantConfigurationManagement tenantConfigurationManagement() {
return new JpaTenantConfigurationManagement();
}
/**
* {@link JpaTenantConfigurationManagement} bean.
*
* @return a new {@link TenantConfigurationManagement}
*/
@Bean
@ConditionalOnMissingBean
public TargetManagement targetManagement() {
return new JpaTargetManagement();
}
/**
* {@link JpaTargetFilterQueryManagement} bean.
*
* @return a new {@link TargetFilterQueryManagement}
*/
@Bean
@ConditionalOnMissingBean
public TargetFilterQueryManagement targetFilterQueryManagement() {
return new JpaTargetFilterQueryManagement();
}
/**
* {@link JpaTagManagement} bean.
*
* @return a new {@link TagManagement}
*/
@Bean
@ConditionalOnMissingBean
public TagManagement tagManagement() {
return new JpaTagManagement();
}
/**
* {@link JpaSoftwareManagement} bean.
*
* @return a new {@link SoftwareManagement}
*/
@Bean
@ConditionalOnMissingBean
public SoftwareManagement softwareManagement() {
return new JpaSoftwareManagement();
}
/**
* {@link JpaRolloutManagement} bean.
*
* @return a new {@link RolloutManagement}
*/
@Bean
@ConditionalOnMissingBean
public RolloutManagement rolloutManagement() {
return new JpaRolloutManagement();
}
/**
* {@link JpaRolloutGroupManagement} bean.
*
* @return a new {@link RolloutGroupManagement}
*/
@Bean
@ConditionalOnMissingBean
public RolloutGroupManagement rolloutGroupManagement() {
return new JpaRolloutGroupManagement();
}
/**
* {@link JpaDeploymentManagement} bean.
*
* @return a new {@link DeploymentManagement}
*/
@Bean
@ConditionalOnMissingBean
public DeploymentManagement deploymentManagement() {
return new JpaDeploymentManagement();
}
/**
* {@link JpaControllerManagement} bean.
*
* @return a new {@link ControllerManagement}
*/
@Bean
@ConditionalOnMissingBean
public ControllerManagement controllerManagement() {
return new JpaControllerManagement();
}
/**
* {@link JpaArtifactManagement} bean.
*
* @return a new {@link ArtifactManagement}
*/
@Bean
@ConditionalOnMissingBean
public ArtifactManagement artifactManagement() {
return new JpaArtifactManagement();
}
/**
* {@link JpaEntityFactory} bean.
*
* @return a new {@link EntityFactory}
*/
@Bean
@ConditionalOnMissingBean
public EntityFactory entityFactory() {
return new JpaEntityFactory();
}
}

View File

@@ -16,7 +16,9 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Tag;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -82,15 +84,26 @@ public interface DistributionSetRepository
List<DistributionSet> findByModules(JpaSoftwareModule module);
/**
* Finds {@link DistributionSet}s based on given ID if they are not assigned
* yet to an {@link UpdateAction}, i.e. unused.
* Finds {@link DistributionSet}s based on given ID that are assigned yet to
* an {@link Action}, i.e. in use.
*
* @param ids
* to search for
* @return
* @return list of {@link DistributionSet#getId()}
*/
@Query("select ac.distributionSet.id from JpaAction ac where ac.distributionSet.id in :ids")
List<Long> findAssignedDistributionSetsById(@Param("ids") Long... ids);
List<Long> findAssignedToTargetDistributionSetsById(@Param("ids") Long... ids);
/**
* Finds {@link DistributionSet}s based on given ID that are assigned yet to
* an {@link Rollout}, i.e. in use.
*
* @param ids
* to search for
* @return list of {@link DistributionSet#getId()}
*/
@Query("select ra.distributionSet.id from JpaRollout ra where ra.distributionSet.id in :ids")
List<Long> findAssignedToRolloutDistributionSetsById(@Param("ids") Long... ids);
/**
* Saves all given {@link DistributionSet}s.

View File

@@ -41,7 +41,6 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -52,7 +51,6 @@ import org.springframework.validation.annotation.Validated;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaArtifactManagement implements ArtifactManagement {
private static final Logger LOG = LoggerFactory.getLogger(JpaArtifactManagement.class);

View File

@@ -54,7 +54,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -65,7 +64,6 @@ import org.springframework.validation.annotation.Validated;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaControllerManagement implements ControllerManagement {
private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class);
private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos");

View File

@@ -96,7 +96,6 @@ import com.google.common.eventbus.EventBus;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaDeploymentManagement implements DeploymentManagement {
private static final Logger LOG = LoggerFactory.getLogger(JpaDeploymentManagement.class);

View File

@@ -60,7 +60,6 @@ import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -74,7 +73,6 @@ import com.google.common.eventbus.EventBus;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaDistributionSetManagement implements DistributionSetManagement {
@Autowired
@@ -173,7 +171,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
public void deleteDistributionSet(final Long... distributionSetIDs) {
final List<Long> toHardDelete = new ArrayList<>();
final List<Long> assigned = distributionSetRepository.findAssignedDistributionSetsById(distributionSetIDs);
final List<Long> assigned = distributionSetRepository
.findAssignedToTargetDistributionSetsById(distributionSetIDs);
assigned.addAll(distributionSetRepository.findAssignedToRolloutDistributionSetsById(distributionSetIDs));
// soft delete assigned
if (!assigned.isEmpty()) {

View File

@@ -42,13 +42,11 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.springframework.stereotype.Service;
/**
* JPA Implementation of {@link EntityFactory}.
*
*/
@Service
public class JpaEntityFactory implements EntityFactory {
@Override

View File

@@ -45,7 +45,6 @@ import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -56,7 +55,6 @@ import org.springframework.validation.annotation.Validated;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaReportManagement implements ReportManagement {
@Value("${spring.jpa.database}")

View File

@@ -47,7 +47,6 @@ import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -56,7 +55,6 @@ import org.springframework.validation.annotation.Validated;
* JPA implementation of {@link RolloutGroupManagement}.
*/
@Validated
@Service
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
public class JpaRolloutGroupManagement implements RolloutGroupManagement {

View File

@@ -60,8 +60,6 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.Isolation;
@@ -76,8 +74,6 @@ import org.springframework.validation.annotation.Validated;
* JPA implementation of {@link RolloutManagement}.
*/
@Validated
@Service
@EnableScheduling
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
public class JpaRolloutManagement implements RolloutManagement {
private static final Logger LOGGER = LoggerFactory.getLogger(RolloutManagement.class);

View File

@@ -60,7 +60,6 @@ import org.springframework.data.domain.SliceImpl;
import org.springframework.data.jpa.domain.Specification;
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;
@@ -74,7 +73,6 @@ import com.google.common.collect.Sets;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaSoftwareManagement implements SoftwareManagement {
@Autowired

View File

@@ -8,7 +8,6 @@
*/
package org.eclipse.hawkbit.repository.jpa;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;
@@ -34,10 +33,8 @@ import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.ApplicationContext;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -49,7 +46,6 @@ import org.springframework.validation.annotation.Validated;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, SystemManagement {
@Autowired
private EntityManager entityManager;
@@ -108,7 +104,11 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
@Autowired
private TenancyCacheManager cacheManager;
private final ThreadLocal<String> createInitialTenant = new ThreadLocal<>();
@Autowired
private SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator;
@Autowired
private ApplicationContext applicationContext;
@Override
public SystemUsageReport getSystemUsageStatistics() {
@@ -154,9 +154,8 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
@Override
@Transactional(propagation = Propagation.SUPPORTS)
@Bean
public KeyGenerator currentTenantKeyGenerator() {
return new CurrentTenantKeyGenerator();
return currentTenantCacheKeyGenerator.currentTenantKeyGenerator();
}
@Override
@@ -169,11 +168,12 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
// Create if it does not exist
if (result == null) {
try {
createInitialTenant.set(tenant);
currentTenantCacheKeyGenerator.getCreateInitialTenant().set(tenant);
cacheManager.getCache("currentTenant").evict(currentTenantKeyGenerator().generate(null, null));
applicationContext.getBean("currentTenantKeyGenerator");
return tenantMetaDataRepository.save(new JpaTenantMetaData(createStandardSoftwareDataSetup(), tenant));
} finally {
createInitialTenant.remove();
currentTenantCacheKeyGenerator.getCreateInitialTenant().remove();
}
}
@@ -239,7 +239,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
// tenant is not cached anyway already.
@Transactional(propagation = Propagation.NOT_SUPPORTED, isolation = Isolation.READ_UNCOMMITTED)
public String currentTenant() {
final String initialTenantCreation = createInitialTenant.get();
final String initialTenantCreation = currentTenantCacheKeyGenerator.getCreateInitialTenant().get();
if (initialTenantCreation == null) {
final TenantMetaData findByTenant = tenantMetaDataRepository
.findByTenantIgnoreCase(tenantAware.getCurrentTenant());
@@ -260,29 +260,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
return tenantMetaDataRepository.save((JpaTenantMetaData) metaData);
}
/**
* A implementation of the {@link KeyGenerator} to generate a key based on
* either the {@code createInitialTenant} thread local and the
* {@link TenantAware}, but in case we are in a tenant creation with its
* default types we need to use the tenant the current tenant which is
* currently created and not the one currently in the {@link TenantAware}.
*
*/
public 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) {
return SimpleKeyGenerator.generateKey(tenantAware.getCurrentTenant().toUpperCase(),
tenantAware.getCurrentTenant().toUpperCase());
}
return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(),
initialTenantCreation.toUpperCase());
}
}
private DistributionSetType createStandardSoftwareDataSetup() {
final SoftwareModuleType app = softwareModuleTypeRepository
.save(new JpaSoftwareModuleType(Constants.SMT_DEFAULT_APP_KEY, Constants.SMT_DEFAULT_APP_NAME,

View File

@@ -39,7 +39,6 @@ import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -52,7 +51,6 @@ import com.google.common.eventbus.EventBus;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaTagManagement implements TagManagement {
@Autowired

View File

@@ -40,7 +40,6 @@ import com.google.common.base.Strings;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaTargetFilterQueryManagement implements TargetFilterQueryManagement {
@Autowired

View File

@@ -59,7 +59,6 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
@@ -75,7 +74,6 @@ import com.google.common.eventbus.EventBus;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaTargetManagement implements TargetManagement {
@Autowired

View File

@@ -23,7 +23,6 @@ import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -33,7 +32,6 @@ import org.springframework.validation.annotation.Validated;
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
@Validated
@Service
public class JpaTenantConfigurationManagement implements EnvironmentAware, TenantConfigurationManagement {
@Autowired

View File

@@ -24,7 +24,6 @@ import org.springframework.validation.annotation.Validated;
*
*/
@Validated
@Service
public class JpaTenantStatsManagement implements TenantStatsManagement {
@Autowired

View File

@@ -0,0 +1,65 @@
/**
* 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.jpa;
import java.lang.reflect.Method;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
/**
* Implementation of {@link CurrentTenantCacheKeyGenerator}.
*
*/
@Service
public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyGenerator {
@Autowired
private TenantAware tenantAware;
private final ThreadLocal<String> createInitialTenant = new ThreadLocal<>();
/**
* A implementation of the {@link KeyGenerator} to generate a key based on
* either the {@code createInitialTenant} thread local and the
* {@link TenantAware}, but in case we are in a tenant creation with its
* default types we need to use the tenant the current tenant which is
* currently created and not the one currently in the {@link TenantAware}.
*
*/
public 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) {
return SimpleKeyGenerator.generateKey(tenantAware.getCurrentTenant().toUpperCase(),
tenantAware.getCurrentTenant().toUpperCase());
}
return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(),
initialTenantCreation.toUpperCase());
}
}
@Override
@Bean
public KeyGenerator currentTenantKeyGenerator() {
return new CurrentTenantKeyGenerator();
}
ThreadLocal<String> getCreateInitialTenant() {
return createInitialTenant;
}
}

View File

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
import org.eclipse.hawkbit.repository.util.AbstractIntegrationTest;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.data.mongodb.gridfs.GridFsOperations;

View File

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
import org.eclipse.hawkbit.repository.util.AbstractIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;

View File

@@ -32,8 +32,8 @@ import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.util.HashGeneratorUtils;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.Test;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.query.Criteria;

View File

@@ -27,6 +27,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.model.Action;
@@ -37,9 +38,15 @@ import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSe
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.fest.assertions.core.Condition;
import org.junit.Test;
import org.springframework.data.domain.Page;
@@ -777,36 +784,55 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
}
@Test
@Description("Deltes a DS that is no in use. Expected behaviour is a soft delete on the database, i.e. only marked as "
+ "deleted, kept eas refernce and unavailable for future use..")
@Description("Deletes a DS that is in use by either target assignment or rollout. Expected behaviour is a soft delete on the database, i.e. only marked as "
+ "deleted, kept as reference but unavailable for future use..")
public void deleteAssignedDistributionSet() {
DistributionSet ds1 = testdataFactory.createDistributionSet("ds-1");
DistributionSet ds2 = testdataFactory.createDistributionSet("ds-2");
DistributionSet dsAssigned = testdataFactory.createDistributionSet("ds-3");
DistributionSet dsToTargetAssigned = testdataFactory.createDistributionSet("ds-3");
final DistributionSet dsToRolloutAssigned = testdataFactory.createDistributionSet("ds-4");
ds1 = distributionSetManagement.findDistributionSetByNameAndVersion(ds1.getName(), ds1.getVersion());
ds2 = distributionSetManagement.findDistributionSetByNameAndVersion(ds2.getName(), ds2.getVersion());
// create assigned DS
dsAssigned = distributionSetManagement.findDistributionSetByNameAndVersion(dsAssigned.getName(),
dsAssigned.getVersion());
dsToTargetAssigned = distributionSetManagement.findDistributionSetByNameAndVersion(dsToTargetAssigned.getName(),
dsToTargetAssigned.getVersion());
final Target target = new JpaTarget("4712");
final Target savedTarget = targetManagement.createTarget(target);
final List<Target> toAssign = new ArrayList<>();
toAssign.add(savedTarget);
deploymentManagement.assignDistributionSet(dsAssigned, toAssign);
deploymentManagement.assignDistributionSet(dsToTargetAssigned, toAssign);
// delete a ds
assertThat(distributionSetRepository.findAll()).hasSize(3);
distributionSetManagement.deleteDistributionSet(dsAssigned.getId());
// create assigned rollout
createRolloutByVariables("test", "test", 5, "name==*", dsToRolloutAssigned, "50", "5");
// delete assigned ds
assertThat(distributionSetRepository.findAll()).hasSize(4);
distributionSetManagement.deleteDistributionSet(dsToTargetAssigned.getId(), dsToRolloutAssigned.getId());
// not assigned so not marked as deleted
assertThat(distributionSetRepository.findAll()).hasSize(3);
assertThat(distributionSetRepository.findAll()).hasSize(4);
assertThat(distributionSetManagement
.findDistributionSetsByDeletedAndOrCompleted(pageReq, Boolean.FALSE, Boolean.TRUE).getTotalElements())
.isEqualTo(2);
}
private Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription,
final int groupSize, final String filterQuery, final DistributionSet distributionSet,
final String successCondition, final String errorCondition) {
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder()
.successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition)
.errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition)
.errorAction(RolloutGroupErrorAction.PAUSE, null).build();
final Rollout rolloutToCreate = new JpaRollout();
rolloutToCreate.setName(rolloutName);
rolloutToCreate.setDescription(rolloutDescription);
rolloutToCreate.setTargetFilterQuery(filterQuery);
rolloutToCreate.setDistributionSet(distributionSet);
return rolloutManagement.createRollout(rolloutToCreate, groupSize, conditions);
}
private Target sendUpdateActionStatusToTarget(final Status status, final Action updActA, final Target t,
final String... msgs) {
updActA.setStatus(status);

View File

@@ -37,9 +37,9 @@ import org.eclipse.hawkbit.repository.report.model.DataReportSeries;
import org.eclipse.hawkbit.repository.report.model.DataReportSeriesItem;
import org.eclipse.hawkbit.repository.report.model.InnerOuterDataReportSeries;
import org.eclipse.hawkbit.repository.report.model.SeriesTime;
import org.eclipse.hawkbit.repository.util.TestdataFactory;
import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -34,13 +34,13 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.repository.util.TestdataFactory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Description;

View File

@@ -39,7 +39,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;

View File

@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule;
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;

View File

@@ -38,13 +38,13 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetIdName;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;

View File

@@ -20,7 +20,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.util.TestdataFactory;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;

View File

@@ -16,7 +16,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.util.TestdataFactory;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;

View File

@@ -18,7 +18,7 @@ import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.util.TestdataFactory;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.repository.Constants;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
@@ -34,7 +35,7 @@ public class RSQLSoftwareModuleTypeFieldsTest extends AbstractJpaIntegrationTest
@Test
@Description("Test filter software module test type by name")
public void testFilterByParameterName() {
assertRSQLQuery(SoftwareModuleTypeFields.NAME.name() + "==Firmware", 1);
assertRSQLQuery(SoftwareModuleTypeFields.NAME.name() + "==" + Constants.SMT_DEFAULT_OS_NAME, 1);
}
@Test

View File

@@ -24,7 +24,7 @@ import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.util.TestdataFactory;
import org.eclipse.hawkbit.repository.test.util.TestdataFactory;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.Page;

View File

@@ -16,8 +16,8 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule;
import org.eclipse.hawkbit.repository.util.WithUser;
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
import org.eclipse.hawkbit.repository.test.util.WithUser;
import org.junit.Test;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Slice;

View File

@@ -0,0 +1,42 @@
/**
* 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.test.matcher;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.hamcrest.Factory;
import org.hamcrest.FeatureMatcher;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
/**
* Matcher for {@link BaseEntity}.
*/
public class BaseEntityMatcher {
private BaseEntityMatcher() {
}
@Factory
public static Matcher<BaseEntity> hasId(final Long id) {
return new HasIdMatcher(Matchers.equalTo(id));
}
private static class HasIdMatcher extends FeatureMatcher<BaseEntity, Long> {
public HasIdMatcher(final Matcher<Long> subMatcher) {
super(subMatcher, "getId()", "id");
}
@Override
protected Long featureValueOf(final BaseEntity baseEntity) {
return baseEntity.getId();
}
}
}

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import org.eclipse.hawkbit.ExcludePathAwareShallowETagFilter;
import org.eclipse.hawkbit.repository.ArtifactManagement;

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import java.io.IOException;
import java.net.UnknownHostException;

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import java.sql.Connection;
import java.sql.DriverManager;

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import java.io.File;
import java.net.InetSocketAddress;

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import java.util.List;

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
/**
* Repository support for tests.

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import java.io.InputStream;
import java.nio.charset.Charset;

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
/**
*

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.util;
package org.eclipse.hawkbit.repository.test.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.rest;
import org.eclipse.hawkbit.repository.util.AbstractIntegrationTest;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest;
import org.eclipse.hawkbit.rest.configuration.RestConfiguration;
import org.eclipse.hawkbit.rest.util.FilterHttpResponse;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.rest;
import org.eclipse.hawkbit.repository.util.AbstractIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB;
import org.eclipse.hawkbit.rest.configuration.RestConfiguration;
import org.eclipse.hawkbit.rest.util.FilterHttpResponse;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -17,7 +17,7 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
/**
*
* Service to check permissions.
*
*/
public class PermissionService {

View File

@@ -0,0 +1,52 @@
/**
* 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.im.authentication;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
/**
* Utility method for creation of <tt>GrantedAuthority</tt> collections etc.
*/
public final class PermissionUtils {
private PermissionUtils() {
}
/**
* Create {@link GrantedAuthority} by a special role.
*
* @param roles
* the roles
* @return a list of {@link GrantedAuthority}
*/
public static List<GrantedAuthority> createAuthorityList(final Collection<String> roles) {
final List<GrantedAuthority> authorities = new ArrayList<>(roles.size());
for (final String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
/**
* Returns all authorities.
*
* @return a list of {@link GrantedAuthority}
*/
public static List<GrantedAuthority> createAllAuthorityList() {
return createAuthorityList(SpPermission.getAllAuthorities());
}
}

View File

@@ -9,7 +9,16 @@
package org.eclipse.hawkbit.im.authentication;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
@@ -35,6 +44,8 @@ import org.springframework.security.core.GrantedAuthority;
*/
public final class SpPermission {
private static final Logger LOGGER = LoggerFactory.getLogger(SpPermission.class);
/**
* Permission to read the targets from the
* {@link ProvisioningTargetRepository} including their meta information,
@@ -139,6 +150,53 @@ public final class SpPermission {
// Constants only
}
/**
* Return all permission.
*
* @return all permission
*/
public static Collection<String> getAllAuthorities() {
return getAllAuthorities(Collections.emptyList());
}
/**
* Return all permission.
*
* @param exclusionRoles
* roles which will excluded
* @return all permissions
*/
public static Collection<String> getAllAuthorities(final String... exclusionRoles) {
return getAllAuthorities(Arrays.asList(exclusionRoles));
}
/**
* Return all permission.
*
* @param exclusionRoles
* roles which will excluded
* @return all permissions
*/
public static Collection<String> getAllAuthorities(final Collection<String> exclusionRoles) {
final List<String> allPermissions = new ArrayList<>();
final Field[] declaredFields = SpPermission.class.getDeclaredFields();
for (final Field field : declaredFields) {
if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) {
field.setAccessible(true);
try {
final String role = (String) field.get(null);
if (!(exclusionRoles.contains(role))) {
allPermissions.add(role);
}
} catch (final IllegalAccessException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
return allPermissions;
}
/**
* Contains all the spring security evaluation expressions for the
* {@link PreAuthorize} annotation for method security.

View File

@@ -8,8 +8,10 @@
*/
package org.eclipse.hawkbit.security;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.eclipse.hawkbit.security.SecurityConstants.SECURITY_LOG_PREFIX;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
@@ -31,25 +33,21 @@ import com.google.common.cache.CacheBuilder;
/**
* Filter for protection against denial of service attacks. It reduces the
* maximum number of request per seconds which can be separately configured for
* read (GET) and write (PUT/POST/DELETE) requests. requests
*
*
*
*
* read (GET) and write (PUT/POST/DELETE) requests.
*/
public class DosFilter extends OncePerRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(DosFilter.class);
private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos");
private static final Logger LOG_BLACKLIST = LoggerFactory.getLogger("server-security.blacklist");
private static final Logger LOG_DOS = LoggerFactory.getLogger(SECURITY_LOG_PREFIX + ".dos");
private static final Logger LOG_BLACKLIST = LoggerFactory.getLogger(SECURITY_LOG_PREFIX + ".blacklist");
private final Pattern ipAdressBlacklist;
private final Cache<String, AtomicInteger> readCountCache = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.SECONDS).build();
private final Cache<String, AtomicInteger> readCountCache = CacheBuilder.newBuilder().expireAfterAccess(1, SECONDS)
.build();
private final Cache<String, AtomicInteger> writeCountCache = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.SECONDS).build();
private final Cache<String, AtomicInteger> writeCountCache = CacheBuilder.newBuilder().expireAfterAccess(1, SECONDS)
.build();
private final Integer maxRead;
private final Integer maxWrite;
@@ -78,7 +76,7 @@ public class DosFilter extends OncePerRequestFilter {
*/
public DosFilter(final Integer maxRead, final Integer maxWrite, final String ipDosWhiteListPattern,
final String ipBlackListPattern, final String forwardHeader) {
super();
this.maxRead = maxRead;
this.maxWrite = maxWrite;
this.forwardHeader = forwardHeader;
@@ -96,21 +94,13 @@ public class DosFilter extends OncePerRequestFilter {
}
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(
* javax.servlet.http. HttpServletRequest,
* javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
*/
@Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
final FilterChain filterChain) throws ServletException, IOException {
boolean processChain;
final String ip = IpUtil.getClientIpFromRequest(request, forwardHeader).getHost();
final String ip = IpUtil.getClientIpFromRequest(request, forwardHeader, true).getHost();
if (checkIpFails(ip)) {
processChain = handleMissingIpAddress(response);
} else {
@@ -152,11 +142,9 @@ public class DosFilter extends OncePerRequestFilter {
}
private static boolean handleMissingIpAddress(final HttpServletResponse response) {
boolean processChain;
LOG.error("Failed to get peer IP adress");
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
processChain = false;
return processChain;
return false;
}
private boolean handleWriteRequest(final HttpServletResponse response, final String ip) {

View File

@@ -82,10 +82,16 @@ public class HawkbitSecurityProperties {
private String blacklist = "";
/**
* Name of the http header from which the remote ip is extracted.
* Name of the http header from which the remote ip is extracted for DDI
* connected clients.
*/
private String remoteIpHeader = "X-Forwarded-For";
/**
* Set to <code>true</code> if DDI clients remote IP should be stored.
*/
private boolean trackRemoteIp = true;
public String getBlacklist() {
return blacklist;
}
@@ -101,6 +107,14 @@ public class HawkbitSecurityProperties {
public void setRemoteIpHeader(final String remoteIpHeader) {
this.remoteIpHeader = remoteIpHeader;
}
public boolean isTrackRemoteIp() {
return trackRemoteIp;
}
public void setTrackRemoteIp(final boolean trackRemoteIp) {
this.trackRemoteIp = trackRemoteIp;
}
}
/**

View File

@@ -0,0 +1,24 @@
/**
* 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.security;
/**
* Constants related to security.
*/
public final class SecurityConstants {
/**
* Logger prefix used for security logging.
*/
public static final String SECURITY_LOG_PREFIX = "server-security";
private SecurityConstants() {
}
}

View File

@@ -14,12 +14,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
/**
* Auditor class that allows {@link BaseEntity}s to insert currenlt logged in
* user for repository changes.
*
*
*
*
* Auditor class that allows BaseEntitys to insert current logged in user for
* repository changes.
*
*/
public class SpringSecurityAuditorAware implements AuditorAware<String> {
@@ -29,16 +25,21 @@ public class SpringSecurityAuditorAware implements AuditorAware<String> {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
if (isAuthenticationInvalid(authentication)) {
return null;
}
if (authentication.getPrincipal() != null) {
return getCurrentAuditor(authentication);
}
private String getCurrentAuditor(final Authentication authentication) {
if (authentication.getPrincipal() instanceof UserDetails) {
return ((UserDetails) authentication.getPrincipal()).getUsername();
}
return authentication.getPrincipal().toString();
}
return null;
private static boolean isAuthenticationInvalid(final Authentication authentication) {
return authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal() == null;
}
}

View File

@@ -15,6 +15,8 @@ import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
import com.google.common.net.HttpHeaders;
/**
@@ -45,17 +47,49 @@ public final class IpUtil {
* @param request
* the {@link HttpServletRequest} to determine the IP address
* where this request has been sent from
* @param forwardHeader
* the header name containing the IP address e.g. forwarded by a
* proxy {@code x-forwarded-for}
* @param securityProperties
* hawkBit security properties.
* @return the {@link URI} based IP address from the client which sent the
* request
*/
public static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader) {
String ip = request.getHeader(forwardHeader);
public static URI getClientIpFromRequest(final HttpServletRequest request,
final HawkbitSecurityProperties securityProperties) {
return getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader(),
securityProperties.getClients().isTrackRemoteIp());
}
/**
* Retrieves the string based IP address from a given
* {@link HttpServletRequest} by either the
* {@link HttpHeaders#X_FORWARDED_FOR} or by the
* {@link HttpServletRequest#getRemoteAddr()} methods.
*
* @param request
* the {@link HttpServletRequest} to determine the IP address
* where this request has been sent from
* @param forwardHeader
* the header name containing the IP address e.g. forwarded by a
* proxy {@code x-forwarded-for}
*
* @param trackRemoteIp
* to <code>true</code> if remote IP should be tracked.
* @return the {@link URI} based IP address from the client which sent the
* request
*/
public static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader,
final boolean trackRemoteIp) {
String ip;
if (trackRemoteIp) {
ip = request.getHeader(forwardHeader);
if (ip == null || (ip = findClientIpAddress(ip)) == null) {
ip = request.getRemoteAddr();
}
} else {
ip = "***";
}
return createHttpUri(ip);
}

View File

@@ -0,0 +1,54 @@
/**
* 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.im.authentication;
import static org.fest.assertions.api.Assertions.assertThat;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
import org.springframework.context.annotation.Description;
import org.springframework.security.core.GrantedAuthority;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test {@link SpPermission}.
*/
@Features("Unit Tests - Security")
@Stories("Permission Test")
public final class PermissionTest {
@Test
@Description("Verify the get permission function")
public void testGetPermissions() {
final int allPermission = 15;
final int permissionWithoutSystem = allPermission - 3;
final Collection<String> allAuthorities = SpPermission.getAllAuthorities();
final List<GrantedAuthority> allAuthoritiesList = PermissionUtils.createAllAuthorityList();
assertThat(allAuthorities).hasSize(allPermission);
assertThat(allAuthoritiesList).hasSize(allPermission);
assertThat(allAuthoritiesList.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList()))
.containsAll(allAuthorities);
final Collection<String> authoritiesWithoutSystem = SpPermission.getAllAuthorities(SpPermission.SYSTEM_ADMIN,
SpPermission.SYSTEM_DIAG, SpPermission.SYSTEM_MONITOR);
final List<GrantedAuthority> authoritiesListWithoutSystem = PermissionUtils.createAuthorityList(SpPermission
.getAllAuthorities(SpPermission.SYSTEM_ADMIN, SpPermission.SYSTEM_DIAG, SpPermission.SYSTEM_MONITOR));
assertThat(authoritiesWithoutSystem).hasSize(permissionWithoutSystem);
assertThat(authoritiesListWithoutSystem).hasSize(permissionWithoutSystem);
assertThat(authoritiesListWithoutSystem.stream().map(authority -> authority.getAuthority())
.collect(Collectors.toList())).containsAll(authoritiesWithoutSystem);
}
}

View File

@@ -50,7 +50,7 @@ public class IpUtilTest {
when(requestMock.getRemoteAddr()).thenReturn(knownRemoteClientIP.getHost());
// test
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux");
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux", true);
// verify
assertThat(remoteAddr).as("The remote address should be as the known client IP address")
@@ -59,6 +59,25 @@ public class IpUtilTest {
verify(requestMock, times(1)).getRemoteAddr();
}
@Test
@Description("Tests create uri from request with masked IP when IP tracking is disabled")
public void maskRemoteAddrIfDisabled() {
// known values
final URI knownRemoteClientIP = IpUtil.createHttpUri("***");
// mock
when(requestMock.getHeader(HttpHeaders.X_FORWARDED_FOR)).thenReturn(null);
when(requestMock.getRemoteAddr()).thenReturn(knownRemoteClientIP.getHost());
// test
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux", false);
// verify
assertThat(remoteAddr).as("The remote address should be as the known client IP address")
.isEqualTo(knownRemoteClientIP);
verify(requestMock, times(0)).getHeader("bumlux");
verify(requestMock, times(0)).getRemoteAddr();
}
@Test
@Description("Tests create uri from x forward header")
public void getRemoteAddrFromXForwardedForHeader() {
@@ -69,7 +88,7 @@ public class IpUtilTest {
when(requestMock.getRemoteAddr()).thenReturn(null);
// test
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "X-Forwarded-For");
final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "X-Forwarded-For", true);
// verify
assertThat(remoteAddr).as("The remote address should be as the known client IP address")

View File

@@ -208,6 +208,7 @@ public class SoftwareModuleAddUpdateWindow extends CustomComponent implements Se
* (controller Id, name & description) and action buttons layout
*/
addStyleName("lay-color");
setSizeUndefined();
formLayout = new FormLayout();
formLayout.setCaption(null);

View File

@@ -330,6 +330,8 @@ public class CreateUpdateSoftwareTypeLayout extends CreateUpdateTypeLayout
getColorPickerLayout().getSelPreview().setColor(getColorPickerLayout().getSelectedColor());
mainLayout.addComponent(colorPickerLayout, 1, 0);
mainLayout.setComponentAlignment(colorPickerLayout, Alignment.MIDDLE_CENTER);
} else {
mainLayout.removeComponent(colorPickerLayout);
}
tagPreviewBtnClicked = !tagPreviewBtnClicked;
}

View File

@@ -53,19 +53,19 @@ public class ArtifactUploadState implements ManagmentEntityState<Long>, Serializ
private Set<Long> selectedSoftwareModules = Collections.emptySet();
private boolean swTypeFilterClosed = Boolean.FALSE;
private boolean swTypeFilterClosed;
private boolean swModuleTableMaximized = Boolean.FALSE;
private boolean swModuleTableMaximized;
private boolean artifactDetailsMaximized = Boolean.FALSE;
private boolean artifactDetailsMaximized;
private final Set<String> selectedDeleteSWModuleTypes = new HashSet<>();
private boolean noDataAvilableSoftwareModule = Boolean.FALSE;
private boolean noDataAvilableSoftwareModule;
private boolean isStatusPopupMinimized = Boolean.FALSE;
private boolean statusPopupMinimized;
private boolean isUploadCompleted = Boolean.FALSE;
private boolean uploadCompleted;
private List<UploadStatusObject> uploadedFileStatusList = new ArrayList<>();
@@ -87,35 +87,30 @@ public class ArtifactUploadState implements ManagmentEntityState<Long>, Serializ
return numberOfFileUploadsExpected;
}
public List<UploadStatusObject> getUploadedFileStatusList() {
return uploadedFileStatusList;
}
public void setUploadedFileStatusList(List<UploadStatusObject> uploadedFileStatusList) {
public void setUploadedFileStatusList(final List<UploadStatusObject> uploadedFileStatusList) {
this.uploadedFileStatusList = uploadedFileStatusList;
}
public boolean isUploadCompleted() {
return isUploadCompleted;
return uploadCompleted;
}
public void setUploadCompleted(boolean isUploadCompleted) {
this.isUploadCompleted = isUploadCompleted;
public void setUploadCompleted(final boolean uploadCompleted) {
this.uploadCompleted = uploadCompleted;
}
public void setStatusPopupMinimized(boolean isStatusPopupMinimized) {
this.isStatusPopupMinimized = isStatusPopupMinimized;
public void setStatusPopupMinimized(final boolean statusPopupMinimized) {
this.statusPopupMinimized = statusPopupMinimized;
}
public boolean isStatusPopupMinimized() {
return isStatusPopupMinimized;
return statusPopupMinimized;
}
/**
* Set software.
*

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.io.Serializable;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
/**
@@ -16,22 +18,24 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
* popup.
*
*/
public class UploadStatusObject {
public class UploadStatusObject implements Serializable {
private static final long serialVersionUID = 1L;
private String status;
private Double progress;
private String filename;
private String reason;
private SoftwareModule selectedSoftwareModule;
private final SoftwareModule selectedSoftwareModule;
public UploadStatusObject(final String status, final Double progress, final String fileName, final String reason,
final SoftwareModule selectedSoftwareModule) {
this(fileName,selectedSoftwareModule);
this(fileName, selectedSoftwareModule);
this.status = status;
this.progress = progress;
this.reason = reason;
}
public UploadStatusObject(String fileName, SoftwareModule selectedSoftwareModule) {
public UploadStatusObject(final String fileName, final SoftwareModule selectedSoftwareModule) {
this.filename = fileName;
this.selectedSoftwareModule = selectedSoftwareModule;
}
@@ -44,7 +48,7 @@ public class UploadStatusObject {
return status;
}
public void setStatus(String status) {
public void setStatus(final String status) {
this.status = status;
}
@@ -52,7 +56,7 @@ public class UploadStatusObject {
return progress;
}
public void setProgress(Double progress) {
public void setProgress(final Double progress) {
this.progress = progress;
}
@@ -60,7 +64,7 @@ public class UploadStatusObject {
return filename;
}
public void setFilename(String filename) {
public void setFilename(final String filename) {
this.filename = filename;
}
@@ -68,19 +72,38 @@ public class UploadStatusObject {
return reason;
}
public void setReason(String reason) {
public void setReason(final String reason) {
this.reason = reason;
}
@Override
public boolean equals(Object obj) {
if (this == null || obj == null) {
return false;
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((filename == null) ? 0 : filename.hashCode());
return result;
}
if (obj instanceof UploadStatusObject && this.getFilename() == ((UploadStatusObject) obj).getFilename()) {
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof UploadStatusObject)) {
return false;
}
final UploadStatusObject other = (UploadStatusObject) obj;
if (filename == null) {
if (other.filename != null) {
return false;
}
} else if (!filename.equals(other.filename)) {
return false;
}
return true;
}
}

View File

@@ -36,6 +36,7 @@ import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
@@ -187,6 +188,9 @@ public class CommonDialogWindow extends Window implements Serializable {
((AbstractOrderedLayout) content).setSpacing(true);
((AbstractOrderedLayout) content).setMargin(true);
}
if (content instanceof GridLayout) {
addStyleName("");
}
if (null != content) {
mainLayout.addComponent(content);

View File

@@ -175,11 +175,7 @@ public final class UserDetailsFormatter {
private static UserDetails loadUserByUsername(final String username) {
final UserDetailsService userDetailsService = SpringContextHelper.getBean(UserDetailsService.class);
try {
final UserDetails loadUserByUsername = userDetailsService.loadUserByUsername(username);
if (loadUserByUsername == null) {
throw new UsernameNotFoundException("User not found " + username);
}
return loadUserByUsername;
return userDetailsService.loadUserByUsername(username);
} catch (final UsernameNotFoundException e) {
return new User(username, "", Collections.emptyList());
}

View File

@@ -155,6 +155,7 @@ public abstract class AbstractFilterButtons extends Table {
columnIds.add(FILTER_BUTTON_COLUMN);
setVisibleColumns(columnIds.toArray());
setColumnHeaderMode(ColumnHeaderMode.HIDDEN);
setColumnWidth(FILTER_BUTTON_COLUMN, 137);
}
private Button createFilterButton(final Long id, final String name, final String description, final String color,
@@ -179,6 +180,7 @@ public abstract class AbstractFilterButtons extends Table {
button.setDescription(name);
}
button.setData(id == null ? SPUIDefinitions.NO_TAG_BUTTON_ID : itemId);
return button;
}

View File

@@ -8,8 +8,6 @@
*/
package org.eclipse.hawkbit.ui.decorators;
import org.eclipse.hawkbit.ui.utils.SPUIButtonDefinitions;
import com.vaadin.server.Resource;
import com.vaadin.ui.Button;
import com.vaadin.ui.themes.ValoTheme;
@@ -22,16 +20,10 @@ public class SPUITagButtonStyle implements SPUIButtonDecorator {
@Override
public Button decorate(final Button button, final String style, final boolean setStyle, final Resource icon) {
/**
* Add ... for long name
*/
final String buttonCaption = button.getCaption();
if (buttonCaption != null && buttonCaption.length() > SPUIButtonDefinitions.BUTTON_CAPTION_LENGTH) {
button.setCaption(buttonCaption.substring(0, SPUIButtonDefinitions.BUTTON_CAPTION_LENGTH) + "...");
}
button.setImmediate(true);
button.addStyleName("button-no-border" + " " + ValoTheme.BUTTON_BORDERLESS + " " + ValoTheme.BUTTON_TINY + " "
button.addStyleName("generatedColumnPadding button-no-border" + " " + ValoTheme.BUTTON_BORDERLESS + " "
+ "button-tag-no-border");
// Set Style
if (null != style) {
if (setStyle) {

View File

@@ -717,6 +717,8 @@ public class CreateUpdateDistSetTypeLayout extends CreateUpdateTypeLayout
getColorPickerLayout().getSelPreview().setColor(getColorPickerLayout().getSelectedColor());
mainLayout.addComponent(colorPickerLayout, 1, 0);
mainLayout.setComponentAlignment(colorPickerLayout, Alignment.MIDDLE_CENTER);
} else {
mainLayout.removeComponent(colorPickerLayout);
}
tagPreviewBtnClicked = !tagPreviewBtnClicked;
}

Some files were not shown because too many files have changed in this diff Show More