From 0b8e693cec47e8f1156509b5119b08224789ebf5 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Thu, 25 Feb 2016 11:36:21 +0100 Subject: [PATCH] Migrated environment aware to property annotation mechanism, documented properties. --- .../simulator/amqp/AmqpProperties.java | 16 +- .../client/ClientConfigurationProperties.java | 11 + .../AsyncConfigurerThreadpoolProperties.java | 14 +- .../scheduling/ExecutorAutoConfiguration.java | 5 +- .../security/SecurityAutoConfiguration.java | 4 +- .../SecurityManagedConfiguration.java | 50 ++-- ...ertyHostnameResolverAutoConfiguration.java | 1 + .../autoconfigure/url/ServerProperties.java | 30 --- .../hawkbit/cache/RedisConfiguration.java | 2 - .../hawkbit/cache/RedisProperties.java | 10 +- .../hawkbit/ControllerPollProperties.java | 9 + .../org/eclipse/hawkbit/ServerProperties.java | 97 ++++++++ .../amqp/AmqpControllerAuthentfication.java | 6 +- .../eclipse/hawkbit/amqp/AmqpProperties.java | 19 +- .../AmqpControllerAuthentficationTest.java | 4 +- .../RepositoryApplicationConfiguration.java | 4 - .../repository/ControllerManagement.java | 41 ++-- .../hawkbit/repository/ReportManagement.java | 5 - .../eclipse/hawkbit/TestConfiguration.java | 4 +- .../security/DdiSecurityProperties.java | 147 +++++++++++ .../hawkbit/security/SecurityProperties.java | 231 +++++++++++------- .../java/org/eclipse/hawkbit/util/SPInfo.java | 68 +----- .../org/eclipse/hawkbit/ui/UiProperties.java | 152 ++++++++++++ .../eclipse/hawkbit/ui/login/LoginView.java | 42 +--- .../hawkbit/ui/menu/DashboardMenu.java | 67 ++--- 25 files changed, 688 insertions(+), 351 deletions(-) delete mode 100644 hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/ServerProperties.java create mode 100644 hawkbit-core/src/main/java/org/eclipse/hawkbit/ServerProperties.java create mode 100644 hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java index ff9762c5d..9aa37e719 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpProperties.java @@ -14,16 +14,28 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * Bean which holds the necessary properties for configuring the AMQP * connection. * - * - * */ @ConfigurationProperties("hawkbit.device.simulator.amqp") public class AmqpProperties { + /** + * Queue for receiving DMF messages from update server. + */ private String receiverConnectorQueueFromSp; + + /** + * Exchange for sending DMF messages to update server. + */ private String senderForSpExchange; + /** + * Simulator dead letter queue. + */ private String deadLetterQueue; + + /** + * Simulator dead letter exchange. + */ private String deadLetterExchange; public String getReceiverConnectorQueueFromSp() { diff --git a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java index 6d15bcc04..68f35b550 100644 --- a/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java +++ b/examples/hawkbit-mgmt-api-client/src/main/java/org/eclipse/hawkbit/mgmt/client/ClientConfigurationProperties.java @@ -18,8 +18,19 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "hawkbit") public class ClientConfigurationProperties { + /** + * Update server URI. + */ private String url = "localhost:8080"; + + /** + * Update server user name. + */ private String username = "admin"; + + /** + * Update server password. + */ private String password = "admin"; // NOSONAR this password is only used for // examples diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java index f7f18f1b0..35996a114 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java @@ -13,17 +13,29 @@ import org.springframework.boot.context.properties.ConfigurationProperties; /** * Properties for the async configurer. * - * */ @ConfigurationProperties("hawkbit.threadpool") public class AsyncConfigurerThreadpoolProperties { + /** + * Max queue size for central event executor. + */ private Integer queuesize = 250; + /** + * Core processing threads for central event executor. + */ private Integer corethreads = 5; + /** + * Maximum thread pool size for central event executor. + */ 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; public Integer getQueuesize() { diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java index f8a86d1bc..43a096e7d 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java @@ -26,10 +26,9 @@ import org.springframework.security.concurrent.DelegatingSecurityContextExecutor import com.google.common.util.concurrent.ThreadFactoryBuilder; /** - * + * Central event processors inside update server. * */ - @Configuration @EnableConfigurationProperties(AsyncConfigurerThreadpoolProperties.class) public class ExecutorAutoConfiguration { @@ -40,7 +39,7 @@ public class ExecutorAutoConfiguration { private AsyncConfigurerThreadpoolProperties asyncConfigurerProperties; /** - * @return ExecutorService for general pupose multi threaded operations + * @return ExecutorService for general purpose multi threaded operations */ @Bean @ConditionalOnMissingBean diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java index 326ff4774..8a3a50ad2 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java @@ -20,7 +20,7 @@ import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter; import org.eclipse.hawkbit.security.SecurityContextTenantAware; -import org.eclipse.hawkbit.security.SecurityProperties; +import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.SpringSecurityAuditorAware; import org.eclipse.hawkbit.tenancy.TenantAware; import org.slf4j.Logger; @@ -53,7 +53,7 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationFi * */ @Configuration -@EnableConfigurationProperties(SecurityProperties.class) +@EnableConfigurationProperties(DdiSecurityProperties.class) public class SecurityAutoConfiguration { /** diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java index ca55f1711..b6a46737e 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java @@ -31,6 +31,7 @@ import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.rest.resource.RestConstants; import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource; +import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.DosFilter; import org.eclipse.hawkbit.security.HttpControllerPreAuthenticateSecurityTokenFilter; import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedGatewaySecurityTokenFilter; @@ -43,17 +44,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.boot.context.embedded.ServletListenerRegistrationBean; import org.springframework.cache.Cache; -import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; -import org.springframework.core.env.Environment; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; 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) @EnableWebMvcSecurity @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 String SP_SERVER_CONFIG_PREFIX = "hawkbit.server."; - private RelaxedPropertyResolver environment; - - @Override - public void setEnvironment(final Environment environment) { - this.environment = new RelaxedPropertyResolver(environment, SP_SERVER_CONFIG_PREFIX); - - } + @Autowired + private SecurityProperties securityProperties; /** * {@link WebSecurityConfigurer} for the internal SP controller API. @@ -123,7 +115,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware { @Autowired private TenantAware tenantAware; @Autowired - private SecurityProperties securityConfiguration; + private DdiSecurityProperties securityConfiguration; @Autowired private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties; @@ -204,13 +196,9 @@ public class SecurityManagedConfiguration implements EnvironmentAware { public FilterRegistrationBean dosFilter() { final FilterRegistrationBean filterRegBean = new FilterRegistrationBean(); - filterRegBean - .setFilter( - new DosFilter(environment.getProperty("security.dos.filter.maxRead", Integer.class, 200), - environment.getProperty("security.dos.filter.maxWrite", Integer.class, 50), - environment.getProperty("security.dos.filter.whitelist"), environment - .getProperty("security.clients.blacklist"), - environment.getProperty("security.rp.remote_ip_header", String.class, "X-Forwarded-For"))); + filterRegBean.setFilter(new DosFilter(securityProperties.getDos().getFilter().getMaxRead(), + securityProperties.getDos().getFilter().getMaxWrite(), securityProperties.getDos().getWhitelist(), + securityProperties.getClients().getBlacklist(), securityProperties.getClients().getRemoteIpHeader())); filterRegBean.addUrlPatterns("/{tenant}/controller/v1/*", "/rest/*"); return filterRegBean; } @@ -310,8 +298,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware { @Configuration @Order(400) @EnableVaadinSecurity - public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter - implements EnvironmentAware { + public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { private static final String XFRAME_OPTION_DENY = "DENY"; private static final String XFRAME_OPTION_SAMEORIGIN = "SAMEORIGIN"; @@ -320,13 +307,8 @@ public class SecurityManagedConfiguration implements EnvironmentAware { private VaadinSecurityContext vaadinSecurityContext; @Autowired private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties; - - private RelaxedPropertyResolver environment; - - @Override - public void setEnvironment(final Environment environment) { - this.environment = new RelaxedPropertyResolver(environment, SP_SERVER_CONFIG_PREFIX); - } + @Autowired + private SecurityProperties securityProperties; /** * post construct for setting the authentication success handler for the @@ -379,13 +361,13 @@ public class SecurityManagedConfiguration implements EnvironmentAware { protected void configure(final HttpSecurity http) throws Exception { // configuration xframe-option - final String confXframeOption = environment.getProperty("security.xframe.option", XFRAME_OPTION_DENY); - final String confAllowFromUri = environment.getProperty("security.xframe.option.allowfrom"); - if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri == null) { + final String confXframeOption = securityProperties.getXframe().getOption(); + final String confAllowFromUri = securityProperties.getXframe().getAllowfrom(); + if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri.isEmpty()) { // if allow-from option is specified but no allowFromUri throw // exception throw new IllegalStateException("hawkbit.server.security.xframe.option has been specified as ALLOW-FROM" - + " 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"); } @@ -461,7 +443,7 @@ public class SecurityManagedConfiguration implements EnvironmentAware { public static class IdRestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { @Autowired - private SecurityProperties securityConfiguration; + private DdiSecurityProperties securityConfiguration; @Autowired @Qualifier(CacheConstants.DOWNLOAD_ID_CACHE) diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/PropertyHostnameResolverAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/PropertyHostnameResolverAutoConfiguration.java index eb925e281..a8fc609ef 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/PropertyHostnameResolverAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/PropertyHostnameResolverAutoConfiguration.java @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.autoconfigure.url; import java.net.MalformedURLException; import java.net.URL; +import org.eclipse.hawkbit.ServerProperties; import org.eclipse.hawkbit.api.HostnameResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/ServerProperties.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/ServerProperties.java deleted file mode 100644 index 24c9dfb0e..000000000 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/url/ServerProperties.java +++ /dev/null @@ -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; - } -} diff --git a/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java b/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java index 2d1b99c98..5dc069f8a 100644 --- a/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java +++ b/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisConfiguration.java @@ -26,8 +26,6 @@ import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer * The spring Redis configuration which is enabled by using the profile * {@code redis} to use a Redis server as cache. * - * - * */ @Configuration @EnableConfigurationProperties(RedisProperties.class) diff --git a/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisProperties.java b/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisProperties.java index c228cde4c..ab409bbf5 100644 --- a/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisProperties.java +++ b/hawkbit-cache-redis/src/main/java/org/eclipse/hawkbit/cache/RedisProperties.java @@ -14,14 +14,18 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * Bean which holds the necessary properties for configuring the Redis * connection. * - * - * - * */ @ConfigurationProperties("hawkbit.server.redis") public class RedisProperties { + /** + * Redis server hostname. + */ private String host; + + /** + * Redis server port. + */ private int port; /** diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java index 694d5c016..fad0f78ec 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java @@ -20,7 +20,16 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "hawkbit.controller") public class ControllerPollProperties { + /** + * Recommended target polling time for DDI API. Final choice is up to the + * target. + */ 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"; public String getPollingTime() { diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/ServerProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/ServerProperties.java new file mode 100644 index 000000000..b48949a31 --- /dev/null +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/ServerProperties.java @@ -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 ServerProperties { + /** + * 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. Influeneced 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; + } +} diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java index dd36ef1fd..67ae1c8fb 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentfication.java @@ -23,7 +23,7 @@ import org.eclipse.hawkbit.security.ControllerPreAuthenticatedGatewaySecurityTok import org.eclipse.hawkbit.security.ControllerPreAuthenticatedSecurityHeaderFilter; import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider; import org.eclipse.hawkbit.security.PreAuthenficationFilter; -import org.eclipse.hawkbit.security.SecurityProperties; +import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.tenancy.TenantAware; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,7 +55,7 @@ public class AmqpControllerAuthentfication { private TenantAware tenantAware; @Autowired - private SecurityProperties secruityProperties; + private DdiSecurityProperties secruityProperties; /** * Constructor. @@ -137,7 +137,7 @@ public class AmqpControllerAuthentfication { this.controllerManagement = controllerManagement; } - public void setSecruityProperties(final SecurityProperties secruityProperties) { + public void setSecruityProperties(final DdiSecurityProperties secruityProperties) { this.secruityProperties = secruityProperties; } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java index ecd2dc3d7..5bb3dbd5d 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java @@ -15,16 +15,29 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * Bean which holds the necessary properties for configuring the AMQP * connection. * - * - * - * */ @ConfigurationProperties("hawkbit.dmf.rabbitmq") public class AmqpProperties { + /** + * DMF API dead letter queue. + */ private String deadLetterQueue = "dmf_connector_deadletter"; + + /** + * DMF API dead letter exchange. + */ private String deadLetterExchange = "dmf.connector.deadletter"; + + /** + * DMF API receiving queue. + */ private String receiverQueue = "dmf_receiver"; + + /** + * Missing queue fatal, see + * {@link SimpleMessageListenerContainer#setMissingQueuesFatal(boolean)}. + */ private boolean missingQueuesFatal = false; /** diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentficationTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentficationTest.java index 1d962907b..68b7b59ff 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentficationTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthentficationTest.java @@ -24,7 +24,7 @@ import org.eclipse.hawkbit.repository.ArtifactManagement; import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.SystemManagement; import org.eclipse.hawkbit.security.SecurityContextTenantAware; -import org.eclipse.hawkbit.security.SecurityProperties; +import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.junit.Before; import org.junit.Test; @@ -68,7 +68,7 @@ public class AmqpControllerAuthentficationTest { authenticationManager = new AmqpControllerAuthentfication(); authenticationManager.setControllerManagement(mock(ControllerManagement.class)); - final SecurityProperties secruityProperties = mock(SecurityProperties.class); + final DdiSecurityProperties secruityProperties = mock(DdiSecurityProperties.class); when(secruityProperties.getRpSslIssuerHashHeader()).thenReturn("X-Ssl-Issuer-Hash-%d"); authenticationManager.setSecruityProperties(secruityProperties); systemManagement = mock(SystemManagement.class); diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java index e2d31a04c..84d1d9b60 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java @@ -40,10 +40,6 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess /** * General configuration for the SP Repository. * - * - * - * - * */ @EnableJpaRepositories(basePackages = { "org.eclipse.hawkbit.repository" }) @EnableTransactionManagement diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java index e4a1e5e6b..5b31f4934 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java @@ -33,13 +33,11 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.Target_; +import org.eclipse.hawkbit.security.SecurityProperties; import org.hibernate.validator.constraints.NotEmpty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; @@ -57,7 +55,7 @@ import org.springframework.validation.annotation.Validated; @Transactional(readOnly = true) @Validated @Service -public class ControllerManagement implements EnvironmentAware { +public class ControllerManagement { private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class); private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos"); @@ -85,9 +83,8 @@ public class ControllerManagement implements EnvironmentAware { @Autowired private ActionStatusRepository actionStatusRepository; - private Integer maxCount = 1000; - - private Integer maxAttributes = 100; + @Autowired + private SecurityProperties securityProperties; /** * 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) { - if (maxCount > 0) { + if (securityProperties.getDos().getMaxStatusEntriesPerAction() > 0) { final Long statusCount = actionStatusRepository.countByAction(action); - if (statusCount >= maxCount) { + if (statusCount >= securityProperties.getDos().getMaxStatusEntriesPerAction()) { LOG_DOS.error( "Potential denial of service (DOS) attack identfied. More status entries in the system than permitted ({})!", - maxCount); - throw new ToManyStatusEntriesException(String.valueOf(maxCount)); + securityProperties.getDos().getMaxStatusEntriesPerAction()); + throw new ToManyStatusEntriesException( + String.valueOf(securityProperties.getDos().getMaxStatusEntriesPerAction())); } } } @@ -436,10 +434,12 @@ public class ControllerManagement implements EnvironmentAware { 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!", - maxAttributes); - throw new ToManyAttributeEntriesException(String.valueOf(maxAttributes)); + securityProperties.getDos().getMaxAttributeEntriesPerTarget()); + throw new ToManyAttributeEntriesException( + String.valueOf(securityProperties.getDos().getMaxAttributeEntriesPerTarget())); } target.getTargetInfo().setLastTargetQuery(System.currentTimeMillis()); @@ -447,19 +447,6 @@ public class ControllerManagement implements EnvironmentAware { 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 * it does not exist yet. diff --git a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java index 8f87f9209..eab926b4b 100644 --- a/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java +++ b/hawkbit-repository/src/main/java/org/eclipse/hawkbit/repository/ReportManagement.java @@ -46,7 +46,6 @@ import org.eclipse.hawkbit.repository.model.Target_; import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -55,14 +54,10 @@ import org.springframework.validation.annotation.Validated; /** * Service layer for generating SP reportings. * - * - * - * */ @Transactional(readOnly = true) @Validated @Service -@ConfigurationProperties public class ReportManagement { @Value("${spring.jpa.database}") diff --git a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java index 945e71c75..0667c6e08 100644 --- a/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java +++ b/hawkbit-repository/src/test/java/org/eclipse/hawkbit/TestConfiguration.java @@ -18,7 +18,7 @@ import org.eclipse.hawkbit.repository.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.utils.RepositoryDataGenerator; import org.eclipse.hawkbit.repository.utils.RepositoryDataGenerator.DatabaseCleanupUtil; 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.tenancy.TenantAware; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; @@ -47,7 +47,7 @@ import com.mongodb.MongoClientOptions; */ @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true) -@EnableConfigurationProperties({ SecurityProperties.class, ControllerPollProperties.class }) +@EnableConfigurationProperties({ DdiSecurityProperties.class, ControllerPollProperties.class }) @Profile("test") public class TestConfiguration implements AsyncConfigurer { diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java new file mode 100644 index 000000000..8a8e38fdc --- /dev/null +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DdiSecurityProperties.java @@ -0,0 +1,147 @@ +/** + * 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 DDI security. + */ +@ConfigurationProperties("hawkbit.server.ddi.security") +public class DdiSecurityProperties { + + /** + * Inner class for 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. + */ + @Component + @ConfigurationProperties("hawkbit.server.ddi.security.rp") + public static class RpProperties { + + /** + * 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 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 getTrustedIPs() { + return trustedIPs; + } + + /** + * @param trustedIPs + * the trustedIPs to set + */ + public void setTrustedIPs(final List trustedIPs) { + this.trustedIPs = trustedIPs; + } + + } + + /** + * Inner class for anonymous enable configuration. + */ + @Component + @ConfigurationProperties("hawkbit.server.ddi.security.authentication.anonymous") + public static class AnoymousAuthenticationProperties { + + /** + * Set to true to enable anonymous DDI client authentication. + */ + 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 getRpTrustedIPs() { + return rppProperties.getTrustedIPs(); + } + + public Boolean getAnonymousEnabled() { + return authenticationsProperties.getEnabled(); + } + +} diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityProperties.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityProperties.java index 8cc056f15..08c7f2132 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityProperties.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityProperties.java @@ -1,130 +1,181 @@ -/** - * 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. - * - * + * Security related hawkbit configuration. * */ -@ConfigurationProperties +@ConfigurationProperties("hawkbit.server.security") public class SecurityProperties { + 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; + } + /** - * Inner class for reverse proxy configuration. + * Defines the XFrameOption policy. + * */ - @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 trustedIPs; + public static class Xframe { /** - * @return the cnHeader + * XFrame option. Allowed values: SAMEORIGIN, DENY, ALLOW-FROM */ - public String getCnHeader() { - return cnHeader; + 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; } - /** - * @param cnHeader - * the cnHeader to set - */ - public void setCnHeader(final String cnHeader) { - this.cnHeader = cnHeader; + public void setOption(final String option) { + this.option = option; } - /** - * @return the sslIssuerHashHeader - */ - public String getSslIssuerHashHeader() { - return sslIssuerHashHeader; + public String getAllowfrom() { + return allowfrom; } - /** - * @param sslIssuerHashHeader - * the sslIssuerHashHeader to set - */ - public void setSslIssuerHashHeader(final String sslIssuerHashHeader) { - this.sslIssuerHashHeader = sslIssuerHashHeader; - } - - /** - * @return the trustedIPs - */ - public List getTrustedIPs() { - return trustedIPs; - } - - /** - * @param trustedIPs - * the trustedIPs to set - */ - public void setTrustedIPs(final List trustedIPs) { - this.trustedIPs = trustedIPs; + public void setAllowfrom(final String allowfrom) { + this.allowfrom = allowfrom; } } /** - * Inner class for anonymous enable configuration. + * Security configuration related to clients. + * */ - @Component - @ConfigurationProperties("hawkbit.server.controller.security.authentication.anonymous") - public static class AnoymousAuthenticationProperties { - private Boolean enabled = Boolean.FALSE; + public static class Clients { /** - * @param enabled - * the enabled to set + * Blacklisted client (IP addresses) for for DDI and Management API. */ - public void setEnabled(final Boolean enabled) { - this.enabled = enabled; - } + private String blacklist = ""; /** - * @return the enabled + * Name of the http header from which the remote ip is extracted. */ - public Boolean getEnabled() { - return enabled; + 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; + } } - @Autowired - private RpProperties rppProperties; + /** + * Denial of service protection related properties. + * + */ + public static class Dos { - @Autowired - private AnoymousAuthenticationProperties authenticationsProperties; + /** + * 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}"; - public String getRpCnHeader() { - return rppProperties.getCnHeader(); + /** + * 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 String getWhitelist() { + return whitelist; + } + + public void setWhitelist(final String whitelist) { + this.whitelist = whitelist; + } + + 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 { + + /** + * # 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 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; + } + + } } - - public String getRpSslIssuerHashHeader() { - return rppProperties.getSslIssuerHashHeader(); - } - - public List getRpTrustedIPs() { - return rppProperties.getTrustedIPs(); - } - - public Boolean getAnonymousEnabled() { - return authenticationsProperties.getEnabled(); - } - } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/SPInfo.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/SPInfo.java index 3a2a696df..feb94c0d7 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/SPInfo.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/SPInfo.java @@ -11,90 +11,24 @@ package org.eclipse.hawkbit.util; import javax.servlet.MultipartConfigElement; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.EnvironmentAware; -import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; /** * Bean which contains all informations about the SP software, e.g. like * version, built time etc. from the environment. * - * - * - * */ @Component -public class SPInfo implements EnvironmentAware { +public class SPInfo { // package private for testing purposes static final String UNKNOWN_VERSION = "unknown"; static final String UNKNOWN_CREDENTIAL = "unknown credential"; - private Environment environmentData; - @Autowired 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 * been configured. diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java new file mode 100644 index 000000000..22a8d8d23 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java @@ -0,0 +1,152 @@ +package org.eclipse.hawkbit.ui; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Properties for Management UI customization. + * + */ +@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; + } + } + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/login/LoginView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/login/LoginView.java index 9beeff56a..484333219 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/login/LoginView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/login/LoginView.java @@ -15,16 +15,14 @@ import javax.servlet.http.Cookie; import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator; 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.documentation.DocumentationPageLink; import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; -import org.eclipse.hawkbit.util.SPInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.UsernamePasswordAuthenticationToken; import org.springframework.security.core.AuthenticationException; @@ -61,7 +59,7 @@ import com.vaadin.ui.themes.ValoTheme; */ @SpringView(name = "") @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 long serialVersionUID = 1L; private static final Logger LOGGER = LoggerFactory.getLogger(LoginView.class); @@ -76,7 +74,7 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware private I18N i18n; @Autowired - private transient SPInfo spInfo; + private transient UiProperties uiProperties; @Autowired private transient MultitenancyIndicator multiTenancyIndicator; @@ -86,9 +84,6 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware private PasswordField password; private Button signin; - private Boolean secureCookie = Boolean.TRUE; - private String userManagementLoginUrl; - void loginAuthenticationFailedNotification() { final Notification notification = new Notification(i18n.get("notification.login.failed.title")); 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 String lookForDemoFragment = spURI.toString(); 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(); @@ -243,18 +239,18 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware links.addComponent(demoLink); demoLink.addStyleName(ValoTheme.LINK_SMALL); - if (spInfo.getRequestAccountEmail() != null) { + if (!uiProperties.getLinks().getRequestAccount().isEmpty()) { final Link requestAccountLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_REQUESTACCOUNT, - i18n.get("link.requestaccount.name"), spInfo.getRequestAccountEmail(), FontAwesome.SHOPPING_CART, - "", linkStyle, true); + i18n.get("link.requestaccount.name"), uiProperties.getLinks().getRequestAccount(), + FontAwesome.SHOPPING_CART, "", linkStyle, true); links.addComponent(requestAccountLink); requestAccountLink.addStyleName(ValoTheme.LINK_SMALL); } - if (userManagementLoginUrl != null) { + if (!uiProperties.getLinks().getUserManagement().isEmpty()) { final Link userManagementLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_USERMANAGEMENT, - i18n.get("link.usermanagement.name"), userManagementLoginUrl, FontAwesome.USERS, "_blank", - linkStyle, true); + i18n.get("link.usermanagement.name"), uiProperties.getLinks().getUserManagement(), + FontAwesome.USERS, "_blank", linkStyle, true); links.addComponent(userManagementLink); userManagementLink.addStyleName(ValoTheme.LINK_SMALL); } @@ -315,7 +311,7 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware // 100 days tenantCookie.setMaxAge(3600 * 24 * 100); tenantCookie.setHttpOnly(true); - tenantCookie.setSecure(secureCookie); + tenantCookie.setSecure(uiProperties.getLogin().getCookie().isSecure()); VaadinService.getCurrentResponse().addCookie(tenantCookie); } @@ -324,7 +320,7 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware // 100 days usernameCookie.setMaxAge(3600 * 24 * 100); usernameCookie.setHttpOnly(true); - usernameCookie.setSecure(secureCookie); + usernameCookie.setSecure(uiProperties.getLogin().getCookie().isSecure()); VaadinService.getCurrentResponse().addCookie(usernameCookie); } @@ -368,16 +364,4 @@ public class LoginView extends VerticalLayout implements View, EnvironmentAware 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); - } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java index 44ec9ea40..9dd207565 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java @@ -18,17 +18,16 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import org.eclipse.hawkbit.ServerProperties; import org.eclipse.hawkbit.im.authentication.PermissionService; 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.documentation.DocumentationPageLink; import org.eclipse.hawkbit.ui.menu.DashboardEvent.PostViewChangeEvent; import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; -import org.eclipse.hawkbit.util.SPInfo; 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.userdetails.UserDetails; 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.ui.Alignment; import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Component; import com.vaadin.ui.CustomComponent; @@ -50,7 +48,6 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Link; import com.vaadin.ui.MenuBar; -import com.vaadin.ui.MenuBar.Command; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.ValoTheme; @@ -61,11 +58,17 @@ import com.vaadin.ui.themes.ValoTheme; */ @SpringComponent @UIScope -public final class DashboardMenu extends CustomComponent implements EnvironmentAware { +public final class DashboardMenu extends CustomComponent { @Autowired private I18N i18n; + @Autowired + private transient UiProperties uiProperties; + + @Autowired + private transient ServerProperties serverProperties; + private static final long serialVersionUID = 5394474618559481462L; public static final String ID = "dashboard-menu"; @@ -81,8 +84,8 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA @Autowired private transient PermissionService permissionService; - @Autowired - private transient SPInfo spInfo; + // @Autowired + // private transient SPInfo spInfo; @Autowired private final List dashboardVaadinViews = new ArrayList<>(); @@ -91,8 +94,6 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA private boolean accessibleViewsEmpty; - private String userManagementLoginUrl; - /** * initializing the view and creating the layout, cannot be done in the * custructor because the constructor will be called by spring and the @@ -162,20 +163,20 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA links.addComponent(docuLink); links.setComponentAlignment(docuLink, Alignment.BOTTOM_CENTER); - if (userManagementLoginUrl != null) { + if (!uiProperties.getLinks().getUserManagement().isEmpty()) { final Link userManagementLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_USERMANAGEMENT, - i18n.get("link.usermanagement.name"), userManagementLoginUrl, FontAwesome.USERS, "_blank", - linkStyle, true); + i18n.get("link.usermanagement.name"), uiProperties.getLinks().getUserManagement(), + FontAwesome.USERS, "_blank", linkStyle, true); userManagementLink.setDescription(i18n.get("link.usermanagement.name")); links.addComponent(userManagementLink); userManagementLink.setSizeFull(); links.setComponentAlignment(userManagementLink, Alignment.BOTTOM_CENTER); } - if (spInfo.getSupportEmail() != null) { + if (!uiProperties.getLinks().getSupport().isEmpty()) { final Link supportLink = SPUIComponentProvider.getLink(SPUIComponetIdProvider.LINK_SUPPORT, - i18n.get("link.support.name"), spInfo.getSupportEmail(), FontAwesome.ENVELOPE_O, "", linkStyle, - true); + i18n.get("link.support.name"), uiProperties.getLinks().getSupport(), FontAwesome.ENVELOPE_O, "", + linkStyle, true); supportLink.setDescription(i18n.get("link.support.name")); supportLink.setSizeFull(); links.addComponent(supportLink); @@ -222,12 +223,7 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA settingsItem.setDescription(user.getUsername()); } - settingsItem.addItem("Sign Out", new Command() { - @Override - public void menuSelected(final MenuItem selectedItem) { - Page.getCurrent().setLocation("/UI/logout"); - } - }); + settingsItem.addItem("Sign Out", selectedItem -> Page.getCurrent().setLocation("/UI/logout")); return settings; } @@ -254,14 +250,11 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA } private Component buildToggleButton() { - final Button valoMenuToggleButton = new Button("Menu", new ClickListener() { - @Override - public void buttonClick(final ClickEvent event) { - if (getCompositionRoot().getStyleName().contains(STYLE_VISIBLE)) { - getCompositionRoot().removeStyleName(STYLE_VISIBLE); - } else { - getCompositionRoot().addStyleName(STYLE_VISIBLE); - } + final Button valoMenuToggleButton = new Button("Menu", (ClickListener) event -> { + if (getCompositionRoot().getStyleName().contains(STYLE_VISIBLE)) { + getCompositionRoot().removeStyleName(STYLE_VISIBLE); + } else { + getCompositionRoot().addStyleName(STYLE_VISIBLE); } }); valoMenuToggleButton.setIcon(FontAwesome.LIST); @@ -307,7 +300,7 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA final Label label = new Label(); label.setSizeFull(); label.setStyleName("version-layout"); - label.setValue(spInfo.getVersion()); + label.setValue(serverProperties.getBuild().getVersion()); return label; } @@ -341,11 +334,6 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA 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. * @@ -411,12 +399,7 @@ public final class DashboardMenu extends CustomComponent implements EnvironmentA setDescription(view.getDashboardCaptionLong()); /* Avoid double click */ setDisableOnClick(true); - addClickListener(new ClickListener() { - @Override - public void buttonClick(final ClickEvent event) { - event.getComponent().getUI().getNavigator().navigateTo(view.getViewName()); - } - }); + addClickListener(event -> event.getComponent().getUI().getNavigator().navigateTo(view.getViewName())); }