I cannot get the right UTF-8 encoding in Spring MVC - spring

I have a problem with UTF-8 character (for example ěčžýáí). I find some solutions on Stack Overflow but it doesn't work for me. Here is my Conf class. I'm not using web.xml, everything is via annotation.
#Configuration
#EnableWebMvc
#Import({ SecurityConfig.class })
#ComponentScan(basePackages = "cz.prosvaly")
public class AppConfig {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
#Bean(name="multipartResolver")
public CommonsMultipartResolver multipartResolver(){
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(10000000);
return multipartResolver;
}
}
Here is my filter for encoding:
public class AppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(container);
container.addListener(new ContextLoaderListener(ctx));
FilterRegistration.Dynamic fr = container.addFilter("encodingFilter",
new CharacterEncodingFilter());
fr.setInitParameter("encoding", "UTF-8");
fr.setInitParameter("forceEncoding", "true");
fr.addMappingForUrlPatterns(null, true, "/*");
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
}
}
Dispatcher config:
#Configuration
public class DispatcherConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
// registry.addResourceHandler("/css/**").addResourceLocations("/resources/css/");
// registry.addResourceHandler("/html/**").addResourceLocations("/html/");
// registry.addResourceHandler("/images/**").addResourceLocations("/images/");
}
}
Spring security
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).
usersByUsernameQuery("select username,password, enabled from admin where username=?").
authoritiesByUsernameQuery("select username, role from user_roles where username =? ")
.passwordEncoder(new Md5PasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.and().formLogin()
.loginPage("/login").defaultSuccessUrl("/admin/goods").failureUrl("/login?error")
.usernameParameter("username").passwordParameter("password")
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/login?logout")
.and().csrf();
}
}
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
//do nothing
}
In form that I'm sending on server I have this taglib:
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
I tried update in Tomcat this row:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
But when I submit the form I see this in the log
....type for žÄáížíé

(Posted on behalf of the OP:)
I have to deleted SpringSecurityInitializer and create filter via the following code in in AppInitializer:
fr = container.addFilter("springSecurityFilterChain",
new DelegatingFilterProxy());
fr.addMappingForUrlPatterns(null, true, "/*");

Related

Spring stops serving static resources after messageSource is created

