com.blossomproject.autoconfigure.ui.web.WebInterfaceAutoConfiguration Maven / Gradle / Ivy
package com.blossomproject.autoconfigure.ui.web;
import com.blossomproject.autoconfigure.ui.WebContextAutoConfiguration;
import com.blossomproject.core.association_user_role.AssociationUserRoleService;
import com.blossomproject.core.common.PluginConstants;
import com.blossomproject.core.common.dto.AbstractDTO;
import com.blossomproject.core.common.search.SearchEngine;
import com.blossomproject.core.common.service.AssociationServicePlugin;
import com.blossomproject.core.common.utils.action_token.ActionTokenService;
import com.blossomproject.core.common.utils.privilege.Privilege;
import com.blossomproject.core.user.UserService;
import com.blossomproject.ui.BlossomAuthenticationSuccessHandlerImpl;
import com.blossomproject.ui.current_user.CurrentUserControllerAdvice;
import com.blossomproject.ui.i18n.LocaleControllerAdvice;
import com.blossomproject.ui.menu.Menu;
import com.blossomproject.ui.menu.MenuControllerAdvice;
import com.blossomproject.ui.security.LimitLoginAuthenticationProvider;
import com.blossomproject.ui.theme.Theme;
import com.blossomproject.ui.theme.ThemeControllerAdvice;
import com.blossomproject.ui.web.*;
import com.blossomproject.ui.web.error.BlossomErrorViewResolver;
import com.blossomproject.ui.web.error.ErrorControllerAdvice;
import com.blossomproject.ui.web.utils.session.BlossomSessionRegistryImpl;
import org.elasticsearch.client.Client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.switchuser.SwitchUserFilter;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
import org.springframework.util.Assert;
import org.springframework.web.servlet.ThemeResolver;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Locale;
import java.util.Set;
import static com.blossomproject.autoconfigure.ui.WebContextAutoConfiguration.BLOSSOM_BASE_PATH;
import static com.blossomproject.autoconfigure.ui.WebSecurityAutoConfiguration.BLOSSOM_REMEMBER_ME_COOKIE_NAME;
/**
* Created by Maël Gargadennnec on 04/05/2017.
*/
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass(HomeController.class)
@AutoConfigureAfter(WebContextAutoConfiguration.class)
public class WebInterfaceAutoConfiguration {
private final AssociationUserRoleService associationUserRoleService;
@Qualifier(PluginConstants.PLUGIN_ASSOCIATION_SERVICE)
@Autowired
private PluginRegistry> associationServicePlugins;
@Autowired
@Qualifier(value = PluginConstants.PLUGIN_THEME)
private PluginRegistry themePlugins;
public WebInterfaceAutoConfiguration(
AssociationUserRoleService associationUserRoleService) {
this.associationUserRoleService = associationUserRoleService;
}
@Bean
public SessionRegistry blossomSessionRegistry() {
return new BlossomSessionRegistryImpl(associationUserRoleService);
}
@Bean
public LoginController loginController() {
return new LoginController();
}
@Bean
public HomeController homeController() {
return new HomeController();
}
@Bean
public StatusController statusController(HealthEndpoint healthEndpoint) {
return new StatusController(healthEndpoint);
}
@Bean
public OmnisearchController searchController(Client client,
@Qualifier(PluginConstants.PLUGIN_SEARCH_ENGINE) PluginRegistry> registry) {
return new OmnisearchController(client, registry);
}
@Bean
public ProfileController profileController(UserService userService) {
return new ProfileController(userService);
}
@Bean
public ActivationController activationController(ActionTokenService tokenService,
UserService userService) {
return new ActivationController(tokenService, userService);
}
@Bean
public CurrentUserControllerAdvice currentUserControllerAdvice() {
return new CurrentUserControllerAdvice();
}
@Bean
public ErrorControllerAdvice errorControllerAdvice() {
return new ErrorControllerAdvice();
}
@Bean
public MenuControllerAdvice menuControllerAdvice(Menu menu) {
return new MenuControllerAdvice(menu);
}
@Bean
public LocaleControllerAdvice languageControllerAdvice(Set availableLocales) {
return new LocaleControllerAdvice(availableLocales);
}
@Bean
public ThemeControllerAdvice themeControllerAdvice(ThemeResolver themeResolver) {
return new ThemeControllerAdvice(themePlugins, themeResolver);
}
@Configuration
static class BlossomErrorViewResolverConfiguration {
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
BlossomErrorViewResolverConfiguration(ApplicationContext applicationContext,
ResourceProperties resourceProperties,
AssociationUserRoleService associationUserRoleService) {
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
}
@Bean
public BlossomErrorViewResolver blossomErrorViewResolver() {
return new BlossomErrorViewResolver(this.applicationContext, this.resourceProperties);
}
}
@Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
private final BlossomAuthenticationSuccessHandlerImpl blossomAuthenticationSuccessHandler;
private final SessionRegistry sessionRegistry;
private final Privilege switchUserPrivilege;
private final LimitLoginAuthenticationProvider limitLoginAuthenticationProvider;
private final BlossomWebBackOfficeProperties webBackOfficeProperties;
public FormLoginWebSecurityConfigurerAdapter(
UserDetailsService userDetailsService,
BlossomAuthenticationSuccessHandlerImpl blossomAuthenticationSuccessHandler,
SessionRegistry sessionRegistry,
LimitLoginAuthenticationProvider limitLoginAuthenticationProvider,
@Qualifier("switchUserPrivilege") Privilege switchUserPrivilege,
BlossomWebBackOfficeProperties webBackOfficeProperties) {
this.userDetailsService = userDetailsService;
this.blossomAuthenticationSuccessHandler = blossomAuthenticationSuccessHandler;
this.sessionRegistry = sessionRegistry;
this.limitLoginAuthenticationProvider = limitLoginAuthenticationProvider;
this.switchUserPrivilege = switchUserPrivilege;
this.webBackOfficeProperties = webBackOfficeProperties;
}
@Bean
public static ServletListenerRegistrationBean httpSessionEventPublisher() {
return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
}
@Bean
public SwitchUserFilter switchUserProcessingFilter() {
SwitchUserFilter filter = new SwitchUserFilter();
filter.setUserDetailsService(userDetailsService);
filter.setSwitchAuthorityRole(switchUserPrivilege.privilege());
filter.setSwitchUserUrl("/" + BLOSSOM_BASE_PATH + "/administration/_impersonate");
filter.setExitUserUrl("/" + BLOSSOM_BASE_PATH + "/administration/_impersonate/logout");
filter.setTargetUrl("/" + BLOSSOM_BASE_PATH);
filter.setSwitchFailureUrl("/" + BLOSSOM_BASE_PATH);
return filter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(limitLoginAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(switchUserProcessingFilter(), FilterSecurityInterceptor.class);
http.antMatcher("/" + BLOSSOM_BASE_PATH + "/**")
.authorizeRequests().anyRequest().fullyAuthenticated()
.and().formLogin().loginPage("/" + BLOSSOM_BASE_PATH + "/login")
.failureUrl("/" + BLOSSOM_BASE_PATH + "/login?error")
.successHandler(blossomAuthenticationSuccessHandler).permitAll()
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/" + BLOSSOM_BASE_PATH + "/logout"))
.deleteCookies(BLOSSOM_REMEMBER_ME_COOKIE_NAME)
.logoutSuccessUrl("/" + BLOSSOM_BASE_PATH + "/login").permitAll()
.and().rememberMe().rememberMeCookieName(BLOSSOM_REMEMBER_ME_COOKIE_NAME)
.and().exceptionHandling().defaultAuthenticationEntryPointFor(
(request, response, authException) -> response.sendError(401),
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"))
.and().sessionManagement()
.maximumSessions(webBackOfficeProperties.getMaxSessionsPerUser()).maxSessionsPreventsLogin(true)
.expiredSessionStrategy(
new BlossomInvalidSessionStrategy("/" + BLOSSOM_BASE_PATH + "/login"))
.sessionRegistry(sessionRegistry);
}
}
public static class BlossomInvalidSessionStrategy implements SessionInformationExpiredStrategy {
private final Logger logger = LoggerFactory.getLogger(BlossomInvalidSessionStrategy.class);
private final String destinationUrl;
private final RedirectStrategy redirectStrategy;
public BlossomInvalidSessionStrategy(String invalidSessionUrl) {
this(invalidSessionUrl, new DefaultRedirectStrategy());
}
public BlossomInvalidSessionStrategy(String invalidSessionUrl,
RedirectStrategy redirectStrategy) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl),
"url must start with '/' or with 'http(s)'");
this.destinationUrl = invalidSessionUrl;
this.redirectStrategy = redirectStrategy;
}
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event)
throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Redirecting to '" + destinationUrl + "'");
}
String ajaxHeader = event.getRequest().getHeader("X-Requested-With");
if (ajaxHeader != null && "XMLHttpRequest".equals(ajaxHeader)) {
logger.info("Ajax call detected, send {} error code", 401);
event.getResponse().sendError(401);
return;
}
redirectStrategy.sendRedirect(event.getRequest(), event.getResponse(), destinationUrl);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy