Java tutorial
/* * Copyright (C) 2009-2017 Slava Semushin <slava.semushin@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ru.mystamps.web.support.spring.security; import java.util.Collections; import javax.servlet.Filter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationListener; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpMethod; import org.springframework.boot.web.filter.OrderedRequestContextFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; // CheckStyle: ignore LineLength for next 1 line import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 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; // CheckStyle: ignore LineLength for next 1 line import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint; import ru.mystamps.web.Url; import ru.mystamps.web.config.ServicesConfig; @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MessageSource messageSource; @Autowired private ServicesConfig servicesConfig; @Override @SuppressWarnings("PMD.SignatureDeclareThrowsException") public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/static/**", "/public/**"); } @Override @SuppressWarnings("PMD.SignatureDeclareThrowsException") protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().mvcMatchers(Url.ADD_CATEGORY_PAGE).hasAuthority(StringAuthority.CREATE_CATEGORY) .mvcMatchers(Url.ADD_COUNTRY_PAGE).hasAuthority(StringAuthority.CREATE_COUNTRY) .mvcMatchers(Url.ADD_SERIES_PAGE).hasAuthority(StringAuthority.CREATE_SERIES) .mvcMatchers(Url.SITE_EVENTS_PAGE).hasAuthority(StringAuthority.VIEW_SITE_EVENTS) .regexMatchers(HttpMethod.POST, "/series/[0-9]+") .hasAnyAuthority(StringAuthority.UPDATE_COLLECTION, StringAuthority.ADD_IMAGES_TO_SERIES) .regexMatchers(HttpMethod.POST, Url.ADD_SERIES_ASK_PAGE.replace("{id}", "[0-9]+")) .hasAuthority(StringAuthority.ADD_SERIES_SALES).anyRequest().permitAll().and().formLogin() .loginPage(Url.AUTHENTICATION_PAGE).usernameParameter("login").passwordParameter("password") .loginProcessingUrl(Url.LOGIN_PAGE).failureUrl(Url.AUTHENTICATION_PAGE + "?failed") .defaultSuccessUrl(Url.INDEX_PAGE, true).permitAll().and().logout().logoutUrl(Url.LOGOUT_PAGE) .logoutSuccessUrl(Url.INDEX_PAGE).invalidateHttpSession(true).permitAll().and().exceptionHandling() .accessDeniedHandler(getAccessDeniedHandler()) // This entry point handles when you request a protected page and you are // not yet authenticated .authenticationEntryPoint(new Http403ForbiddenEntryPoint()).and().csrf() // Allow unsecured requests to H2 consoles. .ignoringAntMatchers("/console/**").and().rememberMe() // TODO: GH #27 .disable().headers() // TODO .disable(); } // Used in ServicesConfig.getUserService() public PasswordEncoder getPasswordEncoder() { return new BCryptPasswordEncoder(); } @Bean public ApplicationListener<AuthenticationFailureBadCredentialsEvent> getApplicationListener() { return new AuthenticationFailureListener(servicesConfig.getSiteService()); } @Bean public AccessDeniedHandler getAccessDeniedHandler() { return new LogCsrfEventAndShow403PageForAccessDenied(servicesConfig.getSiteService(), Url.FORBIDDEN_PAGE); } @Bean public AuthenticationProvider getAuthenticationProvider() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setPasswordEncoder(getPasswordEncoder()); provider.setUserDetailsService(getUserDetailsService()); provider.setMessageSource(messageSource); return provider; } // By default RequestContextFilter is created. Override it with its ordered version. // Note that name is important here @Bean(name = "requestContextFilter") public Filter getOrderedRequestContextFilter() { return new OrderedRequestContextFilter(); } // Bean name will be shown in logs @Bean(name = "resetLocaleFilter") public FilterRegistrationBean getResetLocaleFilter(@Qualifier("requestContextFilter") Filter filter) { FilterRegistrationBean bean = new FilterRegistrationBean(new SessionLocaleResolverAwareFilter()); // SessionLocaleResolverAwareFilter should be invoked after RequestContextFilter // to overwrite locale in LocaleContextHolder OrderedRequestContextFilter requestContextFilter = (OrderedRequestContextFilter) filter; bean.setOrder(requestContextFilter.getOrder() + 1); // url pattern should match HttpSecurity.formLogin().loginProcessingUrl() bean.setUrlPatterns(Collections.singletonList(Url.LOGIN_PAGE)); return bean; } private UserDetailsService getUserDetailsService() { return new CustomUserDetailsService(servicesConfig.getUserService()); } }