Configure logoutHandler and logoutSuccessHandler as Beans (#938)

* Keep the given query parameter when redirecting the login url

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* Make logout endpoint configurable via properties;
Undo query parameter acceptance when redirecting the login url

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* make logout base variable non static

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* Redo query parameter acceptance when redirecting the login url

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* Remove tenant redirection in RedirectController

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* Configure logoutHandler and logoutSuccessHandler with Beans

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* Undo logout endpoint configuration via properties;

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* remove authenticationEntryPoint configuration; fix review issues

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>

* adopt review comments

Signed-off-by: Natalia Kislicyn <natalia.kislicyn@bosch-si.com>
This commit is contained in:
Natalia Kislicyn
2020-03-04 17:13:54 +01:00
committed by GitHub
parent c091518777
commit b1497a6f0f
4 changed files with 87 additions and 43 deletions

View File

@@ -61,7 +61,9 @@ import org.springframework.security.oauth2.server.resource.authentication.JwtAut
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@@ -86,11 +88,20 @@ public class OidcUserManagementAutoConfiguration {
return new JwtAuthoritiesOidcUserService(extractor); return new JwtAuthoritiesOidcUserService(extractor);
} }
/**
* @return the logout success handler for OpenID Connect
*/
@Bean
public LogoutSuccessHandler oidcLogoutSuccessHandler() {
SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
logoutSuccessHandler.setDefaultTargetUrl("/");
return logoutSuccessHandler;
}
/** /**
* @return the OpenID Connect authentication success handler * @return the OpenID Connect authentication success handler
*/ */
@Bean @Bean
@ConditionalOnMissingBean
public AuthenticationSuccessHandler oidcAuthenticationSuccessHandler() { public AuthenticationSuccessHandler oidcAuthenticationSuccessHandler() {
return new OidcAuthenticationSuccessHandler(); return new OidcAuthenticationSuccessHandler();
} }
@@ -99,7 +110,6 @@ public class OidcUserManagementAutoConfiguration {
* @return the OpenID Connect logout handler * @return the OpenID Connect logout handler
*/ */
@Bean @Bean
@ConditionalOnMissingBean
public LogoutHandler oidcLogoutHandler() { public LogoutHandler oidcLogoutHandler() {
return new OidcLogoutHandler(); return new OidcLogoutHandler();
} }

View File

@@ -22,6 +22,12 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.AuditorAware; import org.springframework.data.domain.AuditorAware;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
/** /**
* {@link EnableAutoConfiguration Auto-configuration} for security. * {@link EnableAutoConfiguration Auto-configuration} for security.
@@ -52,9 +58,9 @@ public class SecurityAutoConfiguration {
} }
/** /**
* Creates the auditore aware. * Creates the auditor aware.
* *
* @return the spring security auditore aware * @return the spring security auditor aware
*/ */
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@@ -82,4 +88,33 @@ public class SecurityAutoConfiguration {
return new SecurityTokenGenerator(); return new SecurityTokenGenerator();
} }
/**
* @return {@link AuthenticationSuccessHandler} bean
*/
@Bean
@ConditionalOnMissingBean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return new SimpleUrlAuthenticationSuccessHandler();
}
/**
* @return {@link LogoutHandler} bean
*/
@Bean
@ConditionalOnMissingBean
public LogoutHandler logoutHandler() {
return new SecurityContextLogoutHandler();
}
/**
* @return {@link LogoutSuccessHandler} bean
*/
@Bean
@ConditionalOnMissingBean
public LogoutSuccessHandler logoutSuccessHandler() {
final SimpleUrlLogoutSuccessHandler simpleUrlLogoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
simpleUrlLogoutSuccessHandler.setTargetUrlParameter("login");
return simpleUrlLogoutSuccessHandler;
}
} }

View File

