diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 32be36d87..e69fd0d40 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -35,8 +35,6 @@ So we kindly ask contributors:
* use [Guava](https://github.com/google/guava) if feasible
* use [Apache commons lang](https://commons.apache.org/proper/commons-lang/) if feasible
-Note that the guava project for instance often documents where they think that JDK is having a similar functionality (e.g. their thoughts on [Throwables.propagate](https://github.com/google/guava/wiki/Why-we-deprecated-Throwables.propagate)).
-
Examples:
* Prefer `Arrays.asList(...)` from JDK over Guava's `Lists.newArrayList(...)`
diff --git a/hawkbit-autoconfigure/pom.xml b/hawkbit-autoconfigure/pom.xml
index a2c0ede90..3fc08c107 100644
--- a/hawkbit-autoconfigure/pom.xml
+++ b/hawkbit-autoconfigure/pom.xml
@@ -31,12 +31,6 @@
${project.version}
true
-
- org.eclipse.hawkbit
- hawkbit-ui
- ${project.version}
- true
-
org.eclipse.hawkbit
hawkbit-repository-jpa
diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/OidcUserManagementAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/OidcUserManagementAutoConfiguration.java
index bf3c64322..463ba48fe 100644
--- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/OidcUserManagementAutoConfiguration.java
+++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/OidcUserManagementAutoConfiguration.java
@@ -53,10 +53,11 @@ import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
+import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtException;
-import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
+import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
@@ -261,8 +262,11 @@ class JwtAuthoritiesExtractor {
Set extract(final ClientRegistration clientRegistration, final String tokenValue) {
try {
// Token is already verified by spring security
- final JwtDecoder jwtDecoder = new NimbusJwtDecoderJwkSupport(
- clientRegistration.getProviderDetails().getJwkSetUri());
+ final NimbusJwtDecoder jwtDecoder =
+ NimbusJwtDecoder
+ .withJwkSetUri(clientRegistration.getProviderDetails().getJwkSetUri())
+ .jwsAlgorithm(SignatureAlgorithm.from(JwsAlgorithms.RS256))
+ .build();
final Jwt token = jwtDecoder.decode(tokenValue);
return extract(clientRegistration.getClientId(), token.getClaims());
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 702289d2f..5706d4549 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
@@ -9,7 +9,6 @@
package org.eclipse.hawkbit.autoconfigure.security;
import java.io.IOException;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -20,14 +19,12 @@ import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
import org.eclipse.hawkbit.ddi.rest.resource.DdiApiConfiguration;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
-import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.resource.MgmtApiConfiguration;
@@ -46,7 +43,6 @@ import org.eclipse.hawkbit.security.HttpDownloadAuthenticationFilter;
import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
-import org.eclipse.hawkbit.ui.MgmtUiConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -54,62 +50,41 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
-import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
-import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.InsufficientAuthenticationException;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
-import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
-import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
-import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
+import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
-import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
-import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
-import org.springframework.security.web.authentication.logout.LogoutHandler;
-import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
-import org.springframework.security.web.firewall.FirewalledRequest;
-import org.springframework.security.web.firewall.HttpFirewall;
-import org.springframework.security.web.firewall.StrictHttpFirewall;
-import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.security.web.session.SessionManagementFilter;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
import org.springframework.web.cors.CorsConfiguration;
-import org.vaadin.spring.http.HttpService;
-import org.vaadin.spring.security.annotation.EnableVaadinSharedSecurity;
-import org.vaadin.spring.security.config.VaadinSharedSecurityConfiguration;
-import org.vaadin.spring.security.shared.VaadinAuthenticationSuccessHandler;
-import org.vaadin.spring.security.shared.VaadinUrlAuthenticationSuccessHandler;
-import org.vaadin.spring.security.web.VaadinRedirectStrategy;
+import org.springframework.web.cors.CorsConfigurationSource;
/**
* All configurations related to HawkBit's authentication and authorization
@@ -155,18 +130,18 @@ public class SecurityManagedConfiguration {
* {@link WebSecurityConfigurer} for the hawkBit server DDI interface.
*/
@Configuration
- @Order(300)
+ @EnableWebSecurity
@ConditionalOnClass(DdiApiConfiguration.class)
- static class ControllerSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
+ static class ControllerSecurityConfigurationAdapter {
- private static final String[] DDI_ANT_MATCHERS = { DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}",
+ private static final String[] DDI_ANT_MATCHERS = {
+ DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}",
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/confirmationBase/**",
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/deploymentBase/**",
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/installedBase/**",
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/cancelAction/**",
DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/configData",
- DdiRestConstants.BASE_V1_REQUEST_MAPPING
- + "/{controllerId}/softwaremodules/{softwareModuleId}/artifacts" };
+ DdiRestConstants.BASE_V1_REQUEST_MAPPING + "/{controllerId}/softwaremodules/{softwareModuleId}/artifacts" };
private final ControllerManagement controllerManagement;
private final TenantConfigurationManagement tenantConfigurationManagement;
@@ -200,75 +175,79 @@ public class SecurityManagedConfiguration {
*/
@Bean
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true)
- public FilterRegistrationBean dosDDiFilter(final HawkbitSecurityProperties securityProperties) {
-
- final FilterRegistrationBean filterRegBean = dosFilter(Arrays.asList(DDI_ANT_MATCHERS),
- securityProperties.getDos().getFilter(), securityProperties.getClients());
+ public FilterRegistrationBean dosFilterDDI(final HawkbitSecurityProperties securityProperties) {
+ final FilterRegistrationBean filterRegBean =
+ dosFilter(List.of(DDI_ANT_MATCHERS),
+ securityProperties.getDos().getFilter(), securityProperties.getClients());
filterRegBean.setOrder(DOS_FILTER_ORDER);
filterRegBean.setName("dosDDiFilter");
return filterRegBean;
}
- @Override
- protected void configure(final HttpSecurity http) throws Exception {
+ @Bean
+ @Order(300)
+ protected SecurityFilterChain filterChainDDI(final HttpSecurity http) throws Exception {
+ final AuthenticationManager authenticationManager = setAuthenticationManager(http, ddiSecurityConfiguration);
- final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
-
- final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
- ddiSecurityConfiguration.getRp().getCnHeader(),
- ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(), tenantConfigurationManagement,
- tenantAware, systemSecurityContext);
- securityHeaderFilter.setAuthenticationManager(authenticationManager());
- securityHeaderFilter.setCheckForPrincipalChanges(true);
- securityHeaderFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- final HttpControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new HttpControllerPreAuthenticateSecurityTokenFilter(
- tenantConfigurationManagement, tenantAware, controllerManagement, systemSecurityContext);
- securityTokenFilter.setAuthenticationManager(authenticationManager());
- securityTokenFilter.setCheckForPrincipalChanges(true);
- securityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- final HttpControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
- tenantConfigurationManagement, tenantAware, systemSecurityContext);
- gatewaySecurityTokenFilter.setAuthenticationManager(authenticationManager());
- gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
- gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- HttpSecurity httpSec = http.csrf().disable();
+ http
+ .requestMatchers(requestMatchers -> requestMatchers.antMatchers(DDI_ANT_MATCHERS))
+ .csrf(AbstractHttpConfigurer::disable);
if (securityProperties.isRequireSsl()) {
- httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
+ http.requiresChannel(crmRegistry -> crmRegistry.anyRequest().requiresSecure());
}
+ final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
if (ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled()) {
-
LOG.info(
- "******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************");
+ """
+ ******************
+ ** Anonymous controller security enabled, should only be used for developing purposes **
+ ******************""");
final AnonymousAuthenticationFilter anonymousFilter = new AnonymousAuthenticationFilter(
"controllerAnonymousFilter", "anonymous",
- Arrays.asList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS)));
+ List.of(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS)));
anonymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
- httpSec.requestMatchers().antMatchers(DDI_ANT_MATCHERS).and().securityContext().disable().anonymous()
- .authenticationFilter(anonymousFilter);
+ http
+ .securityContext(AbstractHttpConfigurer::disable)
+ .anonymous(configurer -> configurer.authenticationFilter(anonymousFilter));
} else {
+ final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
+ ddiSecurityConfiguration.getRp().getCnHeader(),
+ ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(), tenantConfigurationManagement,
+ tenantAware, systemSecurityContext);
+ securityHeaderFilter.setAuthenticationManager(authenticationManager);
+ securityHeaderFilter.setCheckForPrincipalChanges(true);
+ securityHeaderFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
- httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter)
- .addFilter(gatewaySecurityTokenFilter).requestMatchers().antMatchers(DDI_ANT_MATCHERS).and()
- .anonymous().disable().authorizeRequests().anyRequest().authenticated().and()
- .exceptionHandling()
- .authenticationEntryPoint((request, response, authException) -> response
- .setStatus(HttpStatus.UNAUTHORIZED.value()))
- .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+ final HttpControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new HttpControllerPreAuthenticateSecurityTokenFilter(
+ tenantConfigurationManagement, tenantAware, controllerManagement, systemSecurityContext);
+ securityTokenFilter.setAuthenticationManager(authenticationManager);
+ securityTokenFilter.setCheckForPrincipalChanges(true);
+ securityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
+
+ final HttpControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
+ tenantConfigurationManagement, tenantAware, systemSecurityContext);
+ gatewaySecurityTokenFilter.setAuthenticationManager(authenticationManager);
+ gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
+ gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
+
+ http
+ .authorizeHttpRequests(amrmRegistry ->
+ amrmRegistry.anyRequest().authenticated())
+ .anonymous(AbstractHttpConfigurer::disable)
+ .addFilter(securityHeaderFilter)
+ .addFilter(securityTokenFilter)
+ .addFilter(gatewaySecurityTokenFilter)
+ .exceptionHandling(configurer -> configurer.authenticationEntryPoint(
+ (request, response, authException) ->
+ response.setStatus(HttpStatus.UNAUTHORIZED.value())))
+ .sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
}
- }
- @Override
- protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
-
- auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
- ddiSecurityConfiguration.getRp().getTrustedIPs()));
+ return http.build();
}
}
@@ -277,9 +256,8 @@ public class SecurityManagedConfiguration {
* interface.
*/
@Configuration
- @Order(301)
@ConditionalOnClass(DdiApiConfiguration.class)
- static class ControllerDownloadSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
+ static class ControllerDownloadSecurityConfigurationAdapter {
private static final String DDI_DL_ANT_MATCHER = DdiRestConstants.BASE_V1_REQUEST_MAPPING
+ "/{controllerId}/softwaremodules/{softwareModuleId}/artifacts/*";
@@ -316,9 +294,8 @@ public class SecurityManagedConfiguration {
*/
@Bean
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true)
- public FilterRegistrationBean dosDDiDlFilter(final HawkbitSecurityProperties securityProperties) {
-
- final FilterRegistrationBean filterRegBean = dosFilter(Arrays.asList(DDI_DL_ANT_MATCHER),
+ public FilterRegistrationBean dosFilterDDIDL(final HawkbitSecurityProperties securityProperties) {
+ final FilterRegistrationBean filterRegBean = dosFilter(List.of(DDI_DL_ANT_MATCHER),
securityProperties.getDos().getFilter(), securityProperties.getClients());
filterRegBean.setOrder(DOS_FILTER_ORDER);
filterRegBean.setName("dosDDiDlFilter");
@@ -326,71 +303,75 @@ public class SecurityManagedConfiguration {
return filterRegBean;
}
- @Override
- protected void configure(final HttpSecurity http) throws Exception {
+ @Bean
+ @Order(301)
+ protected SecurityFilterChain filterChainDDIDL(final HttpSecurity http) throws Exception {
+ final AuthenticationManager authenticationManager = setAuthenticationManager(http, ddiSecurityConfiguration);
+
+ http
+ .requestMatcher(new AntPathRequestMatcher(DDI_DL_ANT_MATCHER))
+ .csrf(AbstractHttpConfigurer::disable);
+
+ if (securityProperties.isRequireSsl()) {
+ http.requiresChannel(crmRegistry -> crmRegistry.anyRequest().requiresSecure());
+ }
final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
- final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
- ddiSecurityConfiguration.getRp().getCnHeader(),
- ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(), tenantConfigurationManagement,
- tenantAware, systemSecurityContext);
- securityHeaderFilter.setAuthenticationManager(authenticationManager());
- securityHeaderFilter.setCheckForPrincipalChanges(true);
- securityHeaderFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- final HttpControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new HttpControllerPreAuthenticateSecurityTokenFilter(
- tenantConfigurationManagement, tenantAware, controllerManagement, systemSecurityContext);
- securityTokenFilter.setAuthenticationManager(authenticationManager());
- securityTokenFilter.setCheckForPrincipalChanges(true);
- securityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- final HttpControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
- tenantConfigurationManagement, tenantAware, systemSecurityContext);
- gatewaySecurityTokenFilter.setAuthenticationManager(authenticationManager());
- gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
- gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- final HttpControllerPreAuthenticateAnonymousDownloadFilter controllerAnonymousDownloadFilter = new HttpControllerPreAuthenticateAnonymousDownloadFilter(
- tenantConfigurationManagement, tenantAware, systemSecurityContext);
- controllerAnonymousDownloadFilter.setAuthenticationManager(authenticationManager());
- controllerAnonymousDownloadFilter.setCheckForPrincipalChanges(true);
- controllerAnonymousDownloadFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
-
- HttpSecurity httpSec = http.csrf().disable();
-
- if (securityProperties.isRequireSsl()) {
- httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
- }
-
if (ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled()) {
-
LOG.info(
- "******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************");
+ """
+ ******************
+ ** Anonymous controller security enabled, should only be used for developing purposes **
+ ******************""");
final AnonymousAuthenticationFilter anonymousFilter = new AnonymousAuthenticationFilter(
"controllerAnonymousFilter", "anonymous",
- Arrays.asList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS)));
+ List.of(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS)));
anonymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
- httpSec.requestMatchers().antMatchers(DDI_DL_ANT_MATCHER).and().securityContext().disable().anonymous()
- .authenticationFilter(anonymousFilter);
+ http
+ .securityContext(AbstractHttpConfigurer::disable)
+ .anonymous(configurer -> configurer.authenticationFilter(anonymousFilter));
} else {
+ final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
+ ddiSecurityConfiguration.getRp().getCnHeader(),
+ ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(), tenantConfigurationManagement,
+ tenantAware, systemSecurityContext);
+ securityHeaderFilter.setAuthenticationManager(authenticationManager);
+ securityHeaderFilter.setCheckForPrincipalChanges(true);
+ securityHeaderFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
- httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter)
- .addFilter(gatewaySecurityTokenFilter).addFilter(controllerAnonymousDownloadFilter)
- .requestMatchers().antMatchers(DDI_DL_ANT_MATCHER).and().anonymous().disable()
- .authorizeRequests().anyRequest().authenticated().and().exceptionHandling()
- .authenticationEntryPoint((request, response, authException) -> response
- .setStatus(HttpStatus.UNAUTHORIZED.value()))
- .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+ final HttpControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new HttpControllerPreAuthenticateSecurityTokenFilter(
+ tenantConfigurationManagement, tenantAware, controllerManagement, systemSecurityContext);
+ securityTokenFilter.setAuthenticationManager(authenticationManager);
+ securityTokenFilter.setCheckForPrincipalChanges(true);
+ securityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
+
+ final HttpControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
+ tenantConfigurationManagement, tenantAware, systemSecurityContext);
+ gatewaySecurityTokenFilter.setAuthenticationManager(authenticationManager);
+ gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
+ gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
+
+ final HttpControllerPreAuthenticateAnonymousDownloadFilter controllerAnonymousDownloadFilter = new HttpControllerPreAuthenticateAnonymousDownloadFilter(
+ tenantConfigurationManagement, tenantAware, systemSecurityContext);
+ controllerAnonymousDownloadFilter.setAuthenticationManager(authenticationManager);
+ controllerAnonymousDownloadFilter.setCheckForPrincipalChanges(true);
+ controllerAnonymousDownloadFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
+
+ http
+ .authorizeHttpRequests(amrmRegistry -> amrmRegistry.anyRequest().authenticated())
+ .anonymous(AbstractHttpConfigurer::disable)
+ .addFilter(securityHeaderFilter)
+ .addFilter(securityTokenFilter)
+ .addFilter(gatewaySecurityTokenFilter)
+ .addFilter(controllerAnonymousDownloadFilter)
+ .exceptionHandling(configurer -> configurer.authenticationEntryPoint(
+ (request, response, authException) -> response.setStatus(HttpStatus.UNAUTHORIZED.value())))
+ .sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
}
- }
- @Override
- protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
-
- auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
- ddiSecurityConfiguration.getRp().getTrustedIPs()));
+ return http.build();
}
}
@@ -407,10 +388,9 @@ public class SecurityManagedConfiguration {
@Bean
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true)
public FilterRegistrationBean dosSystemFilter(final HawkbitSecurityProperties securityProperties) {
-
final FilterRegistrationBean filterRegBean = dosFilter(Collections.emptyList(),
securityProperties.getDos().getFilter(), securityProperties.getClients());
- filterRegBean.setUrlPatterns(Arrays.asList("/system/*"));
+ filterRegBean.setUrlPatterns(List.of("/system/*"));
filterRegBean.setOrder(DOS_FILTER_ORDER);
filterRegBean.setName("dosSystemFilter");
@@ -420,7 +400,6 @@ public class SecurityManagedConfiguration {
private static FilterRegistrationBean dosFilter(final Collection includeAntPaths,
final HawkbitSecurityProperties.Dos.Filter filterProperties,
final HawkbitSecurityProperties.Clients clientProperties) {
-
final FilterRegistrationBean filterRegBean = new FilterRegistrationBean<>();
filterRegBean.setFilter(new DosFilter(includeAntPaths, filterProperties.getMaxRead(),
@@ -435,36 +414,30 @@ public class SecurityManagedConfiguration {
*/
@Configuration
@EnableWebSecurity
- @Order(320)
@ConditionalOnClass(MgmtApiConfiguration.class)
- public static class IdRestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
+ public static class IdRestSecurityConfigurationAdapter {
- @Autowired
- private DdiSecurityProperties ddiSecurityConfiguration;
-
- @Autowired
- private DownloadIdCache downloadIdCache;
-
- @Override
- protected void configure(final HttpSecurity http) throws Exception {
+ @Bean
+ @Order(320)
+ protected SecurityFilterChain filterChainDLID(
+ final HttpSecurity http,
+ final DdiSecurityProperties ddiSecurityConfiguration, final DownloadIdCache downloadIdCache)
+ throws Exception {
+ final AuthenticationManager authenticationManager = setAuthenticationManager(http, ddiSecurityConfiguration);
final HttpDownloadAuthenticationFilter downloadIdAuthenticationFilter = new HttpDownloadAuthenticationFilter(
downloadIdCache);
- downloadIdAuthenticationFilter.setAuthenticationManager(authenticationManager());
+ downloadIdAuthenticationFilter.setAuthenticationManager(authenticationManager);
- http.csrf().disable();
- http.anonymous().disable();
+ http
+ .requestMatcher(new AntPathRequestMatcher("/**/downloadId/**"))
+ .authorizeHttpRequests(armrRepository -> armrRepository.anyRequest().authenticated())
+ .csrf(AbstractHttpConfigurer::disable)
+ .anonymous(AbstractHttpConfigurer::disable)
+ .addFilterBefore(downloadIdAuthenticationFilter, FilterSecurityInterceptor.class)
+ .sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
- http.antMatcher("/**/downloadId/**").addFilterBefore(downloadIdAuthenticationFilter,
- FilterSecurityInterceptor.class);
- http.authorizeRequests().anyRequest().authenticated().and().sessionManagement()
- .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
- }
-
- @Override
- protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
- auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
- ddiSecurityConfiguration.getRp().getTrustedIPs()));
+ return http.build();
}
}
@@ -472,72 +445,79 @@ public class SecurityManagedConfiguration {
* Security configuration for the REST management API.
*/
@Configuration
- @Order(350)
@EnableWebSecurity
@ConditionalOnClass(MgmtApiConfiguration.class)
- public static class RestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
+ public static class RestSecurityConfigurationAdapter {
- @Autowired
- @Lazy
- private UserAuthenticationFilter userAuthenticationFilter;
+ private final HawkbitSecurityProperties securityProperties;
- @Autowired(required = false)
- private OidcBearerTokenAuthenticationFilter oidcBearerTokenAuthenticationFilter;
-
- @Autowired(required = false)
- private InMemoryClientRegistrationRepository clientRegistrationRepository;
-
- @Autowired
- private SystemManagement systemManagement;
-
- @Autowired
- private HawkbitSecurityProperties securityProperties;
-
- @Autowired
- private SystemSecurityContext systemSecurityContext;
+ public RestSecurityConfigurationAdapter(final HawkbitSecurityProperties securityProperties) {
+ this.securityProperties = securityProperties;
+ }
/**
* Filter to protect the hawkBit server Management interface against to
* many requests.
*
- * @param securityProperties
- * for filter configuration
- *
* @return the spring filter registration bean for registering a denial
* of service protection filter in the filter chain
*/
@Bean
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.filter", name = "enabled", matchIfMissing = true)
- public FilterRegistrationBean dosMgmtFilter(final HawkbitSecurityProperties securityProperties) {
-
+ public FilterRegistrationBean dosFilterREST() {
final FilterRegistrationBean filterRegBean = dosFilter(null,
securityProperties.getDos().getFilter(), securityProperties.getClients());
- filterRegBean.setUrlPatterns(Arrays.asList("/rest/*", "/api/*"));
+ filterRegBean.setUrlPatterns(List.of("/rest/*", "/api/*"));
filterRegBean.setOrder(DOS_FILTER_ORDER);
filterRegBean.setName("dosMgmtFilter");
return filterRegBean;
}
- @Override
- protected void configure(final HttpSecurity http) throws Exception {
-
- HttpSecurity httpSec = http.requestMatchers().antMatchers("/rest/**", "/system/admin/**").and().csrf()
- .disable();
+ @Bean
+ @Order(350)
+ protected SecurityFilterChain filterChainREST(
+ final HttpSecurity http,
+ @Lazy
+ final UserAuthenticationFilter userAuthenticationFilter,
+ @Autowired(required = false)
+ final OidcBearerTokenAuthenticationFilter oidcBearerTokenAuthenticationFilter,
+ @Autowired(required = false)
+ final InMemoryClientRegistrationRepository clientRegistrationRepository,
+ final SystemManagement systemManagement,
+ final SystemSecurityContext systemSecurityContext)
+ throws Exception {
+ http
+ .requestMatchers(requestMatchers -> requestMatchers.antMatchers("/rest/**", MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**"))
+ .csrf(AbstractHttpConfigurer::disable)
+ .authorizeHttpRequests(amrmRegistry ->
+ amrmRegistry
+ .antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
+ .hasAnyAuthority(SpPermission.SYSTEM_ADMIN)
+ .anyRequest()
+ .authenticated())
+ .addFilterAfter(
+ // Servlet filter to create metadata after successful authentication over RESTful.
+ (request, response, chain) -> {
+ final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if (authentication != null && authentication.isAuthenticated()) {
+ systemSecurityContext.runAsSystem(systemManagement::getTenantMetadata);
+ }
+ chain.doFilter(request, response);
+ },
+ SessionManagementFilter.class)
+ .anonymous(AbstractHttpConfigurer::disable)
+ .sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
if (securityProperties.getCors().isEnabled()) {
- httpSec = httpSec.cors().configurationSource(reuest -> corsConfiguration()).and();
+ http.cors(configurer -> configurer.configurationSource(corsConfigurationSource()));
}
if (securityProperties.isRequireSsl()) {
- httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
+ http.requiresChannel(crmRegistry -> crmRegistry.anyRequest().requiresSecure());
}
- httpSec.authorizeRequests().antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
- .hasAnyAuthority(SpPermission.SYSTEM_ADMIN).anyRequest().authenticated();
-
if (oidcBearerTokenAuthenticationFilter != null) {
-
// Only get the first client registration. Testing against every
// client could increase the
// attack vector
@@ -547,16 +527,16 @@ public class SecurityManagedConfiguration {
: null;
Assert.notNull(clientRegistration, "There must be a valid client registration");
- httpSec.oauth2ResourceServer().jwt().jwkSetUri(clientRegistration.getProviderDetails().getJwkSetUri());
+ http.oauth2ResourceServer(configurer -> configurer.jwt().jwkSetUri(clientRegistration.getProviderDetails().getJwkSetUri()));
oidcBearerTokenAuthenticationFilter.setClientRegistration(clientRegistration);
- httpSec.addFilterAfter(oidcBearerTokenAuthenticationFilter, BearerTokenAuthenticationFilter.class);
+ http.addFilterAfter(oidcBearerTokenAuthenticationFilter, BearerTokenAuthenticationFilter.class);
} else {
final BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthEntryPoint.setRealmName(securityProperties.getBasicRealm());
- httpSec.addFilterBefore(new Filter() {
+ http.addFilterBefore(new Filter() {
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
userAuthenticationFilter.init(filterConfig);
@@ -573,20 +553,22 @@ public class SecurityManagedConfiguration {
userAuthenticationFilter.destroy();
}
}, RequestHeaderAuthenticationFilter.class);
- httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint);
+ http
+ .httpBasic(Customizer.withDefaults())
+ .exceptionHandling(configurer -> configurer.authenticationEntryPoint(basicAuthEntryPoint));
}
- httpSec.addFilterAfter(
- new AuthenticationSuccessTenantMetadataCreationFilter(systemManagement, systemSecurityContext),
- SessionManagementFilter.class);
-
- httpSec.anonymous().disable();
- httpSec.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+ return http.build();
}
@Bean
- @ConditionalOnProperty(prefix = "hawkbit.server.security.cors", name = "enabled", matchIfMissing = false)
- CorsConfiguration corsConfiguration() {
+ @ConditionalOnProperty(prefix = "hawkbit.server.security.cors", name = "enabled")
+ CorsConfigurationSource corsConfigurationSource() {
+ final CorsConfiguration configuration = corsConfiguration();
+ return request -> configuration;
+ }
+
+ private CorsConfiguration corsConfiguration() {
final CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(securityProperties.getCors().getAllowedOrigins());
@@ -599,281 +581,15 @@ public class SecurityManagedConfiguration {
}
}
- /**
- * {@link WebSecurityConfigurer} for external (management) access.
- */
- @Configuration
- @Order(400)
- @EnableWebSecurity
- @EnableVaadinSharedSecurity
- @ConditionalOnClass(MgmtUiConfiguration.class)
- public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
-
- @Autowired
- private HawkbitSecurityProperties hawkbitSecurityProperties;
-
- @Autowired(required = false)
- private OAuth2UserService oidcUserService;
-
- @Autowired(required = false)
- private AuthenticationSuccessHandler authenticationSuccessHandler;
-
- @Autowired
- private LogoutHandler logoutHandler;
-
- @Autowired
- private LogoutSuccessHandler logoutSuccessHandler;
-
- /**
- * Filter to protect the hawkBit management UI against to many requests.
- *
- * @param securityProperties
- * for filter configuration
- *
- * @return the spring filter registration bean for registering a denial
- * of service protection filter in the filter chain
- */
- @Bean
- @ConditionalOnProperty(prefix = "hawkbit.server.security.dos.ui-filter", name = "enabled", matchIfMissing = true)
- public FilterRegistrationBean dosMgmtUiFilter(final HawkbitSecurityProperties securityProperties) {
-
- final FilterRegistrationBean filterRegBean = dosFilter(null,
- securityProperties.getDos().getUiFilter(), securityProperties.getClients());
- // All URLs that can be called anonymous
- filterRegBean.setUrlPatterns(Arrays.asList("/UI/login", "/UI/login/*", "/UI/logout", "/UI/logout/*"));
- filterRegBean.setOrder(DOS_FILTER_ORDER);
- filterRegBean.setName("dosMgmtUiFilter");
-
- return filterRegBean;
- }
-
- @Override
- @Bean(name = VaadinSharedSecurityConfiguration.AUTHENTICATION_MANAGER_BEAN)
- public AuthenticationManager authenticationManagerBean() throws Exception {
- return super.authenticationManagerBean();
- }
-
- /**
- * Overwriting VaadinAuthenticationSuccessHandler of default
- * VaadinSharedSecurityConfiguration
- *
- * @return the vaadin success authentication handler
- */
- @Primary
- @Bean(name = VaadinSharedSecurityConfiguration.VAADIN_AUTHENTICATION_SUCCESS_HANDLER_BEAN)
- public VaadinAuthenticationSuccessHandler redirectSaveHandler(final HttpService httpService,
- final VaadinRedirectStrategy redirectStrategy) {
- final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(
- httpService, redirectStrategy, "/UI/");
- handler.setTargetUrlParameter("r");
-
- return handler;
- }
-
- /**
- * Listener to redirect to login page after session timeout. Close the
- * vaadin session, because it's is not possible to redirect in
- * atmosphere.
- *
- * @return the servlet listener.
- */
- @Bean
- public ServletListenerRegistrationBean httpSessionEventPublisher() {
- return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
- }
-
- @Override
- protected void configure(final HttpSecurity http) throws Exception {
-
- final boolean enableOidc = oidcUserService != null && authenticationSuccessHandler != null;
-
- // workaround regex: we need to exclude the URL /UI/HEARTBEAT here
- // because we bound the vaadin application to /UI and not to root,
- // described in vaadin-forum:
- // https://vaadin.com/forum#!/thread/3200565.
- HttpSecurity httpSec;
- if (enableOidc) {
- httpSec = http.requestMatchers().antMatchers("/**/UI/**", "/**/oauth2/**").and();
- } else {
- httpSec = http.antMatcher("/**/UI/**");
- }
- // disable as CSRF is handled by Vaadin
- httpSec.csrf().disable();
- // allow same origin X-Frame-Options for correct file download under
- // Safari
- httpSec.headers().frameOptions().sameOrigin();
-
- if (hawkbitSecurityProperties.isRequireSsl()) {
- httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
- } else {
-
- LOG.info(
- "\"******************\\n** Requires HTTPS Security has been disabled for UI, should only be used for developing purposes **\\n******************\"");
- }
-
- if (!StringUtils.isEmpty(hawkbitSecurityProperties.getContentSecurityPolicy())) {
- httpSec.headers().contentSecurityPolicy(hawkbitSecurityProperties.getContentSecurityPolicy());
- }
-
- // UI
- httpSec.authorizeRequests().antMatchers("/UI/login/**", "/UI/UIDL/**").permitAll().anyRequest()
- .authenticated();
-
- if (enableOidc) {
- // OIDC
- httpSec.oauth2Login().userInfoEndpoint().oidcUserService(oidcUserService).and()
- .successHandler(authenticationSuccessHandler).and().oauth2Client();
- } else {
- // UI login / Basic auth
- httpSec.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/UI/login"));
- }
-
- // UI logout
- httpSec.logout().logoutUrl("/UI/logout*").addLogoutHandler(logoutHandler)
- .logoutSuccessHandler(logoutSuccessHandler);
- }
-
- /**
- * HttpFirewall which enables to define a list of allowed host names.
- *
- * @return the http firewall.
- */
- @Bean
- public HttpFirewall httpFirewall() {
- final List allowedHostNames = hawkbitSecurityProperties.getAllowedHostNames();
- final IgnorePathsStrictHttpFirewall firewall = new IgnorePathsStrictHttpFirewall(
- hawkbitSecurityProperties.getHttpFirewallIgnoredPaths());
-
- if (!CollectionUtils.isEmpty(allowedHostNames)) {
- firewall.setAllowedHostnames(hostName -> {
- LOG.debug("Firewall check host: {}, allowed: {}", hostName, allowedHostNames.contains(hostName));
- return allowedHostNames.contains(hostName);
- });
- }
- return firewall;
- }
-
- private static class IgnorePathsStrictHttpFirewall extends StrictHttpFirewall {
-
- private final Collection pathsToIgnore;
-
- public IgnorePathsStrictHttpFirewall(final Collection pathsToIgnore) {
- super();
- this.pathsToIgnore = pathsToIgnore;
- }
-
- @Override
- public FirewalledRequest getFirewalledRequest(final HttpServletRequest request) {
- if (pathsToIgnore != null && pathsToIgnore.contains(request.getRequestURI())) {
- return new FirewalledRequest(request) {
- @Override
- public void reset() {
- // nothing to do
- }
- };
- }
- return super.getFirewalledRequest(request);
- }
- }
-
- @Override
- public void configure(final WebSecurity webSecurity) throws Exception {
- // No security for static content
- webSecurity.ignoring().antMatchers("/documentation/**", "/VAADIN/**", "/*.*", "/docs/**");
- }
-
- /**
- * Configuration that defines the {@link AccessDecisionManager} bean for
- * UI method security used by the Vaadin Servlet. Notice: we can not use
- * the top-level method security configuration because
- * {@link AdviceMode.ASPECTJ} is not supported.
- */
- @Configuration
- @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
- @ConditionalOnClass(MgmtUiConfiguration.class)
- static class UIMethodSecurity extends GlobalMethodSecurityConfiguration {
-
- @Bean(name = VaadinSharedSecurityConfiguration.ACCESS_DECISION_MANAGER_BEAN)
- @Override
- protected AccessDecisionManager accessDecisionManager() {
- return super.accessDecisionManager();
- }
- }
+ private static AuthenticationManager setAuthenticationManager(final HttpSecurity http, final DdiSecurityProperties ddiSecurityConfiguration) throws Exception {
+ // configure authentication manager
+ final AuthenticationManager authenticationManager =
+ http
+ .getSharedObject(AuthenticationManagerBuilder.class)
+ .authenticationProvider(
+ new PreAuthTokenSourceTrustAuthenticationProvider(ddiSecurityConfiguration.getRp().getTrustedIPs()))
+ .build();
+ http.authenticationManager(authenticationManager);
+ return authenticationManager;
}
}
-
-/**
- * After a successful login on the UI we need to ensure to create the tenant
- * meta data within SP.
- */
-class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends VaadinUrlAuthenticationSuccessHandler {
-
- @Autowired
- private SystemManagement systemManagement;
-
- @Autowired
- private SystemSecurityContext systemSecurityContext;
-
- public TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(final HttpService http,
- final VaadinRedirectStrategy redirectStrategy, final String defaultTargetUrl) {
- super(http, redirectStrategy, defaultTargetUrl);
- }
-
- @Override
- public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
- systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, getTenantFrom(authentication));
-
- super.onAuthenticationSuccess(authentication);
- }
-
- private static String getTenantFrom(final Authentication authentication) {
- final Object details = authentication.getDetails();
- if (details instanceof TenantAwareAuthenticationDetails) {
- return ((TenantAwareAuthenticationDetails) details).getTenant();
- }
-
- throw new InsufficientAuthenticationException("Authentication details/tenant info are not specified!");
- }
-}
-
-/**
- * Servletfilter to create metadata after successful authentication over
- * RESTful.
- */
-class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
-
- private final SystemManagement systemManagement;
- private final SystemSecurityContext systemSecurityContext;
-
- AuthenticationSuccessTenantMetadataCreationFilter(final SystemManagement systemManagement,
- final SystemSecurityContext systemSecurityContext) {
- this.systemManagement = systemManagement;
- this.systemSecurityContext = systemSecurityContext;
- }
-
- @Override
- public void init(final FilterConfig filterConfig) throws ServletException {
- // not needed
- }
-
- @Override
- public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
- throws IOException, ServletException {
- lazyCreateTenantMetadata();
- chain.doFilter(request, response);
-
- }
-
- private void lazyCreateTenantMetadata() {
- final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
- if (authentication != null && authentication.isAuthenticated()) {
- systemSecurityContext.runAsSystem(systemManagement::getTenantMetadata);
- }
- }
-
- @Override
- public void destroy() {
- // not needed
- }
-
-}
diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/web/WebMvcAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/web/WebMvcAutoConfiguration.java
deleted file mode 100644
index e0a770137..000000000
--- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/web/WebMvcAutoConfiguration.java
+++ /dev/null
@@ -1,35 +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.web;
-
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
-import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
-
-/**
- * A configuration bean which disables the {@code useSuffixPatternMatch} feature
- * from Spring because it will truncate the dot in a REST URL which leads to
- * problem in case a controllerId contains dots and is a path parameter or
- * filename ending.
- */
-@Configuration
-public class WebMvcAutoConfiguration extends WebMvcConfigurerAdapter {
-
- @Override
- public void configurePathMatch(final PathMatchConfigurer configurer) {
- configurer.setUseSuffixPatternMatch(false);
- configurer.setUseRegisteredSuffixPatternMatch(false);
- }
-
- @Override
- public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
- configurer.favorPathExtension(false);
- }
-}
diff --git a/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories b/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories
index 5716eb54a..501071626 100644
--- a/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -4,7 +4,6 @@ org.eclipse.hawkbit.autoconfigure.cache.CacheAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.cache.DownloadIdCacheAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.ddi.DDiApiAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.dmf.amqp.DmfApiAutoConfiguration,\
-org.eclipse.hawkbit.autoconfigure.mgmt.ui.MgmtUiAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.mgmt.MgmtApiAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.repository.event.EventPublisherAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.repository.ArtifactFilesystemAutoConfiguration,\
@@ -14,5 +13,4 @@ org.eclipse.hawkbit.autoconfigure.scheduling.ExecutorAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.security.SecurityAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.security.InMemoryUserManagementAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.security.OidcUserManagementAutoConfiguration,\
-org.eclipse.hawkbit.autoconfigure.web.WebMvcAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.PropertyHostnameResolverAutoConfiguration
diff --git a/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/pom.xml b/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/pom.xml
index 79d3006c2..9f4697a83 100644
--- a/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/pom.xml
+++ b/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/pom.xml
@@ -61,11 +61,6 @@
spring-boot-starter-web
compile
-
- org.apache.httpcomponents
- httpclient
- compile
-
org.springframework.amqp
spring-rabbit-test
diff --git a/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/AmqpTestConfiguration.java b/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/AmqpTestConfiguration.java
index 5dd491a1f..0a2119834 100644
--- a/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/AmqpTestConfiguration.java
+++ b/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/AmqpTestConfiguration.java
@@ -29,8 +29,6 @@ import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService;
-import com.google.common.base.Throwables;
-
/**
*
*/
@@ -62,13 +60,14 @@ public class AmqpTestConfiguration {
return new ThreadPoolTaskScheduler();
}
+ @SuppressWarnings("java:S112")
@Bean
HostnameResolver hostnameResolver(final HawkbitServerProperties serverProperties) {
return () -> {
try {
return new URL(serverProperties.getUrl());
} catch (final MalformedURLException e) {
- throw Throwables.propagate(e);
+ throw new RuntimeException(e);
}
};
}
diff --git a/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/RabbitMqSetupService.java b/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/RabbitMqSetupService.java
index 530a153ec..68368b957 100644
--- a/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/RabbitMqSetupService.java
+++ b/hawkbit-dmf/hawkbit-dmf-rabbitmq-test/src/main/java/org/eclipse/hawkbit/rabbitmq/test/RabbitMqSetupService.java
@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.rabbitmq.test;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
+import java.net.URL;
import java.util.UUID;
import javax.annotation.PreDestroy;
@@ -17,9 +18,8 @@ import javax.annotation.PreDestroy;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.junit.BrokerRunningSupport;
-import org.springframework.util.StringUtils;
+import org.springframework.util.ObjectUtils;
-import com.google.common.base.Throwables;
import com.rabbitmq.http.client.Client;
import com.rabbitmq.http.client.domain.UserPermissions;
@@ -39,9 +39,9 @@ public class RabbitMqSetupService {
private final String hostname;
- private String username;
+ private final String username;
- private String password;
+ private final String password;
public RabbitMqSetupService() {
@@ -52,12 +52,13 @@ public class RabbitMqSetupService {
password = brokerSupport.getPassword();
}
+ @SuppressWarnings("java:S112")
private synchronized Client getRabbitmqHttpClient() {
if (rabbitmqHttpClient == null) {
try {
- rabbitmqHttpClient = new Client(getHttpApiUrl(), getUsername(), getPassword());
- } catch (MalformedURLException | URISyntaxException e) {
- throw Throwables.propagate(e);
+ rabbitmqHttpClient = new Client(new URL(getHttpApiUrl()), getUsername(), getPassword());
+ } catch (final MalformedURLException | URISyntaxException e) {
+ throw new RuntimeException(e);
}
}
return rabbitmqHttpClient;
@@ -77,7 +78,7 @@ public class RabbitMqSetupService {
@PreDestroy
public void deleteVirtualHost() {
- if (StringUtils.isEmpty(virtualHost)) {
+ if (ObjectUtils.isEmpty(virtualHost)) {
return;
}
getRabbitmqHttpClient().deleteVhost(virtualHost);
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/BaseEntityRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/BaseEntityRepository.java
index 1e79ce588..2c547f14d 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/BaseEntityRepository.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/BaseEntityRepository.java
@@ -15,6 +15,7 @@ import java.util.Optional;
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
+import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.transaction.annotation.Transactional;
@@ -30,7 +31,7 @@ import org.springframework.transaction.annotation.Transactional;
@NoRepositoryBean
@Transactional(readOnly = true)
public interface BaseEntityRepository
- extends PagingAndSortingRepository, NoCountSliceRepository {
+ extends PagingAndSortingRepository, CrudRepository, NoCountSliceRepository {
/**
* Retrieves an {@link BaseEntity} by its id.
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetMetadataRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetMetadataRepository.java
index ab19ca067..545e5de93 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetMetadataRepository.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetMetadataRepository.java
@@ -12,6 +12,7 @@ import org.eclipse.hawkbit.repository.jpa.model.DsMetadataCompositeKey;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
@@ -22,6 +23,7 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional(readOnly = true)
public interface DistributionSetMetadataRepository
extends PagingAndSortingRepository,
+ CrudRepository,
JpaSpecificationExecutor {
/**
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTypeRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTypeRepository.java
index 65ca4e3d8..f80c86c21 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTypeRepository.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetTypeRepository.java
@@ -27,7 +27,8 @@ import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
/**
- * {@link PagingAndSortingRepository} for {@link DistributionSetType}.
+ * {@link PagingAndSortingRepository} and {@link org.springframework.data.repository.CrudRepository} for
+ * {@link DistributionSetType}.
*
*/
@Transactional(readOnly = true)
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleMetadataRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleMetadataRepository.java
index 022023a3b..fa3cec4d3 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleMetadataRepository.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SoftwareModuleMetadataRepository.java
@@ -17,6 +17,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
@@ -28,6 +29,7 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional(readOnly = true)
public interface SoftwareModuleMetadataRepository
extends PagingAndSortingRepository,
+ CrudRepository,
JpaSpecificationExecutor {
/**
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetMetadataRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetMetadataRepository.java
index baa8d22b0..588092a2b 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetMetadataRepository.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetMetadataRepository.java
@@ -12,6 +12,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata;
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
import org.eclipse.hawkbit.repository.model.TargetMetadata;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
@@ -22,6 +23,7 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional(readOnly = true)
public interface TargetMetadataRepository
extends PagingAndSortingRepository,
+ CrudRepository,
JpaSpecificationExecutor {
/**
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTypeRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTypeRepository.java
index 2aaf90eb0..c815efce3 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTypeRepository.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTypeRepository.java
@@ -30,7 +30,8 @@ import org.springframework.lang.NonNull;
import org.springframework.transaction.annotation.Transactional;
/**
- * {@link PagingAndSortingRepository} for {@link JpaTargetType}.
+ * {@link PagingAndSortingRepository} and {@link org.springframework.data.repository.CrudRepository} for
+ * {@link JpaTargetType}.
*
*/
@Transactional(readOnly = true)
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantMetaDataRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantMetaDataRepository.java
index 6bbb87fde..8e8a9ee07 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantMetaDataRepository.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TenantMetaDataRepository.java
@@ -14,6 +14,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTenantMetaData;
import org.eclipse.hawkbit.repository.model.TenantMetaData;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
@@ -23,7 +24,9 @@ import org.springframework.transaction.annotation.Transactional;
*
*/
@Transactional(readOnly = true)
-public interface TenantMetaDataRepository extends PagingAndSortingRepository {
+public interface TenantMetaDataRepository
+ extends PagingAndSortingRepository,
+ CrudRepository {
/**
* Search {@link TenantMetaData} by tenant name.
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java
index c7957f8e9..8673035e5 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java
@@ -42,7 +42,8 @@ import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
-@ContextConfiguration(classes = { RepositoryApplicationConfiguration.class, TestConfiguration.class,
+@ContextConfiguration(classes = {
+ RepositoryApplicationConfiguration.class, TestConfiguration.class,
TestSupportBinderAutoConfiguration.class })
@TestPropertySource(locations = "classpath:/jpa-test.properties")
public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest {
diff --git a/hawkbit-rest/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/AbstractDDiApiIntegrationTest.java b/hawkbit-rest/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/AbstractDDiApiIntegrationTest.java
index 4ad8f7032..7989e8ce8 100644
--- a/hawkbit-rest/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/AbstractDDiApiIntegrationTest.java
+++ b/hawkbit-rest/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/AbstractDDiApiIntegrationTest.java
@@ -54,7 +54,8 @@ import com.fasterxml.jackson.dataformat.cbor.CBORGenerator;
import com.fasterxml.jackson.dataformat.cbor.CBORParser;
@ContextConfiguration(classes = { DdiApiConfiguration.class, RestConfiguration.class,
- RepositoryApplicationConfiguration.class, TestConfiguration.class, TestSupportBinderAutoConfiguration.class })
+ RepositoryApplicationConfiguration.class, TestConfiguration.class,
+ TestSupportBinderAutoConfiguration.class })
@TestPropertySource(locations = "classpath:/ddi-test.properties")
public abstract class AbstractDDiApiIntegrationTest extends AbstractRestIntegrationTest {
diff --git a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/AbstractManagementApiIntegrationTest.java b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/AbstractManagementApiIntegrationTest.java
index 309315707..ce2ee12ef 100644
--- a/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/AbstractManagementApiIntegrationTest.java
+++ b/hawkbit-rest/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/AbstractManagementApiIntegrationTest.java
@@ -30,7 +30,8 @@ import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.ResultMatcher;
@ContextConfiguration(classes = { MgmtApiConfiguration.class, RestConfiguration.class,
- RepositoryApplicationConfiguration.class, TestConfiguration.class, TestSupportBinderAutoConfiguration.class })
+ RepositoryApplicationConfiguration.class, TestConfiguration.class,
+ TestSupportBinderAutoConfiguration.class })
@TestPropertySource(locations = "classpath:/mgmt-test.properties")
public abstract class AbstractManagementApiIntegrationTest extends AbstractRestIntegrationTest {
diff --git a/hawkbit-rest/hawkbit-rest-docs/src/test/java/org/eclipse/hawkbit/rest/documentation/AbstractApiRestDocumentation.java b/hawkbit-rest/hawkbit-rest-docs/src/test/java/org/eclipse/hawkbit/rest/documentation/AbstractApiRestDocumentation.java
index ce20c076e..21aa96445 100644
--- a/hawkbit-rest/hawkbit-rest-docs/src/test/java/org/eclipse/hawkbit/rest/documentation/AbstractApiRestDocumentation.java
+++ b/hawkbit-rest/hawkbit-rest-docs/src/test/java/org/eclipse/hawkbit/rest/documentation/AbstractApiRestDocumentation.java
@@ -71,7 +71,8 @@ import io.qameta.allure.Feature;
@Feature("Documentation Verification - API")
@ExtendWith(RestDocumentationExtension.class)
@ContextConfiguration(classes = { DdiApiConfiguration.class, MgmtApiConfiguration.class, RestConfiguration.class,
- RepositoryApplicationConfiguration.class, TestConfiguration.class, TestSupportBinderAutoConfiguration.class })
+ RepositoryApplicationConfiguration.class, TestConfiguration.class,
+ TestSupportBinderAutoConfiguration.class })
@TestPropertySource(locations = { "classpath:/updateserver-restdocumentation-test.properties" })
public abstract class AbstractApiRestDocumentation extends AbstractRestIntegrationTest {
diff --git a/hawkbit-runtime/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/CorsTest.java b/hawkbit-runtime/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/CorsTest.java
index 76d9f9d84..7217b489c 100644
--- a/hawkbit-runtime/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/CorsTest.java
+++ b/hawkbit-runtime/hawkbit-update-server/src/test/java/org/eclipse/hawkbit/app/CorsTest.java
@@ -17,6 +17,7 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.PropertySource;
import org.springframework.http.HttpHeaders;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.web.servlet.ResultActions;
@@ -25,10 +26,15 @@ import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.qameta.allure.Story;
-@SpringBootTest(properties = { "hawkbit.dmf.rabbitmq.enabled=false", "hawkbit.server.security.cors.enabled=true",
- "hawkbit.server.security.cors.allowedOrigins=" + CorsTest.ALLOWED_ORIGIN_FIRST + ","
+@SpringBootTest(properties = {
+ "hawkbit.dmf.rabbitmq.enabled=false",
+ "hawkbit.server.security.cors.enabled=true",
+ "hawkbit.server.security.cors.allowedOrigins="
+ + CorsTest.ALLOWED_ORIGIN_FIRST + ","
+ CorsTest.ALLOWED_ORIGIN_SECOND,
- "hawkbit.server.security.cors.exposedHeaders=Access-Control-Allow-Origin" })@Feature("Integration Test - Security")
+ "hawkbit.server.security.cors.exposedHeaders="
+ + HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN})
+@Feature("Integration Test - Security")
@Story("CORS")
public class CorsTest extends AbstractSecurityTest {
diff --git a/hawkbit-ui/pom.xml b/hawkbit-ui/pom.xml
index 41592dd8d..29b7b83c7 100644
--- a/hawkbit-ui/pom.xml
+++ b/hawkbit-ui/pom.xml
@@ -149,6 +149,16 @@
hawkbit-repository-api
${project.version}
+
+ org.eclipse.hawkbit
+ hawkbit-http-security
+ ${project.version}
+
+
+ org.eclipse.hawkbit
+ hawkbit-autoconfigure
+ ${project.version}
+
commons-io
commons-io
diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/autoconfigure/MgmtUiAutoConfiguration.java
similarity index 98%
rename from hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java
rename to hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/autoconfigure/MgmtUiAutoConfiguration.java
index 713328029..417c88d7e 100644
--- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/autoconfigure/MgmtUiAutoConfiguration.java
@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
-package org.eclipse.hawkbit.autoconfigure.mgmt.ui;
+package org.eclipse.hawkbit.ui.autoconfigure;
import java.util.concurrent.ScheduledExecutorService;
diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/RedirectController.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/autoconfigure/RedirectController.java
similarity index 94%
rename from hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/RedirectController.java
rename to hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/autoconfigure/RedirectController.java
index 9fd9049e3..ef902cd34 100644
--- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/RedirectController.java
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/autoconfigure/RedirectController.java
@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
-package org.eclipse.hawkbit.autoconfigure.mgmt.ui;
+package org.eclipse.hawkbit.ui.autoconfigure;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/autoconfigure/UISecurityConfigurationAdapter.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/autoconfigure/UISecurityConfigurationAdapter.java
new file mode 100644
index 000000000..01e50b365
--- /dev/null
+++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/autoconfigure/UISecurityConfigurationAdapter.java
@@ -0,0 +1,306 @@
+/**
+ * Copyright (c) 2021 Bosch.IO 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.autoconfigure;
+
+import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
+import org.eclipse.hawkbit.repository.SystemManagement;
+import org.eclipse.hawkbit.security.DosFilter;
+import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
+import org.eclipse.hawkbit.security.SystemSecurityContext;
+import org.eclipse.hawkbit.ui.MgmtUiConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.access.AccessDecisionManager;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.InsufficientAuthenticationException;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
+import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
+import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
+import org.springframework.security.web.firewall.FirewalledRequest;
+import org.springframework.security.web.firewall.HttpFirewall;
+import org.springframework.security.web.firewall.StrictHttpFirewall;
+import org.springframework.security.web.session.HttpSessionEventPublisher;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+import org.vaadin.spring.http.HttpService;
+import org.vaadin.spring.security.annotation.EnableVaadinSharedSecurity;
+import org.vaadin.spring.security.config.VaadinSharedSecurityConfiguration;
+import org.vaadin.spring.security.shared.VaadinAuthenticationSuccessHandler;
+import org.vaadin.spring.security.shared.VaadinUrlAuthenticationSuccessHandler;
+import org.vaadin.spring.security.web.VaadinRedirectStrategy;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * {@link WebSecurityConfigurer} for external (management) access.
+ */
+@Configuration
+@EnableWebSecurity
+@EnableVaadinSharedSecurity
+@ConditionalOnClass(MgmtUiConfiguration.class)
+public class UISecurityConfigurationAdapter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(UISecurityConfigurationAdapter.class);
+
+ private static final int DOS_FILTER_ORDER = -200;
+
+ @Autowired
+ private HawkbitSecurityProperties hawkbitSecurityProperties;
+
+ /**
+ * Filter to protect the hawkBit management UI against to many requests.
+ *
+ * @param securityProperties for filter configuration
+ * @return the spring filter registration bean for registering a denial
+ * of service protection filter in the filter chain
+ */
+ @Bean
+ @ConditionalOnProperty(prefix = "hawkbit.server.security.dos.ui-filter", name = "enabled", matchIfMissing = true)
+ public FilterRegistrationBean dosMgmtUiFilter(final HawkbitSecurityProperties securityProperties) {
+ final HawkbitSecurityProperties.Dos.Filter filterProperties = securityProperties.getDos().getUiFilter();
+ final HawkbitSecurityProperties.Clients clientProperties = securityProperties.getClients();
+
+ final FilterRegistrationBean filterRegBean = new FilterRegistrationBean<>();
+
+ filterRegBean.setFilter(new DosFilter(null, filterProperties.getMaxRead(),
+ filterProperties.getMaxWrite(), filterProperties.getWhitelist(), clientProperties.getBlacklist(),
+ clientProperties.getRemoteIpHeader()));
+
+ // All URLs that can be called anonymous
+ filterRegBean.setUrlPatterns(Arrays.asList("/UI/login", "/UI/login/*", "/UI/logout", "/UI/logout/*"));
+ filterRegBean.setOrder(DOS_FILTER_ORDER);
+ filterRegBean.setName("dosMgmtUiFilter");
+
+ return filterRegBean;
+ }
+
+ @Bean
+ AuthenticationManager authenticationManager(final AuthenticationConfiguration authenticationConfiguration) throws Exception {
+ return authenticationConfiguration.getAuthenticationManager();
+ }
+
+ /**
+ * Overwriting VaadinAuthenticationSuccessHandler of default
+ * VaadinSharedSecurityConfiguration
+ *
+ * @return the vaadin success authentication handler
+ */
+ @Primary
+ @Bean(name = VaadinSharedSecurityConfiguration.VAADIN_AUTHENTICATION_SUCCESS_HANDLER_BEAN)
+ public VaadinAuthenticationSuccessHandler redirectSaveHandler(final HttpService httpService,
+ final VaadinRedirectStrategy redirectStrategy) {
+ final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(
+ httpService, redirectStrategy, "/UI/");
+ handler.setTargetUrlParameter("r");
+
+ return handler;
+ }
+
+ /**
+ * Listener to redirect to login page after session timeout. Close the
+ * vaadin session, because it's is not possible to redirect in
+ * atmosphere.
+ *
+ * @return the servlet listener.
+ */
+ @Bean
+ public ServletListenerRegistrationBean httpSessionEventPublisher() {
+ return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
+ }
+
+ @Bean
+ @Order(400)
+ protected SecurityFilterChain filterChainUI(
+ final HttpSecurity http,
+ @Autowired(required = false)
+ final OAuth2UserService oidcUserService,
+ @Autowired(required = false)
+ final AuthenticationSuccessHandler authenticationSuccessHandler,
+ final LogoutHandler logoutHandler,
+ final LogoutSuccessHandler logoutSuccessHandler)
+ throws Exception {
+ final boolean enableOidc = oidcUserService != null && authenticationSuccessHandler != null;
+
+ // workaround regex: we need to exclude the URL /UI/HEARTBEAT here
+ // because we bound the vaadin application to /UI and not to root,
+ // described in vaadin-forum:
+ // https://vaadin.com/forum#!/thread/3200565.
+ HttpSecurity httpSec;
+ if (enableOidc) {
+ httpSec = http.requestMatchers().antMatchers("/**/UI/**", "/**/oauth2/**").and();
+ } else {
+ httpSec = http.antMatcher("/**/UI/**");
+ }
+ // disable as CSRF is handled by Vaadin
+ httpSec.csrf(AbstractHttpConfigurer::disable);
+ // allow same origin X-Frame-Options for correct file download under
+ // Safari
+ httpSec.headers().frameOptions().sameOrigin();
+
+ if (hawkbitSecurityProperties.isRequireSsl()) {
+ httpSec = httpSec.requiresChannel(crmRegistry -> crmRegistry.anyRequest().requiresSecure());
+ } else {
+ LOG.info(
+ """
+ ******************
+ ** Requires HTTPS Security has been disabled for UI, should only be used for developing purposes **
+ ******************""");
+ }
+
+ if (!ObjectUtils.isEmpty(hawkbitSecurityProperties.getContentSecurityPolicy())) {
+ httpSec.headers().contentSecurityPolicy(hawkbitSecurityProperties.getContentSecurityPolicy());
+ }
+
+ // UI
+ httpSec.authorizeRequests().antMatchers("/UI/login/**", "/UI/UIDL/**").permitAll().anyRequest()
+ .authenticated();
+
+ if (enableOidc) {
+ // OIDC
+ httpSec.oauth2Login().userInfoEndpoint().oidcUserService(oidcUserService).and()
+ .successHandler(authenticationSuccessHandler).and().oauth2Client();
+ } else {
+ // UI login / Basic auth
+ httpSec.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/UI/login"));
+ }
+
+ // UI logout
+ httpSec.logout().logoutUrl("/UI/logout*").addLogoutHandler(logoutHandler)
+ .logoutSuccessHandler(logoutSuccessHandler);
+
+ return httpSec.build();
+ }
+
+ /**
+ * HttpFirewall which enables to define a list of allowed host names.
+ *
+ * @return the http firewall.
+ */
+ @Bean
+ public HttpFirewall httpFirewall() {
+ final List allowedHostNames = hawkbitSecurityProperties.getAllowedHostNames();
+ final IgnorePathsStrictHttpFirewall firewall = new IgnorePathsStrictHttpFirewall(
+ hawkbitSecurityProperties.getHttpFirewallIgnoredPaths());
+
+ if (!CollectionUtils.isEmpty(allowedHostNames)) {
+ firewall.setAllowedHostnames(hostName -> {
+ LOG.debug("Firewall check host: {}, allowed: {}", hostName, allowedHostNames.contains(hostName));
+ return allowedHostNames.contains(hostName);
+ });
+ }
+ return firewall;
+ }
+
+ private static class IgnorePathsStrictHttpFirewall extends StrictHttpFirewall {
+
+ private final Collection pathsToIgnore;
+
+ public IgnorePathsStrictHttpFirewall(final Collection pathsToIgnore) {
+ super();
+ this.pathsToIgnore = pathsToIgnore;
+ }
+
+ @Override
+ public FirewalledRequest getFirewalledRequest(final HttpServletRequest request) {
+ if (pathsToIgnore != null && pathsToIgnore.contains(request.getRequestURI())) {
+ return new FirewalledRequest(request) {
+ @Override
+ public void reset() {
+ // nothing to do
+ }
+ };
+ }
+ return super.getFirewalledRequest(request);
+ }
+ }
+
+ @Bean
+ public WebSecurityCustomizer webSecurityCustomizer() {
+ // No security for static content
+ return (web) -> web.ignoring().antMatchers("/documentation/**", "/VAADIN/**", "/*.*", "/docs/**");
+ }
+
+ /**
+ * Configuration that defines the {@link AccessDecisionManager} bean for
+ * UI method security used by the Vaadin Servlet. Notice: we can not use
+ * the top-level method security configuration because
+ * AdviceMode.ASPECTJ is not supported.
+ */
+ @Configuration
+ @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
+ @ConditionalOnClass(MgmtUiConfiguration.class)
+ static class UIMethodSecurity extends GlobalMethodSecurityConfiguration {
+
+ @Bean(name = VaadinSharedSecurityConfiguration.ACCESS_DECISION_MANAGER_BEAN)
+ @Override
+ protected AccessDecisionManager accessDecisionManager() {
+ return super.accessDecisionManager();
+ }
+ }
+
+ /**
+ * After a successful login on the UI we need to ensure to create the tenant
+ * meta data within SP.
+ */
+ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends VaadinUrlAuthenticationSuccessHandler {
+
+ @Autowired
+ private SystemManagement systemManagement;
+
+ @Autowired
+ private SystemSecurityContext systemSecurityContext;
+
+ public TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(final HttpService http,
+ final VaadinRedirectStrategy redirectStrategy, final String defaultTargetUrl) {
+ super(http, redirectStrategy, defaultTargetUrl);
+ }
+
+ @Override
+ public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
+ systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, getTenantFrom(authentication));
+
+ super.onAuthenticationSuccess(authentication);
+ }
+
+ private static String getTenantFrom(final Authentication authentication) {
+ final Object details = authentication.getDetails();
+ if (details instanceof TenantAwareAuthenticationDetails) {
+ return ((TenantAwareAuthenticationDetails) details).getTenant();
+ }
+
+ throw new InsufficientAuthenticationException("Authentication details/tenant info are not specified!");
+ }
+ }
+}
diff --git a/hawkbit-ui/src/main/resources/META-INF/spring.factories b/hawkbit-ui/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..877556b91
--- /dev/null
+++ b/hawkbit-ui/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,3 @@
+# Auto Configure
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.eclipse.hawkbit.ui.autoconfigure.MgmtUiAutoConfiguration
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 801e798ad..e805283bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.7.12
+ 2.7.13
org.eclipse.hawkbit
@@ -127,16 +127,14 @@
+ true
17
- 2.7.12
- 5.3.26
+ 2.7.13
2021.0.5
2.0.0.RELEASE
- true
-
@@ -148,11 +146,6 @@
2.14.2
-
- 1.2.9
-
-
- 5.7.7
3.12.1
@@ -853,11 +846,6 @@
spring-plugin-core
${spring.plugin.core.version}
-
- org.springframework.security
- spring-security-oauth2-client
- ${spring-security-oauth2-client.version}
-