Merge remote-tracking branch 'eclipse/master' into harmonize-test-documentation
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -16,13 +16,13 @@
|
|||||||
*.jar
|
*.jar
|
||||||
*.war
|
*.war
|
||||||
|
|
||||||
######################
|
|
||||||
# Sonar
|
# Sonar
|
||||||
######################
|
|
||||||
.sonar_lock
|
.sonar_lock
|
||||||
|
|
||||||
# Eclipse IDE
|
# Created by spring-boot-configuration-processor
|
||||||
|
.factorypath
|
||||||
|
|
||||||
|
# Eclipse IDE
|
||||||
*.pydevproject
|
*.pydevproject
|
||||||
.project
|
.project
|
||||||
.metadata
|
.metadata
|
||||||
|
|||||||
9
MIGRATION.md
Normal file
9
MIGRATION.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# hawkBit Migration Guides
|
||||||
|
## Release 0.2
|
||||||
|
### Configuration Property changes
|
||||||
|
- hawkbit.server.controller._ have changed to hawkbit.server.ddi._
|
||||||
|
- info.build._ have changed to hawkbit.server.build._
|
||||||
|
- hawkbit.server.demo._ have changed to hawkbit.server.ui.demo._
|
||||||
|
- hawkbit.server.email.support has changed to hawkbit.server.ui.links.support
|
||||||
|
- hawkbit.server.email.request.account has changed to hawkbit.server.ui.links.requestAccount
|
||||||
|
- hawkbit.server.im.login.url has changed to hawkbit.server.ui.links.userManagement
|
||||||
@@ -100,7 +100,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
<version>19.0</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.netflix.feign</groupId>
|
<groupId>com.netflix.feign</groupId>
|
||||||
@@ -116,6 +115,11 @@
|
|||||||
<groupId>com.jayway.jsonpath</groupId>
|
<groupId>com.jayway.jsonpath</groupId>
|
||||||
<artifactId>json-path</artifactId>
|
<artifactId>json-path</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -9,21 +9,35 @@
|
|||||||
package org.eclipse.hawkbit.simulator.amqp;
|
package org.eclipse.hawkbit.simulator.amqp;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean which holds the necessary properties for configuring the AMQP
|
* Bean which holds the necessary properties for configuring the AMQP
|
||||||
* connection.
|
* connection.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
@ConfigurationProperties("hawkbit.device.simulator.amqp")
|
@ConfigurationProperties("hawkbit.device.simulator.amqp")
|
||||||
public class AmqpProperties {
|
public class AmqpProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue for receiving DMF messages from update server.
|
||||||
|
*/
|
||||||
private String receiverConnectorQueueFromSp;
|
private String receiverConnectorQueueFromSp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchange for sending DMF messages to update server.
|
||||||
|
*/
|
||||||
private String senderForSpExchange;
|
private String senderForSpExchange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulator dead letter queue.
|
||||||
|
*/
|
||||||
private String deadLetterQueue;
|
private String deadLetterQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulator dead letter exchange.
|
||||||
|
*/
|
||||||
private String deadLetterExchange;
|
private String deadLetterExchange;
|
||||||
|
|
||||||
public String getReceiverConnectorQueueFromSp() {
|
public String getReceiverConnectorQueueFromSp() {
|
||||||
|
|||||||
@@ -7,23 +7,20 @@
|
|||||||
# http://www.eclipse.org/legal/epl-v10.html
|
# http://www.eclipse.org/legal/epl-v10.html
|
||||||
#
|
#
|
||||||
|
|
||||||
# need to re-name these properties in the defaulthawkbit.properties and code!
|
hawkbit.server.ddi.security.authentication.anonymous.enabled=true
|
||||||
hawkbit.server.controller.security.authentication.anonymous.enabled=true
|
hawkbit.server.ddi.security.authentication.targettoken.enabled=false
|
||||||
hawkbit.server.controller.security.authentication.header.enabled=false
|
hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false
|
||||||
hawkbit.server.controller.security.authentication.targettoken.enabled=false
|
|
||||||
hawkbit.server.controller.security.authentication.gatewaytoken.enabled=false
|
|
||||||
|
|
||||||
spring.profiles.active=amqp
|
spring.profiles.active=amqp
|
||||||
|
|
||||||
vaadin.servlet.productionMode=false
|
vaadin.servlet.productionMode=false
|
||||||
vaadin.static.servlet.productionMode=false
|
|
||||||
|
|
||||||
## Configuration for RabbitMQ integration
|
## Configuration for RabbitMQ integration
|
||||||
hawkbit.server.amqp.username=guest
|
spring.rabbitmq.username=guest
|
||||||
hawkbit.server.amqp.password=guest
|
spring.rabbitmq.password=guest
|
||||||
hawkbit.server.amqp.virtualHost=/
|
spring.rabbitmq.virtualHost=/
|
||||||
hawkbit.server.amqp.host=localhost
|
spring.rabbitmq.host=localhost
|
||||||
hawkbit.server.amqp.port=5672
|
spring.rabbitmq.port=5672
|
||||||
hawkbit.server.amqp.deadLetterQueue=sp_deadletter
|
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter
|
||||||
hawkbit.server.amqp.deadLetterExchange=sp.deadletter
|
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
|
||||||
hawkbit.server.amqp.receiverQueue=sp_receiver
|
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
|
||||||
|
|||||||
@@ -87,5 +87,10 @@
|
|||||||
<artifactId>google-collections</artifactId>
|
<artifactId>google-collections</artifactId>
|
||||||
<version>1.0-rc2</version>
|
<version>1.0-rc2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -9,17 +9,30 @@
|
|||||||
package org.eclipse.hawkbit.mgmt.client;
|
package org.eclipse.hawkbit.mgmt.client;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration bean which holds the configuration of the client e.g. the base
|
* Configuration bean which holds the configuration of the client e.g. the base
|
||||||
* URL of the hawkbit-server and the credentials to use the RESTful Management
|
* URL of the hawkbit-server and the credentials to use the RESTful Management
|
||||||
* API.
|
* API.
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
@ConfigurationProperties(prefix = "hawkbit")
|
@ConfigurationProperties(prefix = "hawkbit")
|
||||||
public class ClientConfigurationProperties {
|
public class ClientConfigurationProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update server URI.
|
||||||
|
*/
|
||||||
private String url = "localhost:8080";
|
private String url = "localhost:8080";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update server user name.
|
||||||
|
*/
|
||||||
private String username = "admin";
|
private String username = "admin";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update server password.
|
||||||
|
*/
|
||||||
private String password = "admin"; // NOSONAR this password is only used for
|
private String password = "admin"; // NOSONAR this password is only used for
|
||||||
// examples
|
// examples
|
||||||
|
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ hawkbit.url=localhost:8080
|
|||||||
hawkbit.username=admin
|
hawkbit.username=admin
|
||||||
hawkbit.password=admin
|
hawkbit.password=admin
|
||||||
|
|
||||||
spring.main.banner-mode=OFF
|
spring.main.show-banner=false
|
||||||
@@ -72,5 +72,10 @@
|
|||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context-support</artifactId>
|
<artifactId>spring-context-support</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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.conf;
|
|
||||||
|
|
||||||
import org.eclipse.hawkbit.ControllerPollProperties;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable the Controlle Poll.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@ConditionalOnClass(ControllerPollProperties.class)
|
|
||||||
@EnableConfigurationProperties(ControllerPollProperties.class)
|
|
||||||
public class ControllerPollAutoConfiguration {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -13,17 +13,29 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
|||||||
/**
|
/**
|
||||||
* Properties for the async configurer.
|
* Properties for the async configurer.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties("hawkbit.threadpool")
|
@ConfigurationProperties("hawkbit.threadpool")
|
||||||
public class AsyncConfigurerThreadpoolProperties {
|
public class AsyncConfigurerThreadpoolProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max queue size for central event executor.
|
||||||
|
*/
|
||||||
private Integer queuesize = 250;
|
private Integer queuesize = 250;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core processing threads for central event executor.
|
||||||
|
*/
|
||||||
private Integer corethreads = 5;
|
private Integer corethreads = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum thread pool size for central event executor.
|
||||||
|
*/
|
||||||
private Integer maxthreads = 50;
|
private Integer maxthreads = 50;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the number of threads is greater than the core, this is the maximum
|
||||||
|
* time that excess idle threads will wait for new tasks before terminating.
|
||||||
|
*/
|
||||||
private Long idletimeout = 10000L;
|
private Long idletimeout = 10000L;
|
||||||
|
|
||||||
public Integer getQueuesize() {
|
public Integer getQueuesize() {
|
||||||
|
|||||||
@@ -26,10 +26,9 @@ import org.springframework.security.concurrent.DelegatingSecurityContextExecutor
|
|||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Central event processors inside update server.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(AsyncConfigurerThreadpoolProperties.class)
|
@EnableConfigurationProperties(AsyncConfigurerThreadpoolProperties.class)
|
||||||
public class ExecutorAutoConfiguration {
|
public class ExecutorAutoConfiguration {
|
||||||
@@ -40,7 +39,7 @@ public class ExecutorAutoConfiguration {
|
|||||||
private AsyncConfigurerThreadpoolProperties asyncConfigurerProperties;
|
private AsyncConfigurerThreadpoolProperties asyncConfigurerProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return ExecutorService for general pupose multi threaded operations
|
* @return ExecutorService for general purpose multi threaded operations
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import org.eclipse.hawkbit.im.authentication.SpPermission;
|
|||||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||||
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
|
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
|
||||||
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
||||||
import org.eclipse.hawkbit.security.SecurityProperties;
|
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||||
import org.eclipse.hawkbit.security.SpringSecurityAuditorAware;
|
import org.eclipse.hawkbit.security.SpringSecurityAuditorAware;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -53,7 +53,7 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(SecurityProperties.class)
|
@EnableConfigurationProperties(DdiSecurityProperties.class)
|
||||||
public class SecurityAutoConfiguration {
|
public class SecurityAutoConfiguration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,29 +31,27 @@ import org.eclipse.hawkbit.repository.ControllerManagement;
|
|||||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||||
import org.eclipse.hawkbit.rest.resource.RestConstants;
|
import org.eclipse.hawkbit.rest.resource.RestConstants;
|
||||||
import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource;
|
import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource;
|
||||||
|
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||||
import org.eclipse.hawkbit.security.DosFilter;
|
import org.eclipse.hawkbit.security.DosFilter;
|
||||||
|
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||||
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter;
|
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter;
|
||||||
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter;
|
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter;
|
||||||
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedSecurityHeaderFilter;
|
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedSecurityHeaderFilter;
|
||||||
import org.eclipse.hawkbit.security.HttpDownloadAuthenticationFilter;
|
import org.eclipse.hawkbit.security.HttpDownloadAuthenticationFilter;
|
||||||
import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider;
|
import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider;
|
||||||
import org.eclipse.hawkbit.security.SecurityProperties;
|
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
|
||||||
import org.springframework.boot.context.embedded.FilterRegistrationBean;
|
import org.springframework.boot.context.embedded.FilterRegistrationBean;
|
||||||
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
|
import org.springframework.boot.context.embedded.ServletListenerRegistrationBean;
|
||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
import org.springframework.context.annotation.AdviceMode;
|
import org.springframework.context.annotation.AdviceMode;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
@@ -94,17 +92,11 @@ import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSucc
|
|||||||
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true)
|
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true)
|
||||||
@EnableWebMvcSecurity
|
@EnableWebMvcSecurity
|
||||||
@Order(value = Ordered.HIGHEST_PRECEDENCE)
|
@Order(value = Ordered.HIGHEST_PRECEDENCE)
|
||||||
public class SecurityManagedConfiguration implements EnvironmentAware {
|
public class SecurityManagedConfiguration {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(SecurityManagedConfiguration.class);
|
private static final Logger LOG = LoggerFactory.getLogger(SecurityManagedConfiguration.class);
|
||||||
|
|
||||||
private static final String SP_SERVER_CONFIG_PREFIX = "hawkbit.server.";
|
@Autowired
|
||||||
private RelaxedPropertyResolver environment;
|
private HawkbitSecurityProperties securityProperties;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(final Environment environment) {
|
|
||||||
this.environment = new RelaxedPropertyResolver(environment, SP_SERVER_CONFIG_PREFIX);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link WebSecurityConfigurer} for the internal SP controller API.
|
* {@link WebSecurityConfigurer} for the internal SP controller API.
|
||||||
@@ -123,7 +115,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TenantAware tenantAware;
|
private TenantAware tenantAware;
|
||||||
@Autowired
|
@Autowired
|
||||||
private SecurityProperties securityConfiguration;
|
private DdiSecurityProperties ddiSecurityConfiguration;
|
||||||
@Autowired
|
@Autowired
|
||||||
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
|
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
|
||||||
|
|
||||||
@@ -132,7 +124,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
|
final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
|
||||||
|
|
||||||
final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
|
final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
|
||||||
securityConfiguration.getRpCnHeader(), securityConfiguration.getRpSslIssuerHashHeader(),
|
ddiSecurityConfiguration.getRp().getCnHeader(), ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(),
|
||||||
systemManagement, tenantAware);
|
systemManagement, tenantAware);
|
||||||
securityHeaderFilter.setAuthenticationManager(authenticationManager());
|
securityHeaderFilter.setAuthenticationManager(authenticationManager());
|
||||||
securityHeaderFilter.setCheckForPrincipalChanges(true);
|
securityHeaderFilter.setCheckForPrincipalChanges(true);
|
||||||
@@ -158,7 +150,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
|
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (securityConfiguration.getAnonymousEnabled()) {
|
if (ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled()) {
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************");
|
"******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************");
|
||||||
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter(
|
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter(
|
||||||
@@ -189,7 +181,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
@Override
|
@Override
|
||||||
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
||||||
auth.authenticationProvider(
|
auth.authenticationProvider(
|
||||||
new PreAuthTokenSourceTrustAuthenticationProvider(securityConfiguration.getRpTrustedIPs()));
|
new PreAuthTokenSourceTrustAuthenticationProvider(ddiSecurityConfiguration.getRp().getTrustedIPs()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,13 +196,10 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
public FilterRegistrationBean dosFilter() {
|
public FilterRegistrationBean dosFilter() {
|
||||||
final FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
|
final FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
|
||||||
|
|
||||||
filterRegBean
|
filterRegBean.setFilter(new DosFilter(securityProperties.getDos().getFilter().getMaxRead(),
|
||||||
.setFilter(
|
securityProperties.getDos().getFilter().getMaxWrite(),
|
||||||
new DosFilter(environment.getProperty("security.dos.filter.maxRead", Integer.class, 200),
|
securityProperties.getDos().getFilter().getWhitelist(), securityProperties.getClients().getBlacklist(),
|
||||||
environment.getProperty("security.dos.filter.maxWrite", Integer.class, 50),
|
securityProperties.getClients().getRemoteIpHeader()));
|
||||||
environment.getProperty("security.dos.filter.whitelist"), environment
|
|
||||||
.getProperty("security.clients.blacklist"),
|
|
||||||
environment.getProperty("security.rp.remote_ip_header", String.class, "X-Forwarded-For")));
|
|
||||||
filterRegBean.addUrlPatterns("/{tenant}/controller/v1/*", "/rest/*");
|
filterRegBean.addUrlPatterns("/{tenant}/controller/v1/*", "/rest/*");
|
||||||
return filterRegBean;
|
return filterRegBean;
|
||||||
}
|
}
|
||||||
@@ -310,8 +299,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
@Configuration
|
@Configuration
|
||||||
@Order(400)
|
@Order(400)
|
||||||
@EnableVaadinSecurity
|
@EnableVaadinSecurity
|
||||||
public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter
|
public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||||
implements EnvironmentAware {
|
|
||||||
|
|
||||||
private static final String XFRAME_OPTION_DENY = "DENY";
|
private static final String XFRAME_OPTION_DENY = "DENY";
|
||||||
private static final String XFRAME_OPTION_SAMEORIGIN = "SAMEORIGIN";
|
private static final String XFRAME_OPTION_SAMEORIGIN = "SAMEORIGIN";
|
||||||
@@ -320,13 +308,8 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
private VaadinSecurityContext vaadinSecurityContext;
|
private VaadinSecurityContext vaadinSecurityContext;
|
||||||
@Autowired
|
@Autowired
|
||||||
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
|
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
|
||||||
|
@Autowired
|
||||||
private RelaxedPropertyResolver environment;
|
private HawkbitSecurityProperties securityProperties;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(final Environment environment) {
|
|
||||||
this.environment = new RelaxedPropertyResolver(environment, SP_SERVER_CONFIG_PREFIX);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* post construct for setting the authentication success handler for the
|
* post construct for setting the authentication success handler for the
|
||||||
@@ -379,13 +362,13 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
protected void configure(final HttpSecurity http) throws Exception {
|
protected void configure(final HttpSecurity http) throws Exception {
|
||||||
|
|
||||||
// configuration xframe-option
|
// configuration xframe-option
|
||||||
final String confXframeOption = environment.getProperty("security.xframe.option", XFRAME_OPTION_DENY);
|
final String confXframeOption = securityProperties.getXframe().getOption();
|
||||||
final String confAllowFromUri = environment.getProperty("security.xframe.option.allowfrom");
|
final String confAllowFromUri = securityProperties.getXframe().getAllowfrom();
|
||||||
if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri == null) {
|
if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri.isEmpty()) {
|
||||||
// if allow-from option is specified but no allowFromUri throw
|
// if allow-from option is specified but no allowFromUri throw
|
||||||
// exception
|
// exception
|
||||||
throw new IllegalStateException("hawkbit.server.security.xframe.option has been specified as ALLOW-FROM"
|
throw new IllegalStateException("hawkbit.server.security.xframe.option has been specified as ALLOW-FROM"
|
||||||
+ " but no hawkbit.server.security.xframe.option.allowfrom has been set, "
|
+ " but no hawkbit.server.security.xframe.allowfrom has been set, "
|
||||||
+ "please ensure to set allow from URIs");
|
+ "please ensure to set allow from URIs");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +444,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
public static class IdRestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
public static class IdRestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SecurityProperties securityConfiguration;
|
private DdiSecurityProperties ddiSecurityConfiguration;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier(CacheConstants.DOWNLOAD_ID_CACHE)
|
@Qualifier(CacheConstants.DOWNLOAD_ID_CACHE)
|
||||||
@@ -484,7 +467,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware {
|
|||||||
@Override
|
@Override
|
||||||
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
||||||
auth.authenticationProvider(
|
auth.authenticationProvider(
|
||||||
new PreAuthTokenSourceTrustAuthenticationProvider(securityConfiguration.getRpTrustedIPs()));
|
new PreAuthTokenSourceTrustAuthenticationProvider(ddiSecurityConfiguration.getRp().getTrustedIPs()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.autoconfigure.url;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.HawkbitServerProperties;
|
||||||
import org.eclipse.hawkbit.api.HostnameResolver;
|
import org.eclipse.hawkbit.api.HostnameResolver;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
@@ -27,11 +28,11 @@ import com.google.common.base.Throwables;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(ServerProperties.class)
|
@EnableConfigurationProperties(HawkbitServerProperties.class)
|
||||||
public class PropertyHostnameResolverAutoConfiguration {
|
public class PropertyHostnameResolverAutoConfiguration {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ServerProperties serverProperties;
|
private HawkbitServerProperties serverProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the default autoconfigure hostname resolver implementation which
|
* @return the default autoconfigure hostname resolver implementation which
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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.url;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties for the server e.g. the server's URL which must be configured.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@ConfigurationProperties("hawkbit.server")
|
|
||||||
public class ServerProperties {
|
|
||||||
|
|
||||||
private String url = "http://localhost:8080";
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUrl(final String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,5 +11,4 @@ org.eclipse.hawkbit.autoconfigure.eventbus.EventBusAutoConfiguration,\
|
|||||||
org.eclipse.hawkbit.autoconfigure.scheduling.AsyncConfigurerAutoConfiguration,\
|
org.eclipse.hawkbit.autoconfigure.scheduling.AsyncConfigurerAutoConfiguration,\
|
||||||
org.eclipse.hawkbit.autoconfigure.cache.RedisAutoConfiguration,\
|
org.eclipse.hawkbit.autoconfigure.cache.RedisAutoConfiguration,\
|
||||||
org.eclipse.hawkbit.autoconfigure.scheduling.ExecutorAutoConfiguration,\
|
org.eclipse.hawkbit.autoconfigure.scheduling.ExecutorAutoConfiguration,\
|
||||||
org.eclipse.hawkbit.autoconfigure.conf.ControllerPollAutoConfiguration,\
|
|
||||||
org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration
|
org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration
|
||||||
|
|||||||
@@ -7,12 +7,6 @@
|
|||||||
# http://www.eclipse.org/legal/epl-v10.html
|
# http://www.eclipse.org/legal/epl-v10.html
|
||||||
#
|
#
|
||||||
|
|
||||||
# Tomcat / Server
|
|
||||||
server.tomcat.compression=on
|
|
||||||
spring.http.gzip.mime-types=text/html,text/xml,text/plain,application/json,application/javascript,text/css,application/x-javascript,text/javascript,application/vnd.ms-fontobject,application/x-font-opentype,application/x-font-truetype,application/x-font-ttf,application/xml,font/eot,font/opentype,font/otf,image/svg+xml,image/vnd.microsoft.icon
|
|
||||||
server.tomcat.compressable-mime-types=${spring.http.gzip.mime-types}
|
|
||||||
spring.http.gzip.min-gzip-size=256
|
|
||||||
|
|
||||||
# JPA / Datasource
|
# JPA / Datasource
|
||||||
spring.jpa.eclipselink.eclipselink.weaving=false
|
spring.jpa.eclipselink.eclipselink.weaving=false
|
||||||
spring.jpa.database=H2
|
spring.jpa.database=H2
|
||||||
@@ -21,7 +15,6 @@ spring.datasource.driverClassName=org.h2.Driver
|
|||||||
|
|
||||||
# MongoDB for artifact-repository
|
# MongoDB for artifact-repository
|
||||||
spring.data.mongodb.uri=mongodb://localhost/artifactrepo
|
spring.data.mongodb.uri=mongodb://localhost/artifactrepo
|
||||||
spring.data.mongo.repositories.enabled=true
|
|
||||||
|
|
||||||
# Flyway DDL
|
# Flyway DDL
|
||||||
flyway.enabled=true
|
flyway.enabled=true
|
||||||
@@ -29,15 +22,10 @@ flyway.initOnMigrate=true
|
|||||||
flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
|
flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
|
||||||
|
|
||||||
# Vaadin Servlet
|
# Vaadin Servlet
|
||||||
vaadin.static.servlet.productionMode=true
|
|
||||||
vaadin.servlet.productionMode=true
|
vaadin.servlet.productionMode=true
|
||||||
vaadin.servlet.urlMapping=/UI/*
|
vaadin.servlet.urlMapping=/UI/*
|
||||||
vaadin.servlet.params.heartbeatInterval=60
|
vaadin.servlet.heartbeatInterval=60
|
||||||
vaadin.servlet.params.closeIdleSessions=false
|
vaadin.servlet.closeIdleSessions=false
|
||||||
|
|
||||||
# Spring MVC
|
|
||||||
spring.mvc.favicon.enabled=false
|
|
||||||
|
|
||||||
|
|
||||||
# Defines the thread pool executor
|
# Defines the thread pool executor
|
||||||
hawkbit.threadpool.corethreads=5
|
hawkbit.threadpool.corethreads=5
|
||||||
@@ -50,6 +38,6 @@ hawkbit.controller.pollingTime=00:05:00
|
|||||||
hawkbit.controller.pollingOverdueTime=00:05:00
|
hawkbit.controller.pollingOverdueTime=00:05:00
|
||||||
|
|
||||||
## Configuration for RabbitMQ integration
|
## Configuration for RabbitMQ integration
|
||||||
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter
|
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_receiver_deadletter
|
||||||
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
|
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.receiver.deadletter
|
||||||
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
|
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
|
||||||
|
|||||||
@@ -37,6 +37,11 @@
|
|||||||
<groupId>redis.clients</groupId>
|
<groupId>redis.clients</groupId>
|
||||||
<artifactId>jedis</artifactId>
|
<artifactId>jedis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer
|
|||||||
* The spring Redis configuration which is enabled by using the profile
|
* The spring Redis configuration which is enabled by using the profile
|
||||||
* {@code redis} to use a Redis server as cache.
|
* {@code redis} to use a Redis server as cache.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(RedisProperties.class)
|
@EnableConfigurationProperties(RedisProperties.class)
|
||||||
|
|||||||
@@ -14,14 +14,18 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
|||||||
* Bean which holds the necessary properties for configuring the Redis
|
* Bean which holds the necessary properties for configuring the Redis
|
||||||
* connection.
|
* connection.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties("hawkbit.server.redis")
|
@ConfigurationProperties("hawkbit.server.redis")
|
||||||
public class RedisProperties {
|
public class RedisProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis server hostname.
|
||||||
|
*/
|
||||||
private String host;
|
private String host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis server port.
|
||||||
|
*/
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -43,6 +43,11 @@
|
|||||||
<artifactId>allure-junit-adaptor</artifactId>
|
<artifactId>allure-junit-adaptor</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -9,18 +9,26 @@
|
|||||||
package org.eclipse.hawkbit;
|
package org.eclipse.hawkbit;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the polling time for the controllers in HH:MM:SS notation.
|
* Defines the polling time for the controllers in HH:MM:SS notation.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
@ConfigurationProperties(prefix = "hawkbit.controller")
|
@ConfigurationProperties(prefix = "hawkbit.controller")
|
||||||
public class ControllerPollProperties {
|
public class ControllerPollProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recommended target polling time for DDI API. Final choice is up to the
|
||||||
|
* target.
|
||||||
|
*/
|
||||||
private String pollingTime = "00:05:00";
|
private String pollingTime = "00:05:00";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assumed time frame where the target is considered overdue when no DDI
|
||||||
|
* polling has been registered by the update server.
|
||||||
|
*/
|
||||||
private String pollingOverdueTime = "00:05:00";
|
private String pollingOverdueTime = "00:05:00";
|
||||||
|
|
||||||
public String getPollingTime() {
|
public String getPollingTime() {
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties for the server e.g. the server's URL which must be configured.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties("hawkbit.server")
|
||||||
|
public class HawkbitServerProperties {
|
||||||
|
/**
|
||||||
|
* Defines under which URI the update server can be reached. Used to
|
||||||
|
* calculate download URLs for DMF transmitted update actions.
|
||||||
|
*/
|
||||||
|
private String url = "http://localhost:8080";
|
||||||
|
|
||||||
|
private final Build build = new Build();
|
||||||
|
|
||||||
|
public Build getBuild() {
|
||||||
|
return build;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build information of the hawkBit instance. Influenced by maven.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Build {
|
||||||
|
/**
|
||||||
|
* Project artifact ID.
|
||||||
|
*/
|
||||||
|
private String artifact = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project name.
|
||||||
|
*/
|
||||||
|
private String name = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project description.
|
||||||
|
*/
|
||||||
|
private String description = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project version.
|
||||||
|
*/
|
||||||
|
private String version = "";
|
||||||
|
|
||||||
|
public String getArtifact() {
|
||||||
|
return artifact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArtifact(final String artifact) {
|
||||||
|
this.artifact = artifact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(final String version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(final String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,12 @@ public enum ActionStatusFields implements FieldNameProvider {
|
|||||||
/**
|
/**
|
||||||
* The id field.
|
* The id field.
|
||||||
*/
|
*/
|
||||||
ID("id");
|
ID("id"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reportedAt field.
|
||||||
|
*/
|
||||||
|
REPORTEDAT("createdAt");
|
||||||
|
|
||||||
private final String fieldName;
|
private final String fieldName;
|
||||||
|
|
||||||
|
|||||||
@@ -22,35 +22,35 @@ public enum TenantConfigurationKey {
|
|||||||
* boolean value {@code true} {@code false}.
|
* boolean value {@code true} {@code false}.
|
||||||
*/
|
*/
|
||||||
AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled",
|
AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled",
|
||||||
"hawkbit.server.controller.security.authentication.header.enabled", Boolean.FALSE.toString()),
|
"hawkbit.server.ddi.security.authentication.header.enabled", Boolean.FALSE.toString()),
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME("authentication.header.authority",
|
AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME("authentication.header.authority",
|
||||||
"hawkbit.server.controller.security.authentication.header.authority", Boolean.FALSE.toString()),
|
"hawkbit.server.ddi.security.authentication.header.authority", Boolean.FALSE.toString()),
|
||||||
/**
|
/**
|
||||||
* boolean value {@code true} {@code false}.
|
* boolean value {@code true} {@code false}.
|
||||||
*/
|
*/
|
||||||
AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED("authentication.targettoken.enabled",
|
AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED("authentication.targettoken.enabled",
|
||||||
"hawkbit.server.controller.security.authentication.targettoken.enabled", Boolean.FALSE.toString()),
|
"hawkbit.server.ddi.security.authentication.targettoken.enabled", Boolean.FALSE.toString()),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* boolean value {@code true} {@code false}.
|
* boolean value {@code true} {@code false}.
|
||||||
*/
|
*/
|
||||||
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED("authentication.gatewaytoken.enabled",
|
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED("authentication.gatewaytoken.enabled",
|
||||||
"hawkbit.server.controller.security.authentication.gatewaytoken.enabled", Boolean.FALSE.toString()),
|
"hawkbit.server.ddi.security.authentication.gatewaytoken.enabled", Boolean.FALSE.toString()),
|
||||||
/**
|
/**
|
||||||
* string value which holds the name of the security token key.
|
* string value which holds the name of the security token key.
|
||||||
*/
|
*/
|
||||||
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME("authentication.gatewaytoken.name",
|
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME("authentication.gatewaytoken.name",
|
||||||
"hawkbit.server.controller.security.authentication.gatewaytoken.name", null),
|
"hawkbit.server.ddi.security.authentication.gatewaytoken.name", null),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* string value which holds the actual security-key of the gateway security
|
* string value which holds the actual security-key of the gateway security
|
||||||
* token.
|
* token.
|
||||||
*/
|
*/
|
||||||
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY("authentication.gatewaytoken.key",
|
AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY("authentication.gatewaytoken.key",
|
||||||
"hawkbit.server.controller.security.authentication.gatewaytoken.key", null);
|
"hawkbit.server.ddi.security.authentication.gatewaytoken.key", null);
|
||||||
|
|
||||||
private final String keyName;
|
private final String keyName;
|
||||||
private final String defaultKeyName;
|
private final String defaultKeyName;
|
||||||
|
|||||||
@@ -60,6 +60,11 @@
|
|||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ import org.eclipse.hawkbit.security.CoapAnonymousPreAuthenticatedFilter;
|
|||||||
import org.eclipse.hawkbit.security.ControllerPreAuthenticateSecurityTokenFilter;
|
import org.eclipse.hawkbit.security.ControllerPreAuthenticateSecurityTokenFilter;
|
||||||
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedGatewaySecurityTokenFilter;
|
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedGatewaySecurityTokenFilter;
|
||||||
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedSecurityHeaderFilter;
|
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedSecurityHeaderFilter;
|
||||||
|
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||||
import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider;
|
import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider;
|
||||||
import org.eclipse.hawkbit.security.PreAuthenficationFilter;
|
import org.eclipse.hawkbit.security.PreAuthenficationFilter;
|
||||||
import org.eclipse.hawkbit.security.SecurityProperties;
|
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -55,7 +55,7 @@ public class AmqpControllerAuthentfication {
|
|||||||
private TenantAware tenantAware;
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SecurityProperties secruityProperties;
|
private DdiSecurityProperties ddiSecruityProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@@ -78,8 +78,8 @@ public class AmqpControllerAuthentfication {
|
|||||||
filterChain.add(gatewaySecurityTokenFilter);
|
filterChain.add(gatewaySecurityTokenFilter);
|
||||||
|
|
||||||
final ControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new ControllerPreAuthenticatedSecurityHeaderFilter(
|
final ControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new ControllerPreAuthenticatedSecurityHeaderFilter(
|
||||||
secruityProperties.getRpCnHeader(), secruityProperties.getRpSslIssuerHashHeader(), systemManagement,
|
ddiSecruityProperties.getRp().getCnHeader(), ddiSecruityProperties.getRp().getSslIssuerHashHeader(),
|
||||||
tenantAware);
|
systemManagement, tenantAware);
|
||||||
filterChain.add(securityHeaderFilter);
|
filterChain.add(securityHeaderFilter);
|
||||||
|
|
||||||
final ControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new ControllerPreAuthenticateSecurityTokenFilter(
|
final ControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new ControllerPreAuthenticateSecurityTokenFilter(
|
||||||
@@ -134,8 +134,8 @@ public class AmqpControllerAuthentfication {
|
|||||||
this.controllerManagement = controllerManagement;
|
this.controllerManagement = controllerManagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecruityProperties(final SecurityProperties secruityProperties) {
|
public void setSecruityProperties(final DdiSecurityProperties secruityProperties) {
|
||||||
this.secruityProperties = secruityProperties;
|
this.ddiSecruityProperties = secruityProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSystemManagement(final SystemManagement systemManagement) {
|
public void setSystemManagement(final SystemManagement systemManagement) {
|
||||||
|
|||||||
@@ -8,41 +8,91 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.amqp;
|
package org.eclipse.hawkbit.amqp;
|
||||||
|
|
||||||
|
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean which holds the necessary properties for configuring the AMQP
|
* Bean which holds the necessary properties for configuring the AMQP
|
||||||
* connection.
|
* connection.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
@ConfigurationProperties("hawkbit.dmf.rabbitmq")
|
@ConfigurationProperties("hawkbit.dmf.rabbitmq")
|
||||||
public class AmqpProperties {
|
public class AmqpProperties {
|
||||||
|
/**
|
||||||
|
* DMF API dead letter queue.
|
||||||
|
*/
|
||||||
private String deadLetterQueue = "dmf_receiver_deadletter";
|
private String deadLetterQueue = "dmf_receiver_deadletter";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DMF API dead letter exchange.
|
||||||
|
*/
|
||||||
private String deadLetterExchange = "dmf.receiver.deadletter";
|
private String deadLetterExchange = "dmf.receiver.deadletter";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DMF API receiving queue.
|
||||||
|
*/
|
||||||
private String receiverQueue = "dmf_receiver";
|
private String receiverQueue = "dmf_receiver";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Missing queue fatal.
|
||||||
|
*/
|
||||||
private boolean missingQueuesFatal = false;
|
private boolean missingQueuesFatal = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is missingQueuesFatal enabled
|
||||||
|
*
|
||||||
|
* @see SimpleMessageListenerContainer#setMissingQueuesFatal
|
||||||
|
* @return the missingQueuesFatal <true> enabled <false> disabled
|
||||||
|
*/
|
||||||
public boolean isMissingQueuesFatal() {
|
public boolean isMissingQueuesFatal() {
|
||||||
return missingQueuesFatal;
|
return missingQueuesFatal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param missingQueuesFatal
|
||||||
|
* the missingQueuesFatal to set.
|
||||||
|
* @see SimpleMessageListenerContainer#setMissingQueuesFatal
|
||||||
|
*/
|
||||||
public void setMissingQueuesFatal(final boolean missingQueuesFatal) {
|
public void setMissingQueuesFatal(final boolean missingQueuesFatal) {
|
||||||
this.missingQueuesFatal = missingQueuesFatal;
|
this.missingQueuesFatal = missingQueuesFatal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dead letter exchange.
|
||||||
|
*
|
||||||
|
* @return dead letter exchange
|
||||||
|
*/
|
||||||
public String getDeadLetterExchange() {
|
public String getDeadLetterExchange() {
|
||||||
return deadLetterExchange;
|
return deadLetterExchange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the dead letter exchange.
|
||||||
|
*
|
||||||
|
* @param deadLetterExchange
|
||||||
|
* the deadLetterExchange to be set
|
||||||
|
*/
|
||||||
public void setDeadLetterExchange(final String deadLetterExchange) {
|
public void setDeadLetterExchange(final String deadLetterExchange) {
|
||||||
this.deadLetterExchange = deadLetterExchange;
|
this.deadLetterExchange = deadLetterExchange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dead letter queue.
|
||||||
|
*
|
||||||
|
* @return the dead letter queue
|
||||||
|
*/
|
||||||
public String getDeadLetterQueue() {
|
public String getDeadLetterQueue() {
|
||||||
return deadLetterQueue;
|
return deadLetterQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the dead letter queue.
|
||||||
|
*
|
||||||
|
* @param deadLetterQueue
|
||||||
|
* the deadLetterQueue ro be set
|
||||||
|
*/
|
||||||
public void setDeadLetterQueue(final String deadLetterQueue) {
|
public void setDeadLetterQueue(final String deadLetterQueue) {
|
||||||
this.deadLetterQueue = deadLetterQueue;
|
this.deadLetterQueue = deadLetterQueue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,9 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
|
|||||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||||
|
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||||
|
import org.eclipse.hawkbit.security.DdiSecurityProperties.Rp;
|
||||||
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
||||||
import org.eclipse.hawkbit.security.SecurityProperties;
|
|
||||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -67,8 +68,11 @@ public class AmqpControllerAuthenticationTest {
|
|||||||
|
|
||||||
authenticationManager = new AmqpControllerAuthentfication();
|
authenticationManager = new AmqpControllerAuthentfication();
|
||||||
authenticationManager.setControllerManagement(mock(ControllerManagement.class));
|
authenticationManager.setControllerManagement(mock(ControllerManagement.class));
|
||||||
final SecurityProperties secruityProperties = mock(SecurityProperties.class);
|
|
||||||
when(secruityProperties.getRpSslIssuerHashHeader()).thenReturn("X-Ssl-Issuer-Hash-%d");
|
final DdiSecurityProperties secruityProperties = mock(DdiSecurityProperties.class);
|
||||||
|
final Rp rp = mock(Rp.class);
|
||||||
|
when(secruityProperties.getRp()).thenReturn(rp);
|
||||||
|
when(rp.getSslIssuerHashHeader()).thenReturn("X-Ssl-Issuer-Hash-%d");
|
||||||
authenticationManager.setSecruityProperties(secruityProperties);
|
authenticationManager.setSecruityProperties(secruityProperties);
|
||||||
systemManagement = mock(SystemManagement.class);
|
systemManagement = mock(SystemManagement.class);
|
||||||
authenticationManager.setSystemManagement(systemManagement);
|
authenticationManager.setSystemManagement(systemManagement);
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Tests generate the http download url")
|
@Description("Tests the generation of http download url.")
|
||||||
public void testHttpUrl() {
|
public void testHttpUrl() {
|
||||||
final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.HTTP);
|
final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.HTTP);
|
||||||
assertEquals("http is build incorrect",
|
assertEquals("http is build incorrect",
|
||||||
@@ -67,7 +67,7 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Tests generate the https download url")
|
@Description("Tests the generation of https download url.")
|
||||||
public void testHttpsUrl() {
|
public void testHttpsUrl() {
|
||||||
final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.HTTPS);
|
final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.HTTPS);
|
||||||
assertEquals("https is build incorrect",
|
assertEquals("https is build incorrect",
|
||||||
@@ -78,7 +78,7 @@ public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Tests generate the coap download url")
|
@Description("Tests the generation of coap download url.")
|
||||||
public void testCoapUrl() {
|
public void testCoapUrl() {
|
||||||
final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.COAP);
|
final String url = urlHandlerProperties.getUrl(controllerId, localArtifact, Artifact.UrlProtocol.COAP);
|
||||||
|
|
||||||
|
|||||||
@@ -99,6 +99,11 @@
|
|||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
<artifactId>flyway-core</artifactId>
|
<artifactId>flyway-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -40,10 +40,6 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
|
|||||||
/**
|
/**
|
||||||
* General configuration for the SP Repository.
|
* General configuration for the SP Repository.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@EnableJpaRepositories(basePackages = { "org.eclipse.hawkbit.repository" })
|
@EnableJpaRepositories(basePackages = { "org.eclipse.hawkbit.repository" })
|
||||||
@EnableTransactionManagement
|
@EnableTransactionManagement
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollout Management properties.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties("hawkbit.rollout")
|
||||||
|
public class RolloutProperties {
|
||||||
|
private final Scheduler scheduler = new Scheduler();
|
||||||
|
|
||||||
|
public Scheduler getScheduler() {
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollout scheduler configuration.
|
||||||
|
*/
|
||||||
|
public static class Scheduler {
|
||||||
|
// used by @Scheduled annotation which needs constant
|
||||||
|
public static final String PROP_SCHEDULER_DELAY_PLACEHOLDER = "${hawkbit.rollout.scheduler.fixedDelay:30000}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule where the rollout scheduler looks necessary state changes in
|
||||||
|
* milliseconds.
|
||||||
|
*/
|
||||||
|
private long fixedDelay = 30000L;
|
||||||
|
|
||||||
|
public long getFixedDelay() {
|
||||||
|
return fixedDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFixedDelay(final long fixedDelay) {
|
||||||
|
this.fixedDelay = fixedDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,45 +21,47 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
/**
|
/**
|
||||||
* {@link ActionStatus} repository.
|
* {@link ActionStatus} repository.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public interface ActionStatusRepository
|
public interface ActionStatusRepository
|
||||||
extends BaseEntityRepository<ActionStatus, Long>, JpaSpecificationExecutor<ActionStatus> {
|
extends BaseEntityRepository<ActionStatus, Long>, JpaSpecificationExecutor<ActionStatus> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param target
|
* Counts {@link ActionStatus} entries of given {@link Action} in
|
||||||
|
* repository.
|
||||||
|
*
|
||||||
* @param action
|
* @param action
|
||||||
* @return
|
* to count status entries
|
||||||
|
* @return number of actions in repository
|
||||||
*/
|
*/
|
||||||
Long countByAction(Action action);
|
Long countByAction(Action action);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Counts {@link ActionStatus} entries of given {@link Action} with given
|
||||||
|
* {@link Status} in repository.
|
||||||
|
*
|
||||||
* @param action
|
* @param action
|
||||||
* @param retrieved
|
* to count status entries
|
||||||
* @return
|
* @param status
|
||||||
|
* to filter for
|
||||||
|
* @return number of actions in repository
|
||||||
*/
|
*/
|
||||||
Long countByActionAndStatus(Action action, Status retrieved);
|
Long countByActionAndStatus(Action action, Status status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Retrieves all {@link ActionStatus} entries from repository of given
|
||||||
|
* {@link Action}.
|
||||||
|
*
|
||||||
* @param pageReq
|
* @param pageReq
|
||||||
|
* parameters
|
||||||
* @param action
|
* @param action
|
||||||
* @return
|
* of the status entries
|
||||||
|
* @return pages list of {@link ActionStatus} entries
|
||||||
*/
|
*/
|
||||||
Page<ActionStatus> findByAction(Pageable pageReq, Action action);
|
Page<ActionStatus> findByAction(Pageable pageReq, Action action);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param pageReq
|
* Finds all status updates for the defined action and target including
|
||||||
* @param action
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Page<ActionStatus> findByActionOrderByIdDesc(Pageable pageReq, Action action);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds all status updates for the defined action and target order by
|
|
||||||
* {@link ActionStatus#getId()} desc including
|
|
||||||
* {@link ActionStatus#getMessages()}.
|
* {@link ActionStatus#getMessages()}.
|
||||||
*
|
*
|
||||||
* @param pageReq
|
* @param pageReq
|
||||||
@@ -71,6 +73,6 @@ public interface ActionStatusRepository
|
|||||||
* @return Page with found targets
|
* @return Page with found targets
|
||||||
*/
|
*/
|
||||||
@EntityGraph(value = "ActionStatus.withMessages", type = EntityGraphType.LOAD)
|
@EntityGraph(value = "ActionStatus.withMessages", type = EntityGraphType.LOAD)
|
||||||
Page<ActionStatus> getByActionOrderByIdDesc(Pageable pageReq, Action action);
|
Page<ActionStatus> getByAction(Pageable pageReq, Action action);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,13 +33,11 @@ import org.eclipse.hawkbit.repository.model.Target;
|
|||||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||||
import org.eclipse.hawkbit.repository.model.Target_;
|
import org.eclipse.hawkbit.repository.model.Target_;
|
||||||
|
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||||
import org.hibernate.validator.constraints.NotEmpty;
|
import org.hibernate.validator.constraints.NotEmpty;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.data.jpa.repository.Modifying;
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@@ -57,7 +55,7 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Validated
|
@Validated
|
||||||
@Service
|
@Service
|
||||||
public class ControllerManagement implements EnvironmentAware {
|
public class ControllerManagement {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class);
|
private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class);
|
||||||
private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos");
|
private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos");
|
||||||
|
|
||||||
@@ -85,9 +83,8 @@ public class ControllerManagement implements EnvironmentAware {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ActionStatusRepository actionStatusRepository;
|
private ActionStatusRepository actionStatusRepository;
|
||||||
|
|
||||||
private Integer maxCount = 1000;
|
@Autowired
|
||||||
|
private HawkbitSecurityProperties securityProperties;
|
||||||
private Integer maxAttributes = 100;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes the time of the last time the controller has been connected to
|
* Refreshes the time of the last time the controller has been connected to
|
||||||
@@ -379,15 +376,16 @@ public class ControllerManagement implements EnvironmentAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkForToManyStatusEntries(final Action action) {
|
private void checkForToManyStatusEntries(final Action action) {
|
||||||
if (maxCount > 0) {
|
if (securityProperties.getDos().getMaxStatusEntriesPerAction() > 0) {
|
||||||
|
|
||||||
final Long statusCount = actionStatusRepository.countByAction(action);
|
final Long statusCount = actionStatusRepository.countByAction(action);
|
||||||
|
|
||||||
if (statusCount >= maxCount) {
|
if (statusCount >= securityProperties.getDos().getMaxStatusEntriesPerAction()) {
|
||||||
LOG_DOS.error(
|
LOG_DOS.error(
|
||||||
"Potential denial of service (DOS) attack identfied. More status entries in the system than permitted ({})!",
|
"Potential denial of service (DOS) attack identfied. More status entries in the system than permitted ({})!",
|
||||||
maxCount);
|
securityProperties.getDos().getMaxStatusEntriesPerAction());
|
||||||
throw new ToManyStatusEntriesException(String.valueOf(maxCount));
|
throw new ToManyStatusEntriesException(
|
||||||
|
String.valueOf(securityProperties.getDos().getMaxStatusEntriesPerAction()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -436,10 +434,12 @@ public class ControllerManagement implements EnvironmentAware {
|
|||||||
|
|
||||||
target.getTargetInfo().getControllerAttributes().putAll(data);
|
target.getTargetInfo().getControllerAttributes().putAll(data);
|
||||||
|
|
||||||
if (target.getTargetInfo().getControllerAttributes().size() > maxAttributes) {
|
if (target.getTargetInfo().getControllerAttributes().size() > securityProperties.getDos()
|
||||||
|
.getMaxAttributeEntriesPerTarget()) {
|
||||||
LOG_DOS.info("Target tries to insert more than the allowed number of entries ({}). DOS attack anticipated!",
|
LOG_DOS.info("Target tries to insert more than the allowed number of entries ({}). DOS attack anticipated!",
|
||||||
maxAttributes);
|
securityProperties.getDos().getMaxAttributeEntriesPerTarget());
|
||||||
throw new ToManyAttributeEntriesException(String.valueOf(maxAttributes));
|
throw new ToManyAttributeEntriesException(
|
||||||
|
String.valueOf(securityProperties.getDos().getMaxAttributeEntriesPerTarget()));
|
||||||
}
|
}
|
||||||
|
|
||||||
target.getTargetInfo().setLastTargetQuery(System.currentTimeMillis());
|
target.getTargetInfo().setLastTargetQuery(System.currentTimeMillis());
|
||||||
@@ -447,19 +447,6 @@ public class ControllerManagement implements EnvironmentAware {
|
|||||||
return targetRepository.save(target);
|
return targetRepository.save(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
*
|
|
||||||
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.
|
|
||||||
* springframework.core.env. Environment)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(final Environment environment) {
|
|
||||||
final RelaxedPropertyResolver env = new RelaxedPropertyResolver(environment, "hawkbit.server.");
|
|
||||||
maxCount = env.getProperty("security.dos.maxStatusEntriesPerAction", Integer.class, 1000);
|
|
||||||
maxAttributes = env.getProperty("security.dos.maxAttributeEntriesPerTarget", Integer.class, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers retrieved status for given {@link Target} and {@link Action} if
|
* Registers retrieved status for given {@link Target} and {@link Action} if
|
||||||
* it does not exist yet.
|
* it does not exist yet.
|
||||||
|
|||||||
@@ -925,7 +925,7 @@ public class DeploymentManagement {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* retrieves all the {@link ActionStatus} entries of the given
|
* retrieves all the {@link ActionStatus} entries of the given
|
||||||
* {@link Action} and {@link Target} in the order latest first.
|
* {@link Action} and {@link Target}.
|
||||||
*
|
*
|
||||||
* @param pageReq
|
* @param pageReq
|
||||||
* pagination parameter
|
* pagination parameter
|
||||||
@@ -937,12 +937,12 @@ public class DeploymentManagement {
|
|||||||
* @return the corresponding {@link Page} of {@link ActionStatus}
|
* @return the corresponding {@link Page} of {@link ActionStatus}
|
||||||
*/
|
*/
|
||||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||||
public Page<ActionStatus> findActionStatusMessagesByActionInDescOrder(final Pageable pageReq, final Action action,
|
public Page<ActionStatus> findActionStatusByAction(final Pageable pageReq, final Action action,
|
||||||
final boolean withMessages) {
|
final boolean withMessages) {
|
||||||
if (withMessages) {
|
if (withMessages) {
|
||||||
return actionStatusRepository.getByActionOrderByIdDesc(pageReq, action);
|
return actionStatusRepository.getByAction(pageReq, action);
|
||||||
} else {
|
} else {
|
||||||
return actionStatusRepository.findByActionOrderByIdDesc(pageReq, action);
|
return actionStatusRepository.findByAction(pageReq, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import org.eclipse.hawkbit.repository.model.Target_;
|
|||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -55,14 +54,10 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
/**
|
/**
|
||||||
* Service layer for generating SP reportings.
|
* Service layer for generating SP reportings.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Validated
|
@Validated
|
||||||
@Service
|
@Service
|
||||||
@ConfigurationProperties
|
|
||||||
public class ReportManagement {
|
public class ReportManagement {
|
||||||
|
|
||||||
@Value("${spring.jpa.database}")
|
@Value("${spring.jpa.database}")
|
||||||
|
|||||||
@@ -10,14 +10,13 @@ package org.eclipse.hawkbit.repository;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.RolloutProperties;
|
||||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
import org.springframework.context.annotation.Profile;
|
import org.springframework.context.annotation.Profile;
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -31,15 +30,10 @@ import org.springframework.stereotype.Component;
|
|||||||
// don't active the rollout scheduler in test, otherwise it is hard to test
|
// don't active the rollout scheduler in test, otherwise it is hard to test
|
||||||
// rolloutmanagement and leads weird side-effects maybe.
|
// rolloutmanagement and leads weird side-effects maybe.
|
||||||
@Profile("!test")
|
@Profile("!test")
|
||||||
public class RolloutScheduler implements EnvironmentAware {
|
public class RolloutScheduler {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(RolloutScheduler.class);
|
private static final Logger logger = LoggerFactory.getLogger(RolloutScheduler.class);
|
||||||
|
|
||||||
private static final String PROP_SCHEDULER_DELAY = "hawkbit.rollout.scheduler.fixedDelay";
|
|
||||||
private static final long DEFAULT_SCHEDULER_DELAY = 30000L;
|
|
||||||
private static final String PROP_SCHEDULER_DELAY_PLACEHOLDER = "${" + PROP_SCHEDULER_DELAY + ":"
|
|
||||||
+ DEFAULT_SCHEDULER_DELAY + "}";
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantAware tenantAware;
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
@@ -52,7 +46,8 @@ public class RolloutScheduler implements EnvironmentAware {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SystemSecurityContext systemSecurityContext;
|
private SystemSecurityContext systemSecurityContext;
|
||||||
|
|
||||||
private long fixedDelay = DEFAULT_SCHEDULER_DELAY;
|
@Autowired
|
||||||
|
private RolloutProperties rolloutProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scheduler method called by the spring-async mechanism. Retrieves all
|
* Scheduler method called by the spring-async mechanism. Retrieves all
|
||||||
@@ -60,7 +55,7 @@ public class RolloutScheduler implements EnvironmentAware {
|
|||||||
* tenant the {@link RolloutManagement#checkRunningRollouts(long)} in the
|
* tenant the {@link RolloutManagement#checkRunningRollouts(long)} in the
|
||||||
* {@link SystemSecurityContext}.
|
* {@link SystemSecurityContext}.
|
||||||
*/
|
*/
|
||||||
@Scheduled(initialDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = PROP_SCHEDULER_DELAY_PLACEHOLDER)
|
@Scheduled(initialDelayString = RolloutProperties.Scheduler.PROP_SCHEDULER_DELAY_PLACEHOLDER, fixedDelayString = RolloutProperties.Scheduler.PROP_SCHEDULER_DELAY_PLACEHOLDER)
|
||||||
public void rolloutScheduler() {
|
public void rolloutScheduler() {
|
||||||
logger.debug("rollout schedule checker has been triggered.");
|
logger.debug("rollout schedule checker has been triggered.");
|
||||||
// run this code in system code privileged to have the necessary
|
// run this code in system code privileged to have the necessary
|
||||||
@@ -76,16 +71,11 @@ public class RolloutScheduler implements EnvironmentAware {
|
|||||||
logger.info("Checking rollouts for {} tenants", tenants.size());
|
logger.info("Checking rollouts for {} tenants", tenants.size());
|
||||||
for (final String tenant : tenants) {
|
for (final String tenant : tenants) {
|
||||||
tenantAware.runAsTenant(tenant, () -> {
|
tenantAware.runAsTenant(tenant, () -> {
|
||||||
rolloutManagement.checkRunningRollouts(fixedDelay);
|
rolloutManagement.checkRunningRollouts(rolloutProperties.getScheduler().getFixedDelay());
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(final Environment environment) {
|
|
||||||
fixedDelay = environment.getProperty(PROP_SCHEDULER_DELAY, Long.class, DEFAULT_SCHEDULER_DELAY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
|
|||||||
import org.eclipse.hawkbit.repository.model.helper.EventBusHolder;
|
import org.eclipse.hawkbit.repository.model.helper.EventBusHolder;
|
||||||
import org.eclipse.hawkbit.repository.utils.RepositoryDataGenerator;
|
import org.eclipse.hawkbit.repository.utils.RepositoryDataGenerator;
|
||||||
import org.eclipse.hawkbit.repository.utils.RepositoryDataGenerator.DatabaseCleanupUtil;
|
import org.eclipse.hawkbit.repository.utils.RepositoryDataGenerator.DatabaseCleanupUtil;
|
||||||
|
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||||
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
||||||
import org.eclipse.hawkbit.security.SecurityProperties;
|
|
||||||
import org.eclipse.hawkbit.security.SpringSecurityAuditorAware;
|
import org.eclipse.hawkbit.security.SpringSecurityAuditorAware;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||||
@@ -47,7 +47,7 @@ import com.mongodb.MongoClientOptions;
|
|||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true)
|
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true)
|
||||||
@EnableConfigurationProperties({ SecurityProperties.class, ControllerPollProperties.class })
|
@EnableConfigurationProperties({ DdiSecurityProperties.class, ControllerPollProperties.class })
|
||||||
@Profile("test")
|
@Profile("test")
|
||||||
public class TestConfiguration implements AsyncConfigurer {
|
public class TestConfiguration implements AsyncConfigurer {
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ public class ControllerManagementTest extends AbstractIntegrationTest {
|
|||||||
.isEqualTo(TargetUpdateStatus.IN_SYNC);
|
.isEqualTo(TargetUpdateStatus.IN_SYNC);
|
||||||
|
|
||||||
assertThat(actionStatusRepository.findAll(pageReq).getNumberOfElements()).isEqualTo(3);
|
assertThat(actionStatusRepository.findAll(pageReq).getNumberOfElements()).isEqualTo(3);
|
||||||
assertThat(deploymentManagement.findActionStatusMessagesByActionInDescOrder(pageReq, savedAction, false)
|
assertThat(deploymentManagement.findActionStatusByAction(pageReq, savedAction, false).getNumberOfElements())
|
||||||
.getNumberOfElements()).isEqualTo(3);
|
.isEqualTo(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
spring.data.mongodb.uri=mongodb://localhost/spArtifactRepository${random.value}
|
spring.data.mongodb.uri=mongodb://localhost/spArtifactRepository${random.value}
|
||||||
spring.data.mongodb.port=28017
|
spring.data.mongodb.port=28017
|
||||||
|
|
||||||
hawkbit.server.controller.security.authentication.header.enabled=true
|
hawkbit.server.ddi.security.authentication.header.enabled=true
|
||||||
|
|
||||||
hawkbit.server.artifact.repo.upload.maxFileSize=5MB
|
hawkbit.server.artifact.repo.upload.maxFileSize=5MB
|
||||||
|
|
||||||
@@ -29,11 +29,6 @@ flyway.initOnMigrate=true
|
|||||||
flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
|
flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
|
||||||
#spring.jpa.show-sql=true
|
#spring.jpa.show-sql=true
|
||||||
|
|
||||||
# SP Controller configuration
|
# DDI configuration
|
||||||
hawkbit.controller.pollingTime=00:01:00
|
hawkbit.controller.pollingTime=00:01:00
|
||||||
hawkbit.controller.pollingOverdueTime=00:01:00
|
hawkbit.controller.pollingOverdueTime=00:01:00
|
||||||
|
|
||||||
## Configuration for RabbitMQ integration
|
|
||||||
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter
|
|
||||||
hawkbit.dmf.rabbitmq.deadLetterExchange=dmf.connector.deadletter
|
|
||||||
hawkbit.dmf.rabbitmq.receiverQueue=dmf_receiver
|
|
||||||
@@ -25,13 +25,11 @@ import org.eclipse.hawkbit.repository.model.Artifact;
|
|||||||
import org.eclipse.hawkbit.repository.model.LocalArtifact;
|
import org.eclipse.hawkbit.repository.model.LocalArtifact;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper;
|
import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper;
|
||||||
|
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||||
import org.eclipse.hawkbit.util.IpUtil;
|
import org.eclipse.hawkbit.util.IpUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
|
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
|
||||||
@@ -55,7 +53,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(ControllerConstants.ARTIFACTS_V1_REQUEST_MAPPING)
|
@RequestMapping(ControllerConstants.ARTIFACTS_V1_REQUEST_MAPPING)
|
||||||
public class ArtifactStoreController implements EnvironmentAware {
|
public class ArtifactStoreController {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ArtifactStoreController.class);
|
private static final Logger LOG = LoggerFactory.getLogger(ArtifactStoreController.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -67,14 +65,8 @@ public class ArtifactStoreController implements EnvironmentAware {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private CacheWriteNotify cacheWriteNotify;
|
private CacheWriteNotify cacheWriteNotify;
|
||||||
|
|
||||||
private static final String SP_SERVER_CONFIG_PREFIX = "hawkbit.server.";
|
@Autowired
|
||||||
private RelaxedPropertyResolver environment;
|
private HawkbitSecurityProperties securityProperties;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(final Environment environment) {
|
|
||||||
this.environment = new RelaxedPropertyResolver(environment, SP_SERVER_CONFIG_PREFIX);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles GET {@link Artifact} download request. This could be full or
|
* Handles GET {@link Artifact} download request. This could be full or
|
||||||
@@ -138,8 +130,8 @@ public class ArtifactStoreController implements EnvironmentAware {
|
|||||||
|
|
||||||
private Action checkAndReportDownloadByTarget(final HttpServletRequest request, final String targetid,
|
private Action checkAndReportDownloadByTarget(final HttpServletRequest request, final String targetid,
|
||||||
final LocalArtifact artifact) {
|
final LocalArtifact artifact) {
|
||||||
final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil.getClientIpFromRequest(
|
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
||||||
request, environment.getProperty("security.rp.remote_ip_header", String.class, "X-Forwarded-For")));
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
|
|
||||||
final Action action = controllerManagement
|
final Action action = controllerManagement
|
||||||
.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), artifact.getSoftwareModule());
|
.getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), artifact.getSoftwareModule());
|
||||||
|
|||||||
@@ -41,15 +41,13 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
|||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||||
import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper;
|
import org.eclipse.hawkbit.rest.resource.helper.RestResourceConversionHelper;
|
||||||
|
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||||
import org.eclipse.hawkbit.util.IpUtil;
|
import org.eclipse.hawkbit.util.IpUtil;
|
||||||
import org.hibernate.validator.constraints.NotEmpty;
|
import org.hibernate.validator.constraints.NotEmpty;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@@ -74,7 +72,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(ControllerConstants.BASE_V1_REQUEST_MAPPING)
|
@RequestMapping(ControllerConstants.BASE_V1_REQUEST_MAPPING)
|
||||||
public class RootController implements EnvironmentAware {
|
public class RootController {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(RootController.class);
|
private static final Logger LOG = LoggerFactory.getLogger(RootController.class);
|
||||||
private static final String GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET = "given action ({}) is not assigned to given target ({}).";
|
private static final String GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET = "given action ({}) is not assigned to given target ({}).";
|
||||||
@@ -99,16 +97,8 @@ public class RootController implements EnvironmentAware {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TenantAware tenantAware;
|
private TenantAware tenantAware;
|
||||||
|
|
||||||
private String requestHeader;
|
@Autowired
|
||||||
|
private HawkbitSecurityProperties securityProperties;
|
||||||
@Override
|
|
||||||
public void setEnvironment(final Environment environment) {
|
|
||||||
final RelaxedPropertyResolver relaxedPropertyResolver = new RelaxedPropertyResolver(environment,
|
|
||||||
SP_SERVER_CONFIG_PREFIX);
|
|
||||||
|
|
||||||
requestHeader = relaxedPropertyResolver.getProperty("security.rp.remote_ip_header", String.class,
|
|
||||||
"X-Forwarded-For");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all artifacts of a given software module and target.
|
* Returns all artifacts of a given software module and target.
|
||||||
@@ -155,12 +145,13 @@ public class RootController implements EnvironmentAware {
|
|||||||
LOG.debug("getControllerBase({})", targetid);
|
LOG.debug("getControllerBase({})", targetid);
|
||||||
|
|
||||||
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(targetid,
|
final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(targetid,
|
||||||
IpUtil.getClientIpFromRequest(request, requestHeader));
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
|
|
||||||
if (target.getTargetInfo().getUpdateStatus() == TargetUpdateStatus.UNKNOWN) {
|
if (target.getTargetInfo().getUpdateStatus() == TargetUpdateStatus.UNKNOWN) {
|
||||||
LOG.debug("target with {} extsisted but was in status UNKNOWN -> REGISTERED)", targetid);
|
LOG.debug("target with {} extsisted but was in status UNKNOWN -> REGISTERED)", targetid);
|
||||||
controllerManagement.updateTargetStatus(target.getTargetInfo(), TargetUpdateStatus.REGISTERED,
|
controllerManagement.updateTargetStatus(target.getTargetInfo(), TargetUpdateStatus.REGISTERED,
|
||||||
System.currentTimeMillis(), IpUtil.getClientIpFromRequest(request, requestHeader));
|
System.currentTimeMillis(),
|
||||||
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ResponseEntity<>(
|
return new ResponseEntity<>(
|
||||||
@@ -195,7 +186,7 @@ public class RootController implements EnvironmentAware {
|
|||||||
ResponseEntity<Void> result;
|
ResponseEntity<Void> result;
|
||||||
|
|
||||||
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
||||||
IpUtil.getClientIpFromRequest(request, requestHeader));
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId);
|
final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId);
|
||||||
|
|
||||||
if (checkModule(fileName, module)) {
|
if (checkModule(fileName, module)) {
|
||||||
@@ -265,7 +256,8 @@ public class RootController implements EnvironmentAware {
|
|||||||
public ResponseEntity<Void> downloadArtifactMd5(@PathVariable final String targetid,
|
public ResponseEntity<Void> downloadArtifactMd5(@PathVariable final String targetid,
|
||||||
@PathVariable final Long softwareModuleId, @PathVariable final String fileName,
|
@PathVariable final Long softwareModuleId, @PathVariable final String fileName,
|
||||||
final HttpServletResponse response, final HttpServletRequest request) {
|
final HttpServletResponse response, final HttpServletRequest request) {
|
||||||
controllerManagement.updateLastTargetQuery(targetid, IpUtil.getClientIpFromRequest(request, requestHeader));
|
controllerManagement.updateLastTargetQuery(targetid,
|
||||||
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
|
|
||||||
final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId);
|
final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId);
|
||||||
|
|
||||||
@@ -311,7 +303,7 @@ public class RootController implements EnvironmentAware {
|
|||||||
LOG.debug("getControllerBasedeploymentAction({},{})", targetid, resource);
|
LOG.debug("getControllerBasedeploymentAction({},{})", targetid, resource);
|
||||||
|
|
||||||
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
||||||
IpUtil.getClientIpFromRequest(request, requestHeader));
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
|
|
||||||
final Action action = findActionWithExceptionIfNotFound(actionId);
|
final Action action = findActionWithExceptionIfNotFound(actionId);
|
||||||
if (!action.getTarget().getId().equals(target.getId())) {
|
if (!action.getTarget().getId().equals(target.getId())) {
|
||||||
@@ -362,7 +354,7 @@ public class RootController implements EnvironmentAware {
|
|||||||
LOG.debug("provideBasedeploymentActionFeedback for target [{},{}]: {}", targetid, actionId, feedback);
|
LOG.debug("provideBasedeploymentActionFeedback for target [{},{}]: {}", targetid, actionId, feedback);
|
||||||
|
|
||||||
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
||||||
IpUtil.getClientIpFromRequest(request, requestHeader));
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
|
|
||||||
if (!actionId.equals(feedback.getId())) {
|
if (!actionId.equals(feedback.getId())) {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
@@ -467,7 +459,8 @@ public class RootController implements EnvironmentAware {
|
|||||||
+ ControllerConstants.CONFIG_DATA_ACTION, method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
|
+ ControllerConstants.CONFIG_DATA_ACTION, method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public ResponseEntity<Void> putConfigData(@Valid @RequestBody final ConfigData configData,
|
public ResponseEntity<Void> putConfigData(@Valid @RequestBody final ConfigData configData,
|
||||||
@PathVariable final String targetid, final HttpServletRequest request) {
|
@PathVariable final String targetid, final HttpServletRequest request) {
|
||||||
controllerManagement.updateLastTargetQuery(targetid, IpUtil.getClientIpFromRequest(request, requestHeader));
|
controllerManagement.updateLastTargetQuery(targetid,
|
||||||
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
|
|
||||||
controllerManagement.updateControllerAttributes(targetid, configData.getData());
|
controllerManagement.updateControllerAttributes(targetid, configData.getData());
|
||||||
|
|
||||||
@@ -493,7 +486,7 @@ public class RootController implements EnvironmentAware {
|
|||||||
LOG.debug("getControllerCancelAction({})", targetid);
|
LOG.debug("getControllerCancelAction({})", targetid);
|
||||||
|
|
||||||
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
||||||
IpUtil.getClientIpFromRequest(request, requestHeader));
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
|
|
||||||
final Action action = findActionWithExceptionIfNotFound(actionId);
|
final Action action = findActionWithExceptionIfNotFound(actionId);
|
||||||
if (!action.getTarget().getId().equals(target.getId())) {
|
if (!action.getTarget().getId().equals(target.getId())) {
|
||||||
@@ -540,7 +533,7 @@ public class RootController implements EnvironmentAware {
|
|||||||
LOG.debug("provideCancelActionFeedback for target [{}]: {}", targetid, feedback);
|
LOG.debug("provideCancelActionFeedback for target [{}]: {}", targetid, feedback);
|
||||||
|
|
||||||
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
final Target target = controllerManagement.updateLastTargetQuery(targetid,
|
||||||
IpUtil.getClientIpFromRequest(request, requestHeader));
|
IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader()));
|
||||||
|
|
||||||
if (!actionId.equals(feedback.getId())) {
|
if (!actionId.equals(feedback.getId())) {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
|
|||||||
@@ -23,11 +23,6 @@ import org.springframework.data.domain.Sort.Direction;
|
|||||||
/**
|
/**
|
||||||
* Utility class for for paged body generation.
|
* Utility class for for paged body generation.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public final class PagingUtility {
|
public final class PagingUtility {
|
||||||
/*
|
/*
|
||||||
@@ -90,8 +85,9 @@ public final class PagingUtility {
|
|||||||
if (sortParam != null) {
|
if (sortParam != null) {
|
||||||
sorting = new Sort(SortUtility.parse(ActionFields.class, sortParam));
|
sorting = new Sort(SortUtility.parse(ActionFields.class, sortParam));
|
||||||
} else {
|
} else {
|
||||||
// default sort
|
// default sort is DESC in case of action to match behavior
|
||||||
sorting = new Sort(Direction.ASC, ActionFields.ID.getFieldName());
|
// of management UI (last entry on top)
|
||||||
|
sorting = new Sort(Direction.DESC, ActionFields.ID.getFieldName());
|
||||||
}
|
}
|
||||||
return sorting;
|
return sorting;
|
||||||
}
|
}
|
||||||
@@ -101,8 +97,9 @@ public final class PagingUtility {
|
|||||||
if (sortParam != null) {
|
if (sortParam != null) {
|
||||||
sorting = new Sort(SortUtility.parse(ActionStatusFields.class, sortParam));
|
sorting = new Sort(SortUtility.parse(ActionStatusFields.class, sortParam));
|
||||||
} else {
|
} else {
|
||||||
// default sort
|
// default sort is DESC in case of action status to match behavior
|
||||||
sorting = new Sort(Direction.ASC, ActionStatusFields.ID.getFieldName());
|
// of management UI (last entry on top)
|
||||||
|
sorting = new Sort(Direction.DESC, ActionStatusFields.ID.getFieldName());
|
||||||
}
|
}
|
||||||
return sorting;
|
return sorting;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -297,8 +297,8 @@ final public class TargetMapper {
|
|||||||
final ActionStatusRest result = new ActionStatusRest();
|
final ActionStatusRest result = new ActionStatusRest();
|
||||||
|
|
||||||
result.setMessages(actionStatus.getMessages());
|
result.setMessages(actionStatus.getMessages());
|
||||||
result.setReportedAt(action.getCreatedAt());
|
result.setReportedAt(actionStatus.getCreatedAt());
|
||||||
result.setStatusId(action.getId());
|
result.setStatusId(actionStatus.getId());
|
||||||
result.setType(getNameOfActionStatusType(actionStatus.getStatus()));
|
result.setType(getNameOfActionStatusType(actionStatus.getStatus()));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ public class TargetResource implements TargetRestApi {
|
|||||||
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
final int sanitizedLimitParam = PagingUtility.sanitizePageLimitParam(pagingLimitParam);
|
||||||
final Sort sorting = PagingUtility.sanitizeActionStatusSortParam(sortParam);
|
final Sort sorting = PagingUtility.sanitizeActionStatusSortParam(sortParam);
|
||||||
|
|
||||||
final Page<ActionStatus> statusList = this.deploymentManagement.findActionStatusMessagesByActionInDescOrder(
|
final Page<ActionStatus> statusList = this.deploymentManagement.findActionStatusByAction(
|
||||||
new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting), action, true);
|
new OffsetBasedPageRequest(sanitizedOffsetParam, sanitizedLimitParam, sorting), action, true);
|
||||||
|
|
||||||
return new ResponseEntity<>(
|
return new ResponseEntity<>(
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.rest.resource;
|
|||||||
import static org.fest.assertions.api.Assertions.assertThat;
|
import static org.fest.assertions.api.Assertions.assertThat;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.not;
|
import static org.hamcrest.CoreMatchers.not;
|
||||||
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
import static org.hamcrest.Matchers.hasKey;
|
import static org.hamcrest.Matchers.hasKey;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
@@ -34,6 +35,7 @@ import org.eclipse.hawkbit.TestDataUtil;
|
|||||||
import org.eclipse.hawkbit.WithUser;
|
import org.eclipse.hawkbit.WithUser;
|
||||||
import org.eclipse.hawkbit.exception.SpServerError;
|
import org.eclipse.hawkbit.exception.SpServerError;
|
||||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||||
|
import org.eclipse.hawkbit.repository.ActionFields;
|
||||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
@@ -109,27 +111,24 @@ public class TargetResourceTest extends AbstractIntegrationTest {
|
|||||||
new ActionStatus(actions.get(0), Status.FINISHED, System.currentTimeMillis(), "testmessage"),
|
new ActionStatus(actions.get(0), Status.FINISHED, System.currentTimeMillis(), "testmessage"),
|
||||||
actions.get(0));
|
actions.get(0));
|
||||||
|
|
||||||
final PageRequest pageRequest = new PageRequest(0, 1000, Direction.ASC, ActionStatusFields.ID.getFieldName());
|
final PageRequest pageRequest = new PageRequest(0, 1000, Direction.ASC, ActionFields.ID.getFieldName());
|
||||||
|
final ActionStatus status = deploymentManagement
|
||||||
|
.findActionsByTarget(pageRequest, targetManagement.findTargetByControllerID(knownTargetId)).getContent()
|
||||||
|
.get(0).getActionStatus().stream().sorted((e1, e2) -> Long.compare(e2.getId(), e1.getId()))
|
||||||
|
.collect(Collectors.toList()).get(0);
|
||||||
|
|
||||||
// limit to 1 - first page -> standard cancel message
|
|
||||||
final Long reportAt = deploymentManagement
|
|
||||||
.findActionsByTarget(pageRequest, targetManagement.findTargetByControllerID(knownTargetId)).getContent()
|
|
||||||
.get(0).getCreatedAt();
|
|
||||||
final Long id = deploymentManagement
|
|
||||||
.findActionsByTarget(pageRequest, targetManagement.findTargetByControllerID(knownTargetId)).getContent()
|
|
||||||
.get(0).getId();
|
|
||||||
mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||||
+ RestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId() + "/status")
|
+ RestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId() + "/status")
|
||||||
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))
|
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))
|
||||||
.param(RestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC"))
|
.param(RestConstants.REQUEST_PARAMETER_SORTING, "ID:DESC"))
|
||||||
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
|
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
|
||||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(3)))
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(3)))
|
||||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
|
||||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)))
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)))
|
||||||
.andExpect(jsonPath("content.[0].id", equalTo(id.intValue())))
|
.andExpect(jsonPath("content.[0].id", equalTo(status.getId().intValue())))
|
||||||
.andExpect(jsonPath("content.[0].type", equalTo("finished")))
|
.andExpect(jsonPath("content.[0].type", equalTo("finished")))
|
||||||
.andExpect(jsonPath("content.[0].messages", hasSize(1)))
|
.andExpect(jsonPath("content.[0].messages", hasSize(1)))
|
||||||
.andExpect(jsonPath("content.[0].reportedAt", equalTo(reportAt)))
|
.andExpect(jsonPath("content.[0].reportedAt", equalTo(status.getCreatedAt().longValue())))
|
||||||
.andExpect(jsonPath("content.[1].type", equalTo("canceling")));
|
.andExpect(jsonPath("content.[1].type", equalTo("canceling")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -839,7 +838,8 @@ public class TargetResourceTest extends AbstractIntegrationTest {
|
|||||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
||||||
|
|
||||||
mvc.perform(get(
|
mvc.perform(get(
|
||||||
RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS))
|
RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS)
|
||||||
|
.param(RestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC"))
|
||||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("content.[1].id", equalTo(actions.get(1).getId().intValue())))
|
.andExpect(jsonPath("content.[1].id", equalTo(actions.get(1).getId().intValue())))
|
||||||
.andExpect(jsonPath("content.[1].type", equalTo("update")))
|
.andExpect(jsonPath("content.[1].type", equalTo("update")))
|
||||||
@@ -856,6 +856,108 @@ public class TargetResourceTest extends AbstractIntegrationTest {
|
|||||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verfies that the API returns the status list with expected content.")
|
||||||
|
public void getMultipleActionStatus() throws Exception {
|
||||||
|
final String knownTargetId = "targetId";
|
||||||
|
final Action action = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId).get(0);
|
||||||
|
// retrieve list in default descending order for actionstaus entries
|
||||||
|
final List<ActionStatus> actionStatus = action.getActionStatus().stream()
|
||||||
|
.sorted((e1, e2) -> Long.compare(e2.getId(), e1.getId())).collect(Collectors.toList());
|
||||||
|
|
||||||
|
// sort is default descending order, latest status first
|
||||||
|
mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||||
|
+ RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("content.[0].id", equalTo(actionStatus.get(0).getId().intValue())))
|
||||||
|
.andExpect(jsonPath("content.[0].type", equalTo("canceling")))
|
||||||
|
.andExpect(jsonPath("content.[0].messages", hasItem("manual cancelation requested")))
|
||||||
|
.andExpect(jsonPath("content.[0].reportedAt", equalTo(actionStatus.get(0).getCreatedAt())))
|
||||||
|
.andExpect(jsonPath("content.[1].id", equalTo(actionStatus.get(1).getId().intValue())))
|
||||||
|
.andExpect(jsonPath("content.[1].type", equalTo("running")))
|
||||||
|
.andExpect(jsonPath("content.[1].reportedAt", equalTo(actionStatus.get(1).getCreatedAt())))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verfies that the API returns the status list with expected content sorted by reportedAt field.")
|
||||||
|
public void getMultipleActionStatusSortedByReportedAt() throws Exception {
|
||||||
|
final String knownTargetId = "targetId";
|
||||||
|
final Action action = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId).get(0);
|
||||||
|
final List<ActionStatus> actionStatus = action.getActionStatus().stream()
|
||||||
|
.sorted((e1, e2) -> Long.compare(e1.getId(), e2.getId())).collect(Collectors.toList());
|
||||||
|
|
||||||
|
// descending order
|
||||||
|
mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||||
|
+ RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS)
|
||||||
|
.param(RestConstants.REQUEST_PARAMETER_SORTING, "REPORTEDAT:DESC"))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("content.[0].id", equalTo(actionStatus.get(1).getId().intValue())))
|
||||||
|
.andExpect(jsonPath("content.[0].type", equalTo("canceling")))
|
||||||
|
.andExpect(jsonPath("content.[0].messages", hasItem("manual cancelation requested")))
|
||||||
|
.andExpect(jsonPath("content.[0].reportedAt", equalTo(actionStatus.get(1).getCreatedAt())))
|
||||||
|
.andExpect(jsonPath("content.[1].id", equalTo(actionStatus.get(0).getId().intValue())))
|
||||||
|
.andExpect(jsonPath("content.[1].type", equalTo("running")))
|
||||||
|
.andExpect(jsonPath("content.[1].reportedAt", equalTo(actionStatus.get(0).getCreatedAt())))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||||
|
|
||||||
|
// ascending order
|
||||||
|
mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||||
|
+ RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS)
|
||||||
|
.param(RestConstants.REQUEST_PARAMETER_SORTING, "REPORTEDAT:ASC"))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("content.[1].id", equalTo(actionStatus.get(1).getId().intValue())))
|
||||||
|
.andExpect(jsonPath("content.[1].type", equalTo("canceling")))
|
||||||
|
.andExpect(jsonPath("content.[1].messages", hasItem("manual cancelation requested")))
|
||||||
|
.andExpect(jsonPath("content.[1].reportedAt", equalTo(actionStatus.get(1).getCreatedAt())))
|
||||||
|
.andExpect(jsonPath("content.[0].id", equalTo(actionStatus.get(0).getId().intValue())))
|
||||||
|
.andExpect(jsonPath("content.[0].type", equalTo("running")))
|
||||||
|
.andExpect(jsonPath("content.[0].reportedAt", equalTo(actionStatus.get(0).getCreatedAt())))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(2)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verfies that the API returns the status list with expected content split into two pages.")
|
||||||
|
public void getMultipleActionStatusWithPagingLimitRequestParameter() throws Exception {
|
||||||
|
final String knownTargetId = "targetId";
|
||||||
|
|
||||||
|
final Action action = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId).get(0);
|
||||||
|
final List<ActionStatus> actionStatus = action.getActionStatus().stream()
|
||||||
|
.sorted((e1, e2) -> Long.compare(e1.getId(), e2.getId())).collect(Collectors.toList());
|
||||||
|
|
||||||
|
// Page 1
|
||||||
|
mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||||
|
+ RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS)
|
||||||
|
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1)))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("content.[0].id", equalTo(actionStatus.get(1).getId().intValue())))
|
||||||
|
.andExpect(jsonPath("content.[0].type", equalTo("canceling")))
|
||||||
|
.andExpect(jsonPath("content.[0].messages", hasItem("manual cancelation requested")))
|
||||||
|
.andExpect(jsonPath("content.[0].reportedAt", equalTo(actionStatus.get(1).getCreatedAt())))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
|
||||||
|
|
||||||
|
// Page 2
|
||||||
|
mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
||||||
|
+ RestConstants.TARGET_V1_ACTIONS + "/" + action.getId() + "/" + RestConstants.TARGET_V1_ACTION_STATUS)
|
||||||
|
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1))
|
||||||
|
.param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1)))
|
||||||
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("content.[0].id", equalTo(actionStatus.get(0).getId().intValue())))
|
||||||
|
.andExpect(jsonPath("content.[0].type", equalTo("running")))
|
||||||
|
.andExpect(jsonPath("content.[0].reportedAt", equalTo(actionStatus.get(0).getCreatedAt())))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(2)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(1)))
|
||||||
|
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(1)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getMultipleActionsWithPagingLimitRequestParameter() throws Exception {
|
public void getMultipleActionsWithPagingLimitRequestParameter() throws Exception {
|
||||||
final String knownTargetId = "targetId";
|
final String knownTargetId = "targetId";
|
||||||
@@ -864,7 +966,8 @@ public class TargetResourceTest extends AbstractIntegrationTest {
|
|||||||
// page 1: one entry
|
// page 1: one entry
|
||||||
mvc.perform(get(
|
mvc.perform(get(
|
||||||
RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS)
|
RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS)
|
||||||
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1)))
|
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1))
|
||||||
|
.param(RestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC"))
|
||||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("content.[0].id", equalTo(actions.get(0).getId().intValue())))
|
.andExpect(jsonPath("content.[0].id", equalTo(actions.get(0).getId().intValue())))
|
||||||
.andExpect(jsonPath("content.[0].type", equalTo("cancel")))
|
.andExpect(jsonPath("content.[0].type", equalTo("cancel")))
|
||||||
@@ -879,7 +982,9 @@ public class TargetResourceTest extends AbstractIntegrationTest {
|
|||||||
mvc.perform(get(
|
mvc.perform(get(
|
||||||
RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS)
|
RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/" + RestConstants.TARGET_V1_ACTIONS)
|
||||||
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1))
|
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(1))
|
||||||
.param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1)))
|
.param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1))
|
||||||
|
.param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1))
|
||||||
|
.param(RestConstants.REQUEST_PARAMETER_SORTING, "ID:ASC"))
|
||||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("content.[0].id", equalTo(actions.get(1).getId().intValue())))
|
.andExpect(jsonPath("content.[0].id", equalTo(actions.get(1).getId().intValue())))
|
||||||
.andExpect(jsonPath("content.[0].type", equalTo("update")))
|
.andExpect(jsonPath("content.[0].type", equalTo("update")))
|
||||||
@@ -907,7 +1012,8 @@ public class TargetResourceTest extends AbstractIntegrationTest {
|
|||||||
+ "?offset=0&limit=50&sort=id:DESC";
|
+ "?offset=0&limit=50&sort=id:DESC";
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Action> generateTargetWithTwoUpdatesWithOneOverride(final String knownTargetId) {
|
private List<Action> generateTargetWithTwoUpdatesWithOneOverride(final String knownTargetId)
|
||||||
|
throws InterruptedException {
|
||||||
|
|
||||||
final PageRequest pageRequest = new PageRequest(0, 100, Direction.ASC, ActionStatusFields.ID.getFieldName());
|
final PageRequest pageRequest = new PageRequest(0, 100, Direction.ASC, ActionStatusFields.ID.getFieldName());
|
||||||
|
|
||||||
@@ -925,6 +1031,8 @@ public class TargetResourceTest extends AbstractIntegrationTest {
|
|||||||
final List<Target> updatedTargets = deploymentManagement.assignDistributionSet(one, targets)
|
final List<Target> updatedTargets = deploymentManagement.assignDistributionSet(one, targets)
|
||||||
.getAssignedTargets();
|
.getAssignedTargets();
|
||||||
// 2nd update
|
// 2nd update
|
||||||
|
// sleep 10ms to ensure that we can sort by reportedAt
|
||||||
|
Thread.sleep(10);
|
||||||
deploymentManagement.assignDistributionSet(two, updatedTargets);
|
deploymentManagement.assignDistributionSet(two, updatedTargets);
|
||||||
|
|
||||||
// two updates, one cancelation
|
// two updates, one cancelation
|
||||||
@@ -951,54 +1059,6 @@ public class TargetResourceTest extends AbstractIntegrationTest {
|
|||||||
equalTo(generateStatusreferenceLink(knownTargetId, actions.get(1)))));
|
equalTo(generateStatusreferenceLink(knownTargetId, actions.get(1)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getActionStatusWithMultipleResultsWithPagingLimitRequestParameter() throws Exception {
|
|
||||||
final int limitSize = 1;
|
|
||||||
final String knownTargetId = "targetId";
|
|
||||||
final List<Action> actions = generateTargetWithTwoUpdatesWithOneOverride(knownTargetId);
|
|
||||||
actions.get(0).setStatus(Status.RUNNING);
|
|
||||||
controllerManagament.addUpdateActionStatus(
|
|
||||||
new ActionStatus(actions.get(0), Status.RUNNING, System.currentTimeMillis(), "testmessage"),
|
|
||||||
actions.get(0));
|
|
||||||
|
|
||||||
final PageRequest pageRequest = new PageRequest(0, 1000, Direction.ASC, ActionStatusFields.ID.getFieldName());
|
|
||||||
|
|
||||||
// limit to 1 - first page -> standard cancel message
|
|
||||||
Long reportAt = deploymentManagement
|
|
||||||
.findActionsByTarget(pageRequest, targetManagement.findTargetByControllerID(knownTargetId)).getContent()
|
|
||||||
.get(0).getCreatedAt();
|
|
||||||
Long id = deploymentManagement
|
|
||||||
.findActionsByTarget(pageRequest, targetManagement.findTargetByControllerID(knownTargetId)).getContent()
|
|
||||||
.get(0).getId();
|
|
||||||
mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
|
||||||
+ RestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId() + "/status")
|
|
||||||
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize)))
|
|
||||||
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(3)))
|
|
||||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(limitSize)))
|
|
||||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_CONTENT, hasSize(limitSize)))
|
|
||||||
.andExpect(jsonPath("content.[0].id", equalTo(id.intValue())))
|
|
||||||
.andExpect(jsonPath("content.[0].type", equalTo("running")))
|
|
||||||
.andExpect(jsonPath("content.[0].messages", hasSize(1)))
|
|
||||||
.andExpect(jsonPath("content.[0].reportedAt", equalTo(reportAt)));
|
|
||||||
|
|
||||||
// limit to 1 - first page -> added custom message
|
|
||||||
reportAt = deploymentManagement
|
|
||||||
.findActionsByTarget(pageRequest, targetManagement.findTargetByControllerID(knownTargetId)).getContent()
|
|
||||||
.get(1).getCreatedAt();
|
|
||||||
id = deploymentManagement
|
|
||||||
.findActionsByTarget(pageRequest, targetManagement.findTargetByControllerID(knownTargetId)).getContent()
|
|
||||||
.get(1).getCreatedAt();
|
|
||||||
|
|
||||||
mvc.perform(get(RestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownTargetId + "/"
|
|
||||||
+ RestConstants.TARGET_V1_ACTIONS + "/" + actions.get(0).getId() + "/status")
|
|
||||||
.param(RestConstants.REQUEST_PARAMETER_PAGING_LIMIT, String.valueOf(limitSize))
|
|
||||||
.param(RestConstants.REQUEST_PARAMETER_PAGING_OFFSET, String.valueOf(1)))
|
|
||||||
.andExpect(status().isOk()).andDo(MockMvcResultPrinter.print())
|
|
||||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_TOTAL, equalTo(3)))
|
|
||||||
.andExpect(jsonPath(JSON_PATH_PAGED_LIST_SIZE, equalTo(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void assignDistributionSetToTarget() throws Exception {
|
public void assignDistributionSetToTarget() throws Exception {
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ hawkbit.server.database=H2
|
|||||||
hawkbit.server.database.env=TEST
|
hawkbit.server.database.env=TEST
|
||||||
spring.main.show_banner=false
|
spring.main.show_banner=false
|
||||||
|
|
||||||
hawkbit.server.controller.security.authentication.header=true
|
hawkbit.server.ddi.security.authentication.header=true
|
||||||
|
|
||||||
hawkbit.server.artifact.repo.upload.maxFileSize=5MB
|
hawkbit.server.artifact.repo.upload.maxFileSize=5MB
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
</Console>
|
</Console>
|
||||||
</Appenders>
|
</Appenders>
|
||||||
<Loggers>
|
<Loggers>
|
||||||
<Logger name="org.eclipse.hawkbit.MockMvcResultPrinter" level="debug" />
|
<Logger name="org.eclipse.hawkbit.MockMvcResultPrinter" level="error" />
|
||||||
|
|
||||||
<Root level="error">
|
<Root level="error">
|
||||||
<AppenderRef ref="Console"/>
|
<AppenderRef ref="Console"/>
|
||||||
|
|||||||
@@ -59,6 +59,11 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot</artifactId>
|
<artifactId>spring-boot</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -0,0 +1,219 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The common properties for DDI security.
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties("hawkbit.server.ddi.security")
|
||||||
|
public class DdiSecurityProperties {
|
||||||
|
|
||||||
|
private final Rp rp = new Rp();
|
||||||
|
private final Authentication authentication = new Authentication();
|
||||||
|
|
||||||
|
public Authentication getAuthentication() {
|
||||||
|
return authentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rp getRp() {
|
||||||
|
return rp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse proxy configuration. Defines the security properties for
|
||||||
|
* authenticating controllers behind a reverse proxy which terminates the
|
||||||
|
* SSL session at the reverse proxy but adding request header which contains
|
||||||
|
* the CN of the certificate.
|
||||||
|
*/
|
||||||
|
public static class Rp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP header field for common name of a DDI target client certificate.
|
||||||
|
*/
|
||||||
|
private String cnHeader = "X-Ssl-Client-Cn";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP header field for issuer hash of a DDI target client certificate.
|
||||||
|
*/
|
||||||
|
private String sslIssuerHashHeader = "X-Ssl-Issuer-Hash-%d";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of trusted (reverse proxy) IP addresses for performing DDI
|
||||||
|
* client certificate authentication.
|
||||||
|
*/
|
||||||
|
private List<String> trustedIPs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the cnHeader
|
||||||
|
*/
|
||||||
|
public String getCnHeader() {
|
||||||
|
return cnHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cnHeader
|
||||||
|
* the cnHeader to set
|
||||||
|
*/
|
||||||
|
public void setCnHeader(final String cnHeader) {
|
||||||
|
this.cnHeader = cnHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the sslIssuerHashHeader
|
||||||
|
*/
|
||||||
|
public String getSslIssuerHashHeader() {
|
||||||
|
return sslIssuerHashHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sslIssuerHashHeader
|
||||||
|
* the sslIssuerHashHeader to set
|
||||||
|
*/
|
||||||
|
public void setSslIssuerHashHeader(final String sslIssuerHashHeader) {
|
||||||
|
this.sslIssuerHashHeader = sslIssuerHashHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the trustedIPs
|
||||||
|
*/
|
||||||
|
public List<String> getTrustedIPs() {
|
||||||
|
return trustedIPs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param trustedIPs
|
||||||
|
* the trustedIPs to set
|
||||||
|
*/
|
||||||
|
public void setTrustedIPs(final List<String> trustedIPs) {
|
||||||
|
this.trustedIPs = trustedIPs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DDI Authentication options.
|
||||||
|
*/
|
||||||
|
public static class Authentication {
|
||||||
|
private final Anonymous anonymous = new Anonymous();
|
||||||
|
private final Targettoken targettoken = new Targettoken();
|
||||||
|
private final Gatewaytoken gatewaytoken = new Gatewaytoken();
|
||||||
|
|
||||||
|
public Anonymous getAnonymous() {
|
||||||
|
return anonymous;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Gatewaytoken getGatewaytoken() {
|
||||||
|
return gatewaytoken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Targettoken getTargettoken() {
|
||||||
|
return targettoken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target token authentication. Tokens are defined per target.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Targettoken {
|
||||||
|
/**
|
||||||
|
* Set to true to enable target token authentication.
|
||||||
|
*/
|
||||||
|
private boolean enabled = false;
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(final boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gateway token authentication. Tokens are defined per tenant. Use with
|
||||||
|
* care!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Gatewaytoken {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gateway token based authentication enabled.
|
||||||
|
*/
|
||||||
|
private boolean enabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default gateway token name.
|
||||||
|
*/
|
||||||
|
private String name = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default gateway token itself.
|
||||||
|
*/
|
||||||
|
private String key = "";
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(final boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKey(final String key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anonymous authentication.
|
||||||
|
*/
|
||||||
|
public static class Anonymous {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to true to enable anonymous DDI client authentication.
|
||||||
|
*/
|
||||||
|
private boolean enabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param enabled
|
||||||
|
* the enabled to set
|
||||||
|
*/
|
||||||
|
public void setEnabled(final boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the enabled
|
||||||
|
*/
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security related hawkbit configuration.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties("hawkbit.server.security")
|
||||||
|
public class HawkbitSecurityProperties {
|
||||||
|
|
||||||
|
private final Clients clients = new Clients();
|
||||||
|
private final Dos dos = new Dos();
|
||||||
|
private final Xframe xframe = new Xframe();
|
||||||
|
|
||||||
|
public Dos getDos() {
|
||||||
|
return dos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Clients getClients() {
|
||||||
|
return clients;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Xframe getXframe() {
|
||||||
|
return xframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the XFrameOption policy.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Xframe {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XFrame option. Allowed values: SAMEORIGIN, DENY, ALLOW-FROM
|
||||||
|
*/
|
||||||
|
private String option = "DENY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ALLOW-FROM defined URL, has to be filled in case ALLOW-FROM option is
|
||||||
|
* selected.
|
||||||
|
*/
|
||||||
|
private String allowfrom = "";
|
||||||
|
|
||||||
|
public String getOption() {
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOption(final String option) {
|
||||||
|
this.option = option;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAllowfrom() {
|
||||||
|
return allowfrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowfrom(final String allowfrom) {
|
||||||
|
this.allowfrom = allowfrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Security configuration related to clients.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Clients {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blacklisted client (IP addresses) for for DDI and Management API.
|
||||||
|
*/
|
||||||
|
private String blacklist = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the http header from which the remote ip is extracted.
|
||||||
|
*/
|
||||||
|
private String remoteIpHeader = "X-Forwarded-For";
|
||||||
|
|
||||||
|
public String getBlacklist() {
|
||||||
|
return blacklist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlacklist(final String blacklist) {
|
||||||
|
this.blacklist = blacklist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemoteIpHeader() {
|
||||||
|
return remoteIpHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemoteIpHeader(final String remoteIpHeader) {
|
||||||
|
this.remoteIpHeader = remoteIpHeader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denial of service protection related properties.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Dos {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of status updates that the controller can report for
|
||||||
|
* an action (0 to disable).
|
||||||
|
*/
|
||||||
|
private int maxStatusEntriesPerAction = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of attributes that the controller can report;
|
||||||
|
*/
|
||||||
|
private int maxAttributeEntriesPerTarget = 100;
|
||||||
|
|
||||||
|
private final Filter filter = new Filter();
|
||||||
|
|
||||||
|
public Filter getFilter() {
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxStatusEntriesPerAction() {
|
||||||
|
return maxStatusEntriesPerAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxStatusEntriesPerAction(final int maxStatusEntriesPerAction) {
|
||||||
|
this.maxStatusEntriesPerAction = maxStatusEntriesPerAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxAttributeEntriesPerTarget() {
|
||||||
|
return maxAttributeEntriesPerTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxAttributeEntriesPerTarget(final int maxAttributeEntriesPerTarget) {
|
||||||
|
this.maxAttributeEntriesPerTarget = maxAttributeEntriesPerTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Filter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* White list of peer IP addresses for DOS filter (regular
|
||||||
|
* expression).
|
||||||
|
*/
|
||||||
|
private String whitelist = "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|192\\.168\\.\\d{1,3}\\.\\d{1,3}|169\\.254\\.\\d{1,3}\\.\\d{1,3}|127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # Maximum number of allowed REST read/GET requests per second per
|
||||||
|
* client.
|
||||||
|
*/
|
||||||
|
int maxRead = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum number of allowed REST write/(PUT/POST/etc.) requests per
|
||||||
|
* second per client.
|
||||||
|
*/
|
||||||
|
int maxWrite = 50;
|
||||||
|
|
||||||
|
public String getWhitelist() {
|
||||||
|
return whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWhitelist(final String whitelist) {
|
||||||
|
this.whitelist = whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxRead() {
|
||||||
|
return maxRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxRead(final int maxRead) {
|
||||||
|
this.maxRead = maxRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxWrite() {
|
||||||
|
return maxWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxWrite(final int maxWrite) {
|
||||||
|
this.maxWrite = maxWrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The common properties for security.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@ConfigurationProperties
|
|
||||||
public class SecurityProperties {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inner class for reverse proxy configuration.
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@ConfigurationProperties("hawkbit.server.controller.security.rp")
|
|
||||||
public static class RpProperties {
|
|
||||||
private String cnHeader = "X-Ssl-Client-Cn";
|
|
||||||
private String sslIssuerHashHeader = "X-Ssl-Issuer-Hash-%d";
|
|
||||||
private List<String> trustedIPs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the cnHeader
|
|
||||||
*/
|
|
||||||
public String getCnHeader() {
|
|
||||||
return cnHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param cnHeader
|
|
||||||
* the cnHeader to set
|
|
||||||
*/
|
|
||||||
public void setCnHeader(final String cnHeader) {
|
|
||||||
this.cnHeader = cnHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the sslIssuerHashHeader
|
|
||||||
*/
|
|
||||||
public String getSslIssuerHashHeader() {
|
|
||||||
return sslIssuerHashHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param sslIssuerHashHeader
|
|
||||||
* the sslIssuerHashHeader to set
|
|
||||||
*/
|
|
||||||
public void setSslIssuerHashHeader(final String sslIssuerHashHeader) {
|
|
||||||
this.sslIssuerHashHeader = sslIssuerHashHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the trustedIPs
|
|
||||||
*/
|
|
||||||
public List<String> getTrustedIPs() {
|
|
||||||
return trustedIPs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param trustedIPs
|
|
||||||
* the trustedIPs to set
|
|
||||||
*/
|
|
||||||
public void setTrustedIPs(final List<String> trustedIPs) {
|
|
||||||
this.trustedIPs = trustedIPs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inner class for anonymous enable configuration.
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@ConfigurationProperties("hawkbit.server.controller.security.authentication.anonymous")
|
|
||||||
public static class AnoymousAuthenticationProperties {
|
|
||||||
private Boolean enabled = Boolean.FALSE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param enabled
|
|
||||||
* the enabled to set
|
|
||||||
*/
|
|
||||||
public void setEnabled(final Boolean enabled) {
|
|
||||||
this.enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the enabled
|
|
||||||
*/
|
|
||||||
public Boolean getEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RpProperties rppProperties;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AnoymousAuthenticationProperties authenticationsProperties;
|
|
||||||
|
|
||||||
public String getRpCnHeader() {
|
|
||||||
return rppProperties.getCnHeader();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRpSslIssuerHashHeader() {
|
|
||||||
return rppProperties.getSslIssuerHashHeader();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getRpTrustedIPs() {
|
|
||||||
return rppProperties.getTrustedIPs();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getAnonymousEnabled() {
|
|
||||||
return authenticationsProperties.getEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -11,90 +11,24 @@ package org.eclipse.hawkbit.util;
|
|||||||
import javax.servlet.MultipartConfigElement;
|
import javax.servlet.MultipartConfigElement;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bean which contains all informations about the SP software, e.g. like
|
* Bean which contains all informations about the SP software, e.g. like
|
||||||
* version, built time etc. from the environment.
|
* version, built time etc. from the environment.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class SPInfo implements EnvironmentAware {
|
public class SPInfo {
|
||||||
|
|
||||||
// package private for testing purposes
|
// package private for testing purposes
|
||||||
static final String UNKNOWN_VERSION = "unknown";
|
static final String UNKNOWN_VERSION = "unknown";
|
||||||
|
|
||||||
static final String UNKNOWN_CREDENTIAL = "unknown credential";
|
static final String UNKNOWN_CREDENTIAL = "unknown credential";
|
||||||
|
|
||||||
private Environment environmentData;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MultipartConfigElement configElement;
|
private MultipartConfigElement configElement;
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
*
|
|
||||||
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.
|
|
||||||
* springframework.core.env. Environment)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(final Environment environment) {
|
|
||||||
this.environmentData = environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the version in string format, e.g. 1.0.0 or {@code "UNKNOWN"} in
|
|
||||||
* case the SP version info cannot be determined.
|
|
||||||
*/
|
|
||||||
public String getVersion() {
|
|
||||||
if (environmentData != null) {
|
|
||||||
return environmentData.getProperty("info.build.version", UNKNOWN_VERSION);
|
|
||||||
}
|
|
||||||
return UNKNOWN_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSupportEmail() {
|
|
||||||
if (environmentData != null) {
|
|
||||||
return environmentData.getProperty("hawkbit.server.email.support");
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRequestAccountEmail() {
|
|
||||||
if (environmentData != null) {
|
|
||||||
return environmentData.getProperty("hawkbit.server.email.request.account");
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDemoTenant() {
|
|
||||||
if (environmentData != null) {
|
|
||||||
return environmentData.getProperty("hawkbit.server.demo.tenant");
|
|
||||||
}
|
|
||||||
return UNKNOWN_CREDENTIAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDemoUser() {
|
|
||||||
if (environmentData != null) {
|
|
||||||
return environmentData.getProperty("hawkbit.server.demo.user");
|
|
||||||
}
|
|
||||||
return UNKNOWN_CREDENTIAL;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDemoPassword() {
|
|
||||||
if (environmentData != null) {
|
|
||||||
return environmentData.getProperty("hawkbit.server.demo.password");
|
|
||||||
}
|
|
||||||
return UNKNOWN_CREDENTIAL;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the max file size to upload artifact files in bytes which has
|
* @return the max file size to upload artifact files in bytes which has
|
||||||
* been configured.
|
* been configured.
|
||||||
|
|||||||
@@ -213,7 +213,6 @@
|
|||||||
<groupId>org.vaadin.addons</groupId>
|
<groupId>org.vaadin.addons</groupId>
|
||||||
<artifactId>tokenfield</artifactId>
|
<artifactId>tokenfield</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- To be mentioned in release notes -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.vaadin.alump.distributionbar</groupId>
|
<groupId>org.vaadin.alump.distributionbar</groupId>
|
||||||
<artifactId>dbar-addon</artifactId>
|
<artifactId>dbar-addon</artifactId>
|
||||||
@@ -222,7 +221,11 @@
|
|||||||
<groupId>org.vaadin.addons</groupId>
|
<groupId>org.vaadin.addons</groupId>
|
||||||
<artifactId>contextmenu</artifactId>
|
<artifactId>contextmenu</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- To be mentioned in release notes -->
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Test -->
|
<!-- Test -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/**
|
||||||
|
* 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.ui;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties for Management UI customization.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties("hawkbit.server.ui")
|
||||||
|
public class UiProperties {
|
||||||
|
|
||||||
|
private final Links links = new Links();
|
||||||
|
private final Login login = new Login();
|
||||||
|
private final Demo demo = new Demo();
|
||||||
|
|
||||||
|
public Login getLogin() {
|
||||||
|
return login;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Links getLinks() {
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Demo getDemo() {
|
||||||
|
return demo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demo account login information.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Demo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demo tenant.
|
||||||
|
*/
|
||||||
|
private String tenant = "DEFAULT";
|
||||||
|
/**
|
||||||
|
* Demo user name.
|
||||||
|
*/
|
||||||
|
private String user = "admin";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demo user password.
|
||||||
|
*/
|
||||||
|
private String password = "admin";
|
||||||
|
|
||||||
|
public String getTenant() {
|
||||||
|
return tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTenant(final String tenant) {
|
||||||
|
this.tenant = tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(final String user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(final String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Links to potentially other systems (e.g. support, user management etc.).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Links {
|
||||||
|
/**
|
||||||
|
* Link to product support.
|
||||||
|
*/
|
||||||
|
private String support = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link to request a system account, access.
|
||||||
|
*/
|
||||||
|
private String requestAccount = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link to user management.
|
||||||
|
*/
|
||||||
|
private String userManagement = "";
|
||||||
|
|
||||||
|
public String getSupport() {
|
||||||
|
return support;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSupport(final String support) {
|
||||||
|
this.support = support;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRequestAccount() {
|
||||||
|
return requestAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestAccount(final String requestAccount) {
|
||||||
|
this.requestAccount = requestAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserManagement() {
|
||||||
|
return userManagement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserManagement(final String userManagement) {
|
||||||
|
this.userManagement = userManagement;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration of login view.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Login {
|
||||||
|
|
||||||
|
private final Cookie cookie = new Cookie();
|
||||||
|
|
||||||
|
public Cookie getCookie() {
|
||||||
|
return cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie configuration for login credential cookie.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Cookie {
|
||||||
|
/**
|
||||||
|
* Secure cookie enabled.
|
||||||
|
*/
|
||||||
|
private boolean secure = true;
|
||||||
|
|
||||||
|
public boolean isSecure() {
|
||||||
|
return secure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSecure(final boolean secure) {
|
||||||
|
this.secure = secure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,16 +15,14 @@ import javax.servlet.http.Cookie;
|
|||||||
|
|
||||||
import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator;
|
import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator;
|
||||||
import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationToken;
|
import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationToken;
|
||||||
|
import org.eclipse.hawkbit.ui.UiProperties;
|
||||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||||
import org.eclipse.hawkbit.ui.documentation.DocumentationPageLink;
|
import org.eclipse.hawkbit.ui.documentation.DocumentationPageLink;
|
||||||
import org.eclipse.hawkbit.ui.utils.I18N;
|
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||||
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
|
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
|
||||||
import org.eclipse.hawkbit.util.SPInfo;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.security.authentication.CredentialsExpiredException;
|
import org.springframework.security.authentication.CredentialsExpiredException;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
@@ -61,7 +59,7 @@ import com.vaadin.ui.themes.ValoTheme;
|
|||||||
*/
|
*/
|
||||||
@SpringView(name = "")
|
@SpringView(name = "")
|
||||||
@UIScope
|
@UIScope
|
||||||
public class LoginView extends VerticalLayout implements View, EnvironmentAware {
|
public class LoginView extends VerticalLayout implements View {
|
||||||
private static final String LOGIN_TEXTFIELD = "login-textfield";
|
private static final String LOGIN_TEXTFIELD = "login-textfield";
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(LoginView.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(LoginView.class);
|
||||||
@@ -76,7 +74,7 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware
|
|||||||
private I18N i18n;
|
private I18N i18n;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private transient SPInfo spInfo;
|
private transient UiProperties uiProperties;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private transient MultitenancyIndicator multiTenancyIndicator;
|
private transient MultitenancyIndicator multiTenancyIndicator;
|
||||||
@@ -86,9 +84,6 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware
|
|||||||
private PasswordField password;
|
private PasswordField password;
|
||||||
private Button signin;
|
private Button signin;
|
||||||
|
|
||||||
private Boolean secureCookie = Boolean.TRUE;
|
|
||||||
private String userManagementLoginUrl;
|
|
||||||
|
|
||||||
void loginAuthenticationFailedNotification() {
|
void loginAuthenticationFailedNotification() {
|
||||||
final Notification notification = new Notification(i18n.get("notification.login.failed.title"));
|
final Notification notification = new Notification(i18n.get("notification.login.failed.title"));
|
||||||
notification.setDescription(i18n.get("notification.login.failed.description"));
|
notification.setDescription(i18n.get("notification.login.failed.description"));
|
||||||
@@ -119,7 +114,8 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware
|
|||||||
final URI spURI = Page.getCurrent().getLocation();
|
final URI spURI = Page.getCurrent().getLocation();
|
||||||
final String lookForDemoFragment = spURI.toString();
|
final String lookForDemoFragment = spURI.toString();
|
||||||
if (lookForDemoFragment.contains("?demo")) {
|
if (lookForDemoFragment.contains("?demo")) {
|
||||||
login(spInfo.getDemoTenant(), spInfo.getDemoUser(), spInfo.getDemoPassword(), false);
|
login(uiProperties.getDemo().getTenant(), uiProperties.getDemo().getUser(),
|
||||||
|
uiProperties.getDemo().getPassword(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Component loginForm = buildLoginForm();
|
final Component loginForm = buildLoginForm();
|
||||||
@@ -243,18 +239,18 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware
|
|||||||
links.addComponent(demoLink);
|
links.addComponent(demoLink);
|
||||||
demoLink.addStyleName(ValoTheme.LINK_SMALL);
|
demoLink.addStyleName(ValoTheme.LINK_SMALL);
|
||||||
|
|
||||||
if (spInfo.getRequestAccountEmail() != null) {
|
if (!uiProperties.getLinks().getRequestAccount().isEmpty()) {
|
||||||
final Link requestAccountLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_REQUESTACCOUNT,
|
final Link requestAccountLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_REQUESTACCOUNT,
|
||||||
i18n.get("link.requestaccount.name"), spInfo.getRequestAccountEmail(), FontAwesome.SHOPPING_CART,
|
i18n.get("link.requestaccount.name"), uiProperties.getLinks().getRequestAccount(),
|
||||||
"", linkStyle, true);
|
FontAwesome.SHOPPING_CART, "", linkStyle, true);
|
||||||
links.addComponent(requestAccountLink);
|
links.addComponent(requestAccountLink);
|
||||||
requestAccountLink.addStyleName(ValoTheme.LINK_SMALL);
|
requestAccountLink.addStyleName(ValoTheme.LINK_SMALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userManagementLoginUrl != null) {
|
if (!uiProperties.getLinks().getUserManagement().isEmpty()) {
|
||||||
final Link userManagementLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_USERMANAGEMENT,
|
final Link userManagementLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_USERMANAGEMENT,
|
||||||
i18n.get("link.usermanagement.name"), userManagementLoginUrl, FontAwesome.USERS, "_blank",
|
i18n.get("link.usermanagement.name"), uiProperties.getLinks().getUserManagement(),
|
||||||
linkStyle, true);
|
FontAwesome.USERS, "_blank", linkStyle, true);
|
||||||
links.addComponent(userManagementLink);
|
links.addComponent(userManagementLink);
|
||||||
userManagementLink.addStyleName(ValoTheme.LINK_SMALL);
|
userManagementLink.addStyleName(ValoTheme.LINK_SMALL);
|
||||||
}
|
}
|
||||||
@@ -315,7 +311,7 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware
|
|||||||
// 100 days
|
// 100 days
|
||||||
tenantCookie.setMaxAge(3600 * 24 * 100);
|
tenantCookie.setMaxAge(3600 * 24 * 100);
|
||||||
tenantCookie.setHttpOnly(true);
|
tenantCookie.setHttpOnly(true);
|
||||||
tenantCookie.setSecure(secureCookie);
|
tenantCookie.setSecure(uiProperties.getLogin().getCookie().isSecure());
|
||||||
VaadinService.getCurrentResponse().addCookie(tenantCookie);
|
VaadinService.getCurrentResponse().addCookie(tenantCookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,7 +320,7 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware
|
|||||||
// 100 days
|
// 100 days
|
||||||
usernameCookie.setMaxAge(3600 * 24 * 100);
|
usernameCookie.setMaxAge(3600 * 24 * 100);
|
||||||
usernameCookie.setHttpOnly(true);
|
usernameCookie.setHttpOnly(true);
|
||||||
usernameCookie.setSecure(secureCookie);
|
usernameCookie.setSecure(uiProperties.getLogin().getCookie().isSecure());
|
||||||
VaadinService.getCurrentResponse().addCookie(usernameCookie);
|
VaadinService.getCurrentResponse().addCookie(usernameCookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,16 +364,4 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware
|
|||||||
loginAuthenticationFailedNotification();
|
loginAuthenticationFailedNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
*
|
|
||||||
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.
|
|
||||||
* springframework.core.env. Environment)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(final Environment environment) {
|
|
||||||
secureCookie = environment.getProperty("hawkbit.server.ui.login.cookie.secure", Boolean.class, Boolean.TRUE);
|
|
||||||
userManagementLoginUrl = environment.getProperty("hawkbit.server.im.login.url", String.class);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.util.StringJoiner;
|
|||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.annotation.PreDestroy;
|
import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
@@ -43,6 +44,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.domain.Sort.Direction;
|
||||||
import org.vaadin.spring.events.EventBus;
|
import org.vaadin.spring.events.EventBus;
|
||||||
import org.vaadin.spring.events.EventScope;
|
import org.vaadin.spring.events.EventScope;
|
||||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||||
@@ -417,10 +420,10 @@ public class ActionHistoryTable extends TreeTable implements Handler {
|
|||||||
|
|
||||||
final org.eclipse.hawkbit.repository.model.Action action = deploymentManagement
|
final org.eclipse.hawkbit.repository.model.Action action = deploymentManagement
|
||||||
.findActionWithDetails(actionId);
|
.findActionWithDetails(actionId);
|
||||||
final Pageable pageReq = new PageRequest(0, 1000);
|
final Pageable pageReq = new PageRequest(0, 1000,
|
||||||
final Page<ActionStatus> actionStatusList = deploymentManagement
|
new Sort(Direction.DESC, ActionStatusFields.ID.getFieldName()));
|
||||||
.findActionStatusMessagesByActionInDescOrder(pageReq, action,
|
final Page<ActionStatus> actionStatusList = deploymentManagement.findActionStatusByAction(pageReq, action,
|
||||||
managementUIState.isActionHistoryMaximized());
|
managementUIState.isActionHistoryMaximized());
|
||||||
final List<ActionStatus> content = actionStatusList.getContent();
|
final List<ActionStatus> content = actionStatusList.getContent();
|
||||||
/*
|
/*
|
||||||
* Since the recent action status and messages are already
|
* Since the recent action status and messages are already
|
||||||
|
|||||||
@@ -18,17 +18,16 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.HawkbitServerProperties;
|
||||||
import org.eclipse.hawkbit.im.authentication.PermissionService;
|
import org.eclipse.hawkbit.im.authentication.PermissionService;
|
||||||
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
|
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
|
||||||
|
import org.eclipse.hawkbit.ui.UiProperties;
|
||||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||||
import org.eclipse.hawkbit.ui.documentation.DocumentationPageLink;
|
import org.eclipse.hawkbit.ui.documentation.DocumentationPageLink;
|
||||||
import org.eclipse.hawkbit.ui.menu.DashboardEvent.PostViewChangeEvent;
|
import org.eclipse.hawkbit.ui.menu.DashboardEvent.PostViewChangeEvent;
|
||||||
import org.eclipse.hawkbit.ui.utils.I18N;
|
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||||
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
|
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
|
||||||
import org.eclipse.hawkbit.util.SPInfo;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.EnvironmentAware;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||||
@@ -42,7 +41,6 @@ import com.vaadin.spring.annotation.SpringComponent;
|
|||||||
import com.vaadin.spring.annotation.UIScope;
|
import com.vaadin.spring.annotation.UIScope;
|
||||||
import com.vaadin.ui.Alignment;
|
import com.vaadin.ui.Alignment;
|
||||||
import com.vaadin.ui.Button;
|
import com.vaadin.ui.Button;
|
||||||
import com.vaadin.ui.Button.ClickEvent;
|
|
||||||
import com.vaadin.ui.Button.ClickListener;
|
import com.vaadin.ui.Button.ClickListener;
|
||||||
import com.vaadin.ui.Component;
|
import com.vaadin.ui.Component;
|
||||||
import com.vaadin.ui.CustomComponent;
|
import com.vaadin.ui.CustomComponent;
|
||||||
@@ -50,7 +48,6 @@ import com.vaadin.ui.HorizontalLayout;
|
|||||||
import com.vaadin.ui.Label;
|
import com.vaadin.ui.Label;
|
||||||
import com.vaadin.ui.Link;
|
import com.vaadin.ui.Link;
|
||||||
import com.vaadin.ui.MenuBar;
|
import com.vaadin.ui.MenuBar;
|
||||||
import com.vaadin.ui.MenuBar.Command;
|
|
||||||
import com.vaadin.ui.MenuBar.MenuItem;
|
import com.vaadin.ui.MenuBar.MenuItem;
|
||||||
import com.vaadin.ui.VerticalLayout;
|
import com.vaadin.ui.VerticalLayout;
|
||||||
import com.vaadin.ui.themes.ValoTheme;
|
import com.vaadin.ui.themes.ValoTheme;
|
||||||
@@ -61,11 +58,17 @@ import com.vaadin.ui.themes.ValoTheme;
|
|||||||
*/
|
*/
|
||||||
@SpringComponent
|
@SpringComponent
|
||||||
@UIScope
|
@UIScope
|
||||||
public final class DashboardMenu extends CustomComponent implements EnvironmentAware {
|
public final class DashboardMenu extends CustomComponent {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private I18N i18n;
|
private I18N i18n;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private transient UiProperties uiProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private transient HawkbitServerProperties serverProperties;
|
||||||
|
|
||||||
private static final long serialVersionUID = 5394474618559481462L;
|
private static final long serialVersionUID = 5394474618559481462L;
|
||||||
|
|
||||||
public static final String ID = "dashboard-menu";
|
public static final String ID = "dashboard-menu";
|
||||||
@@ -74,16 +77,12 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA
|
|||||||
private static final String STYLE_VISIBLE = "valo-menu-visible";
|
private static final String STYLE_VISIBLE = "valo-menu-visible";
|
||||||
|
|
||||||
// this should be resolved when we introduce event bus on UI to just inform
|
// this should be resolved when we introduce event bus on UI to just inform
|
||||||
// the buttons directly
|
// the buttons directly via events
|
||||||
// via events
|
|
||||||
private final List<ValoMenuItemButton> menuButtons = new ArrayList<>();
|
private final List<ValoMenuItemButton> menuButtons = new ArrayList<>();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private transient PermissionService permissionService;
|
private transient PermissionService permissionService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private transient SPInfo spInfo;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private final List<DashboardMenuItem> dashboardVaadinViews = new ArrayList<>();
|
private final List<DashboardMenuItem> dashboardVaadinViews = new ArrayList<>();
|
||||||
|
|
||||||
@@ -91,12 +90,10 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA
|
|||||||
|
|
||||||
private boolean accessibleViewsEmpty;
|
private boolean accessibleViewsEmpty;
|
||||||
|
|
||||||
private String userManagementLoginUrl;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initializing the view and creating the layout, cannot be done in the
|
* initializing the view and creating the layout, cannot be done in the
|
||||||
* custructor because the constructor will be called by spring and the
|
* constructor because the constructor will be called by spring and the
|
||||||
* dashabord must be initialized when the dashboard UI is creating.
|
* dashboard must be initialized when the dashboard UI is creating.
|
||||||
*/
|
*/
|
||||||
public void init() {
|
public void init() {
|
||||||
initialViewName = "";
|
initialViewName = "";
|
||||||
@@ -162,20 +159,20 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA
|
|||||||
links.addComponent(docuLink);
|
links.addComponent(docuLink);
|
||||||
links.setComponentAlignment(docuLink, Alignment.BOTTOM_CENTER);
|
links.setComponentAlignment(docuLink, Alignment.BOTTOM_CENTER);
|
||||||
|
|
||||||
if (userManagementLoginUrl != null) {
|
if (!uiProperties.getLinks().getUserManagement().isEmpty()) {
|
||||||
final Link userManagementLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_USERMANAGEMENT,
|
final Link userManagementLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_USERMANAGEMENT,
|
||||||
i18n.get("link.usermanagement.name"), userManagementLoginUrl, FontAwesome.USERS, "_blank",
|
i18n.get("link.usermanagement.name"), uiProperties.getLinks().getUserManagement(),
|
||||||
linkStyle, true);
|
FontAwesome.USERS, "_blank", linkStyle, true);
|
||||||
userManagementLink.setDescription(i18n.get("link.usermanagement.name"));
|
userManagementLink.setDescription(i18n.get("link.usermanagement.name"));
|
||||||
links.addComponent(userManagementLink);
|
links.addComponent(userManagementLink);
|
||||||
userManagementLink.setSizeFull();
|
userManagementLink.setSizeFull();
|
||||||
links.setComponentAlignment(userManagementLink, Alignment.BOTTOM_CENTER);
|
links.setComponentAlignment(userManagementLink, Alignment.BOTTOM_CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spInfo.getSupportEmail() != null) {
|
if (!uiProperties.getLinks().getSupport().isEmpty()) {
|
||||||
final Link supportLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_SUPPORT,
|
final Link supportLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_SUPPORT,
|
||||||
i18n.get("link.support.name"), spInfo.getSupportEmail(), FontAwesome.ENVELOPE_O, "", linkStyle,
|
i18n.get("link.support.name"), uiProperties.getLinks().getSupport(), FontAwesome.ENVELOPE_O, "",
|
||||||
true);
|
linkStyle, true);
|
||||||
supportLink.setDescription(i18n.get("link.support.name"));
|
supportLink.setDescription(i18n.get("link.support.name"));
|
||||||
supportLink.setSizeFull();
|
supportLink.setSizeFull();
|
||||||
links.addComponent(supportLink);
|
links.addComponent(supportLink);
|
||||||
@@ -222,12 +219,7 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA
|
|||||||
settingsItem.setDescription(user.getUsername());
|
settingsItem.setDescription(user.getUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
settingsItem.addItem("Sign Out", new Command() {
|
settingsItem.addItem("Sign Out", selectedItem -> Page.getCurrent().setLocation("/UI/logout"));
|
||||||
@Override
|
|
||||||
public void menuSelected(final MenuItem selectedItem) {
|
|
||||||
Page.getCurrent().setLocation("/UI/logout");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,14 +246,11 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Component buildToggleButton() {
|
private Component buildToggleButton() {
|
||||||
final Button valoMenuToggleButton = new Button("Menu", new ClickListener() {
|
final Button valoMenuToggleButton = new Button("Menu", (ClickListener) event -> {
|
||||||
@Override
|
if (getCompositionRoot().getStyleName().contains(STYLE_VISIBLE)) {
|
||||||
public void buttonClick(final ClickEvent event) {
|
getCompositionRoot().removeStyleName(STYLE_VISIBLE);
|
||||||
if (getCompositionRoot().getStyleName().contains(STYLE_VISIBLE)) {
|
} else {
|
||||||
getCompositionRoot().removeStyleName(STYLE_VISIBLE);
|
getCompositionRoot().addStyleName(STYLE_VISIBLE);
|
||||||
} else {
|
|
||||||
getCompositionRoot().addStyleName(STYLE_VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
valoMenuToggleButton.setIcon(FontAwesome.LIST);
|
valoMenuToggleButton.setIcon(FontAwesome.LIST);
|
||||||
@@ -307,7 +296,7 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA
|
|||||||
final Label label = new Label();
|
final Label label = new Label();
|
||||||
label.setSizeFull();
|
label.setSizeFull();
|
||||||
label.setStyleName("version-layout");
|
label.setStyleName("version-layout");
|
||||||
label.setValue(spInfo.getVersion());
|
label.setValue(serverProperties.getBuild().getVersion());
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,11 +330,6 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA
|
|||||||
menuButtons.forEach(button -> button.postViewChange(event));
|
menuButtons.forEach(button -> button.postViewChange(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnvironment(final Environment environment) {
|
|
||||||
userManagementLoginUrl = environment.getProperty("hawkbit.server.im.login.url", String.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the dashboard view type by a given view name.
|
* Returns the dashboard view type by a given view name.
|
||||||
*
|
*
|
||||||
@@ -411,12 +395,7 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA
|
|||||||
setDescription(view.getDashboardCaptionLong());
|
setDescription(view.getDashboardCaptionLong());
|
||||||
/* Avoid double click */
|
/* Avoid double click */
|
||||||
setDisableOnClick(true);
|
setDisableOnClick(true);
|
||||||
addClickListener(new ClickListener() {
|
addClickListener(event -> event.getComponent().getUI().getNavigator().navigateTo(view.getViewName()));
|
||||||
@Override
|
|
||||||
public void buttonClick(final ClickEvent event) {
|
|
||||||
event.getComponent().getUI().getNavigator().navigateTo(view.getViewName());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
1
pom.xml
1
pom.xml
@@ -559,7 +559,6 @@
|
|||||||
<groupId>org.json</groupId>
|
<groupId>org.json</groupId>
|
||||||
<artifactId>json</artifactId>
|
<artifactId>json</artifactId>
|
||||||
<version>${json.version}</version>
|
<version>${json.version}</version>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>de.flapdoodle.embed</groupId>
|
<groupId>de.flapdoodle.embed</groupId>
|
||||||
|
|||||||
Reference in New Issue
Block a user