@@ -86,7 +86,7 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter; import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@@ -236,12 +236,12 @@ public class SecurityManagedConfiguration {
LOG.info( LOG.info(
"******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************"); "******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************");
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter( final AnonymousAuthenticationFilter anonymousFilter = new AnonymousAuthenticationFilter(
"controllerAnonymousFilter", "anonymous", "controllerAnonymousFilter", "anonymous",
Arrays.asList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS))); Arrays.asList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS)));
anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource); anonymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
httpSec.requestMatchers().antMatchers(DDI_ANT_MATCHERS).and().securityContext().disable().anonymous() httpSec.requestMatchers().antMatchers(DDI_ANT_MATCHERS).and().securityContext().disable().anonymous()
.authenticationFilter(anoymousFilter); .authenticationFilter(anonymousFilter);
} else { } else {
httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter) httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter)
@@ -358,12 +358,12 @@ public class SecurityManagedConfiguration {
LOG.info( LOG.info(
"******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************"); "******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************");
final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter( final AnonymousAuthenticationFilter anonymousFilter = new AnonymousAuthenticationFilter(
"controllerAnonymousFilter", "anonymous", "controllerAnonymousFilter", "anonymous",
Arrays.asList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS))); Arrays.asList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS)));
anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource); anonymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
httpSec.requestMatchers().antMatchers(DDI_DL_ANT_MATCHER).and().securityContext().disable().anonymous() httpSec.requestMatchers().antMatchers(DDI_DL_ANT_MATCHER).and().securityContext().disable().anonymous()
.authenticationFilter(anoymousFilter); .authenticationFilter(anonymousFilter);
} else { } else {
httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter) httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter)
@@ -421,7 +421,7 @@ public class SecurityManagedConfiguration {
} }
/** /**
* A Websecruity config to handle and filter the download ids. * A Websecurity config to handle and filter the download ids.
*/ */
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@@ -608,15 +608,19 @@ public class SecurityManagedConfiguration {
private final VaadinUrlAuthenticationSuccessHandler handler; private final VaadinUrlAuthenticationSuccessHandler handler;
@Autowired(required = false)
private AuthenticationSuccessHandler oidcAuthenticationSuccessHandler;
@Autowired(required = false)
private LogoutHandler oidcLogoutHandler;
@Autowired(required = false) @Autowired(required = false)
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService; private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;
@Autowired(required = false)
private AuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
private LogoutHandler logoutHandler;
@Autowired
private LogoutSuccessHandler logoutSuccessHandler;
public UISecurityConfigurationAdapter(final VaadinRedirectStrategy redirectStrategy) { public UISecurityConfigurationAdapter(final VaadinRedirectStrategy redirectStrategy) {
handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(); handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler();
handler.setRedirectStrategy(redirectStrategy); handler.setRedirectStrategy(redirectStrategy);
@@ -673,7 +677,7 @@ public class SecurityManagedConfiguration {
/** /**
* Listener to redirect to login page after session timeout. Close the * Listener to redirect to login page after session timeout. Close the
* vaadin session, because it's is not possible to redirect in * vaadin session, because it's is not possible to redirect in
* atmospehere. * atmosphere.
* *
* @return the servlet listener. * @return the servlet listener.
*/ */
@@ -685,14 +689,13 @@ public class SecurityManagedConfiguration {
@Override @Override
protected void configure(final HttpSecurity http) throws Exception { protected void configure(final HttpSecurity http) throws Exception {
final boolean enableOidc = oidcUserService != null && oidcAuthenticationSuccessHandler != null final boolean enableOidc = oidcUserService != null && authenticationSuccessHandler != null;
&& oidcLogoutHandler != null;
// workaround regex: we need to exclude the URL /UI/HEARTBEAT here // workaround regex: we need to exclude the URL /UI/HEARTBEAT here
// because we bound the vaadin application to /UI and not to root, // because we bound the vaadin application to /UI and not to root,
// described in vaadin-forum: // described in vaadin-forum:
// https://vaadin.com/forum#!/thread/3200565. // https://vaadin.com/forum#!/thread/3200565.
HttpSecurity httpSec = null; HttpSecurity httpSec;
if (enableOidc) { if (enableOidc) {
httpSec = http.regexMatcher("(?!.*HEARTBEAT)^.*\\/(UI|oauth2).*$"); httpSec = http.regexMatcher("(?!.*HEARTBEAT)^.*\\/(UI|oauth2).*$");
} else { } else {
@@ -713,27 +716,23 @@ public class SecurityManagedConfiguration {
httpSec.headers().contentSecurityPolicy(hawkbitSecurityProperties.getContentSecurityPolicy()); httpSec.headers().contentSecurityPolicy(hawkbitSecurityProperties.getContentSecurityPolicy());
} }
if (enableOidc) { // UI
httpSec.authorizeRequests().antMatchers("/UI/login/**").permitAll().antMatchers("/UI/UIDL/**") httpSec.authorizeRequests().antMatchers("/UI/login/**", "/UI/UIDL/**").permitAll()
.permitAll().anyRequest().authenticated().and() .anyRequest().authenticated();
// OIDC
.oauth2Login().userInfoEndpoint().oidcUserService(oidcUserService).and()
.successHandler(oidcAuthenticationSuccessHandler).and().oauth2Client().and()
// logout
.logout().logoutUrl("/UI/logout").addLogoutHandler(oidcLogoutHandler).logoutSuccessUrl("/");
} else {
final SimpleUrlLogoutSuccessHandler simpleUrlLogoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
simpleUrlLogoutSuccessHandler.setTargetUrlParameter("login");
httpSec if (enableOidc) {
// UI // OIDC
.authorizeRequests().antMatchers("/UI/login/**").permitAll().antMatchers("/UI/UIDL/**") httpSec.oauth2Login().userInfoEndpoint().oidcUserService(oidcUserService).and()
.permitAll().anyRequest().authenticated().and() .successHandler(authenticationSuccessHandler).and().oauth2Client();
// UI login / logout } else {
.exceptionHandling() // UI login / Basic auth
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/UI/login/#/")).and().logout() httpSec.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/UI/login"));
.logoutUrl("/UI/logout").logoutSuccessHandler(simpleUrlLogoutSuccessHandler);
} }
// UI logout
httpSec.logout().logoutUrl("/UI/logout*").addLogoutHandler(logoutHandler)
.logoutSuccessHandler(logoutSuccessHandler);
} }
@Override @Override
@@ -780,7 +779,7 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
} }
/** /**
* Sevletfilter to create metadata after successful authentication over RESTful. * Servletfilter to create metadata after successful authentication over RESTful.
*/ */
class AuthenticationSuccessTenantMetadataCreationFilter implements Filter { class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
@@ -817,4 +816,5 @@ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
public void destroy() { public void destroy() {
// not needed // not needed
} }
} }

View File

@@ -15,7 +15,6 @@ package org.eclipse.hawkbit.ui.menu;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.hawkbit.HawkbitServerProperties; import org.eclipse.hawkbit.HawkbitServerProperties;