After creatig messageSource bean in spring webMvcConfigurer my application stops serving static resources(images/css/js) with http status 404, but all files have a right path(I'm completely sure that error somewhere within messageSource because without this bean serving works correctly). Maybe you have idea how to resolve this problem?
My WebMvcConfigurerImpl:
#Configuration
#Import({dbConfig.class})
#EnableWebMvc
#EnableSpringDataWebSupport
#ComponentScan("my.shop.common.fliPusto")
#PropertySource("classpath:properties/resources.properties")
public class mvcConfig implements WebMvcConfigurer {
#Value("${uploadBook.path}")
private String bookPath;
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/images/**")
.addResourceLocations("file:/" + bookPath + "/images/");
registry.addResourceHandler("/scripts/**")
.addResourceLocations("file:/" + bookPath + "/scripts/");
registry.addResourceHandler("/styles/**")
.addResourceLocations("file:/" + bookPath + "/styles/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
#Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("classpath:freemarkerTemplates/");
configurer.setDefaultEncoding("UTF-8");
return configurer;
}
#Bean
public FreeMarkerViewResolver freeMarkerViewResolver() {
FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver();
freeMarkerViewResolver.setCache(false);
freeMarkerViewResolver.setPrefix("");
freeMarkerViewResolver.setSuffix(".ftl");
freeMarkerViewResolver.setContentType("text/html; charset=UTF-8");
return freeMarkerViewResolver;
}
#Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("/messages/locales");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}
My securityConfig:
#Configuration
#EnableWebSecurity(debug = true)
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan(value = "my.shop.common.fliPusto.services")
public class securityConfig extends WebSecurityConfigurerAdapter {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(4);
}
#Bean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("UTF-8");
encodingFilter.setForceEncoding(true);
encodingFilter.setForceRequestEncoding(true);
encodingFilter.setForceResponseEncoding(true);
return encodingFilter;
}
#Autowired
void setAuthManagerBuilder(AuthenticationManagerBuilder authenticationManagerBuilder, PasswordEncoder passwordEncoder, UserDetailsService userDetailsService) {
try {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/registration", "/test/*", "/book", "/tag/**", "/user/profile/{profile}", "/images/**", "/scripts/**", "/styles/**").permitAll()
.antMatchers("/admin/**").hasAuthority("MODERATOR")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/")
.permitAll()
.and()
.requiresChannel()
.anyRequest()
.requiresSecure();
http.addFilterBefore(characterEncodingFilter(), CsrfFilter.
}
}
I'm solved this by adding messagesource to another Configuration class and adding this class to the dispatherServlet as the ServletConfigClass
Another config:
#Configuration
public class OtherConfig {
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new
ResourceBundleMessageSource();
messageSource.setBasename("/messages/locales");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}
Servlet class:
public class servlet extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[] {mvcConfig.class, securityConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[] {OtherConfig.class}; <-------------There
}
protected String[] getServletMappings() {
return new String[] {"/"};
}
#Override
protected Filter[] getServletFilters() {
return new Filter[]{new charsetFilter()};
}
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement(""));
}
}

Spring Boot with different security contexts

I have two DispatcherServlets and I want to have different contexts for them. First servlet should be secured with spring security and second servlet should not use security at all.
I register servlets as follows:
#SpringBootApplication(exclude = {DispatcherServletAutoConfiguration.class})
public class Application{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ServletRegistrationBean FirstServletRegistration() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(FirstWebConfig.class, SecurityConfig.class);
dispatcherServlet.setApplicationContext(applicationContext);
ServletRegistrationBean registrationBean = new ServletRegistrationBean(
dispatcherServlet, "/api/*"
);
registrationBean.setName("firstServlet");
return registrationBean;
}
#Bean
public ServletRegistrationBean SecondServletRegistration() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(SecondWebConfig.class);
dispatcherServlet.setApplicationContext(applicationContext);
ServletRegistrationBean registrationBean = new ServletRegistrationBean(
dispatcherServlet, "/*"
);
registrationBean.setName("secondServlet");
return registrationBean;
}
}
For each of the servlets, I set the context:
#Configuration
#EnableWebMvc
#ComponentScan("com.example.app.controllers.first")
public class FirstWebConfig extends WebMvcConfigurerAdapter {
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
#Configuration
#EnableWebMvc
#ComponentScan("com.example.app.controllers.second")
public class SecondWebConfig extends WebMvcConfigurerAdapter {
}
And I want to use SecurityConfig only for "firstServlet":
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final BCryptPasswordEncoder passwordEncoder;
private final DataSource dataSource;
#Autowired
public SecurityConfig(BCryptPasswordEncoder passwordEncoder, DataSource dataSource) {
this.passwordEncoder = passwordEncoder;
this.dataSource = dataSource;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.usersByUsernameQuery(USERS_BY_USERNAME_QUERY)
.authoritiesByUsernameQuery(AUTHORITIES_BY_USERNAME_QUERY)
.dataSource(dataSource)
.passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated().and()
.formLogin()
.loginPage("/api/login")
.usernameParameter("username")
.passwordParameter("password")
.and()
.httpBasic().and()
.csrf().disable();
}
}
So how can I exclude use of security for "secondServlet"?

Basic Authentication not enabling on Spring Boot Application

I am working on a REST WebService. Now as per the requirement, I need to make the webservice secure. To do that I tired to use Spring Security in my application by enabling basic authentication. But Still i can access the app without authentication. I am using only annotations to do all the configuration. Please help me
UPDATE1: I am Deploying it on JBOSS EAP 6.4
Here is the WebSecurityConfig.java which enables the security
#Configuration
#EnableGlobalMethodSecurity
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${ldap.url}")
private String ldapUrl;
#Value("${ldap.userDN}")
private String ldapuserDN;
#Value("${ldap.password}")
private String ldapPassword;
#Override
#Order(1)
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
//.and().csrf().disable();
}
#Override
#Order(2)
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
}
#Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
LdapAuthenticationProvider provider = new LdapAuthenticationProvider(bindAuth());
return provider;
}
#Bean
public BindAuthenticator bindAuth(){
BindAuthenticator bindAuther=new BindAuthenticator(ldapContext());
String [] patternList=new String[1];
patternList[0]="cn={0},ou=ColtUsers,dc=eu,dc=colt";
bindAuther.setUserDnPatterns(patternList);
return bindAuther;
}
#Bean
public DefaultSpringSecurityContextSource ldapContext(){
DefaultSpringSecurityContextSource context= new DefaultSpringSecurityContextSource("ldap://host:390");
context.setUserDn("dndeatils");
context.setPassword("password");
return context;
}
}
here is the appconfig.java
#Configuration
#ComponentScan("package")
#EnableWebMvc
public class AppConfig {
}
Here is the WebAppInitializer
public class WebAppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.register(WebSecurityConfig.class);
ctx.setServletContext(servletContext);
Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
dynamic.addMapping("/*");
dynamic.setLoadOnStartup(1);
}
}
You need to add DelegatingFilterProxy in your WebAppInitializer
public class WebAppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.register(WebSecurityConfig.class);
ctx.setServletContext(servletContext);
// This ContextLoaderListener
servletContext.addListener(new ContextLoaderListener(ctx));
// This Filter
servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain")).addMappingForUrlPatterns(null, false, "/*");
Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
dynamic.addMapping("/*");
dynamic.setLoadOnStartup(1);
}
}

Spring Security Custom Authfilter doesnt work

i am working in a personal project and i using spring web mvc and spring security 4, all annotation based configs, and my custom UsernamePasswordAuthenticationFilter is never reached, i am losing it, i already search but i can get it solved, so if anyone could help, i 'd be very grateful, So here is my code
Spring Initialization
#Order(1)
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{AppConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Security Initialization
#Order(2)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
Spring beans declarations and context stuff
#EnableWebMvc
#Configuration
#ComponentScan({"app","server"})
#Import({ SecurityContext.class })
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/META-INF/resources/");
}
#Bean
public InternalResourceViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setSuffix(".jsp");
resolver.setPrefix("/WEB-INF/views/");
resolver.setContentType("text/html; charset=UTF-8");
resolver.setViewClass(JstlView.class);
return resolver;
}
#Bean
public DriverManagerDataSource dataSource(){
DriverManagerDataSource driver = new DriverManagerDataSource();
driver.setDriverClassName("com.mysql.jdbc.Driver");
driver.setUrl("jdbc:mysql://localhost:3306/dberp-1");
driver.setUsername("root");
driver.setPassword("123456");
return driver;
}
#Bean
public LocalSessionFactoryBean sessionFactory(){
LocalSessionFactoryBean session = new LocalSessionFactoryBean();
session.setDataSource(dataSource());
String[] pakages = {"model"};
session.setPackagesToScan(pakages);
Properties prop = new Properties();
prop.put("dialect", MySQLDialect.class);
session.setHibernateProperties(prop);
return session;
}
}
I am almost sure i am doing something wrong in this SecurityContext class....
#Configuration
#EnableWebSecurity
public class SecurityContext extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint())
.and()
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/login","/resources/**").anonymous()
.antMatchers("/users").hasAuthority("admin")
.antMatchers("/**").hasAnyAuthority("employee","admin")
.and()
.logout()
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
.logoutUrl("/logout")
.and()
.csrf().disable();
}
#Bean
public AuthenticationEntryPoint authenticationEntryPoint(){
AuthenticationEntryPoint entryAuth = new LoginUrlAuthenticationEntryPoint("/login");
return entryAuth;
}
#Bean(name="customAuthenticationManager")
#Override
protected AuthenticationManager authenticationManager() throws Exception {
AuthenticationManager authManager = new CustomAuthenticationManager();
return authManager;
};
#Bean
public UsernamePasswordAuthenticationFilter authenticationFilter() throws Exception{
/*UsernamePasswordAuthenticationFilter authFilter = new UsernamePasswordAuthenticationFilter();
authFilter.setAuthenticationManager(authenticationManager());
authFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/home"));
authFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"));*/
UsernamePasswordAuthenticationFilter authFilter = new AuthFilter();
authFilter.setAuthenticationManager(authenticationManager());
authFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/home"));
authFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"));
authFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
return authFilter;
}
}

Spring Security 3.2: #Autowire doesn't work with java configuration and custom AuthenticationProvider in Spring MVC application?

This problem is relatively well discussed in several blog posts and SO questions. Nevertheless, I wasn't able to find one specifically addressing the problem with java configuration. I'm suspecting that I'm doing something wrong in my java configuration files, since I've found some posts indicating that the problem can be resolved by removing the debug XML tag (https://jira.springsource.org/browse/SEC-1885).
I'm using 3.2.0.RELEASE of spring security, and 3.2.6.RELEASE of spring framework. Below the main files used in the spring security/mvc configuration and the custom AuthenticationProvider.
WebConfig:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.mypackage"})
#ImportResource( { "classpath:/spring-data.xml", "classpath:/trace-context.xml" })
#EnableTransactionManagement
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
#Bean
public StandardServletMultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
#Bean(destroyMethod = "shutdown")
public GraphDatabaseService graphDatabaseService() {
return new GraphDatabaseFactory().newEmbeddedDatabase("target/temp.db");
}
#Bean
public RepositoryInitializer repositoryInitializer() {
return new RepositoryInitializer();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
#Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
cookieLocaleResolver.setDefaultLocale(StringUtils.parseLocaleString("en"));
return cookieLocaleResolver;
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:messages/messages", "classpath:messages/validation");
// if true, the key of the message will be displayed if the key is not
// found, instead of throwing a NoSuchMessageException
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
// # -1 : never reload, 0 always reload
messageSource.setCacheSeconds(0);
return messageSource;
}
}
WebInitializer:
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { WebSecurityConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return new Filter[] { characterEncodingFilter, new SiteMeshFilter()};
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
//servletContext.addListener(new HttpSessionEventPublisher());
}
}
WebSecurityConfig:
#Configuration
#EnableWebSecurity
#Order(1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().permitAll();
// .antMatchers("/", "/login").permitAll()
// .anyRequest().authenticated();
http
.formLogin()
.defaultSuccessUrl("/hello")
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.permitAll();
http
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true);
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.authenticationProvider(new ApplicationAuthenticationProvider());
}
}
WebSecurityInitializer:
public class WebSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
AuthenticationProvider:
#Component(value = "authenticationProvider")
public class ApplicationAuthenticationProvider implements AuthenticationProvider {
#Autowired
public UserService userService;
public ApplicationAuthenticationProvider() {}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = (String) authentication.getCredentials();
User user = userService.loadUserByUsername(username);
if (user == null) {
throw new BadCredentialsException("Username not found.");
}
if (!password.equals(user.getPassword())) {
throw new BadCredentialsException("Wrong password.");
}
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(username, password, authorities);
}
#Override
public boolean supports(Class<?> arg0) {
return true;
}
}
UserService:
#Service
public class UserService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public User loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username);
}
}
Spring is throwing an exception while it is building its application context (during application initialization):
[ERROR] [main 11:53:37] (FrameworkServlet.java:initServletBean:467) Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authenticationProvider': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: public com.evidencefactory.service.UserService com.evidencefactory.security.ApplicationAuthenticationProvider.userService; nested exception is java.lang.IllegalArgumentException: Can not set com.evidencefactory.service.UserService field com.evidencefactory.security.ApplicationAuthenticationProvider.userService to sun.proxy.$Proxy71
I don't understand why it is happening, but if I remove the UserDetailsService interface implementation from UserService class, then the application starts successfully. However, when ApplicationAuthenticationProvider is invoked by Spring, the UserService is not autowired into it and the application throws a NullPointerException.
java.lang.NullPointerException
at com.evidencefactory.security.ApplicationAuthenticationProvider.authenticate(ApplicationAuthenticationProvider.java:33)
Figured out how to put it to work, although there still some issues unanswered.
1) I still don't know why Spring context initialization fails when UserService implements UserDetailsService. Given that I'm not seeing use for it, since I'm using a custom AuthenticationProvider, I just removed this implementation and things are ok for now.
To the best of my knowledge (from what I could understand from my first initial reading of Spring Security reference documentation) providing a custom AuthenticationProvider or an UserDetailsService implementation are exclusive alternatives.
2) As noticed by one of the respondents (#Sotirios Delimanolis) I was instantiating ApplicatinoAuthenticationProvider by hand and since it wasn't being managed by Spring this instance would not have an UserService instance autowired into it. Based on this, I changed WebSecurityConfig to get an autowired instance of ApplicationAuthenticationProvider as can be seen below:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ApplicationAuthenticationProvider authenticationProvider;
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.authenticationProvider(authenticationProvider);
}
}
This wasn't still sufficient, because ApplicationAuthenticationProvider wasn't being autowired into WebSecurityConfig. Based on this link Spring Security 3.1.3 #Autowired not Work when using WebApplicationInitializer I noticed that this was because security config should have a component scan declaration too. Adding #ComponentScan(basePackages = {"com.mypackage"}) to WebSecurityConfig resolved the problem.
I'm going to assume that UserService is a class and has some #Transactional annotation either on itself or one of its methods.
You'll need to add CGLIB to your classpath and change your #EnableTransactionManagement to
#EnableTransactionManagement(proxyTargetClass = true)
so that Spring uses CGLIB proxying (which can proxy classes) instead of JKD proxies (which cannot).
Alternatively, you can create an interface UserService and implement (and annotate with #Service) a UserServiceImpl class. Your autowired UserService field would remain the same, but Spring will be able to use JDK proxies.

Resources