iLikeBreakfast
iLikeBreakfast

Reputation: 1555

Spring Security with JSON does not work

I'm brand new to spring and I'm trying to figure out how to authenticate a user.

Currently, it looks like everything is set up correctly. When I use x-www-form-urlencoded, I can successfully log in. When using application/json, my application does not receive the emailAddress parameter.

I have been googling and checking SO, but I can't find anything related.

Here is my SecurityConfig.

package com.myapp.config;

import com.myapp.security.RestAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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.EnableWebSecurity;
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.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.web.bind.annotation.RestController;

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    @Qualifier("customUserDetailsService")
    private UserDetailsService userDetailsService;

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Autowired
    public void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.userDetailsService(userDetailsService);
        builder.authenticationProvider(this.authenticationProvider());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());

        return authenticationProvider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);

        http.csrf().disable()
            .exceptionHandling()
            .authenticationEntryPoint(restAuthenticationEntryPoint)
            .and()
            .authorizeRequests()
            .antMatchers("/").authenticated()
            .and()
            .formLogin().loginPage("/login").usernameParameter("emailAddress").passwordParameter("password")
            .successHandler(new SimpleUrlAuthenticationSuccessHandler())
            .failureHandler(new SimpleUrlAuthenticationFailureHandler())
            .and()
            .logout();
    }
}

Upvotes: 0

Views: 807

Answers (1)

Wilson
Wilson

Reputation: 11619

formLogin().loginPage("/login").usernameParameter("emailAddress").passwordParameter("password")
                .successHandler(new SimpleUrlAuthenticationSuccessHandler())
                .failureHandler(new SimpleUrlAuthenticationFailureHandler())

In the above configure, a standard UsernamePasswordAuthenticationFilter is used to obtain username and password from request parameter. However, the standard filter do not parse parameters from your json string in the request.

You may try to create a custom UsernamePasswordAuthenticationFilter to obtain username and password from the your json string and apply your custom filter in configuration. However, unlike XML configuration that can use <custom-filter position="FORM_LOGIN_FILTER" ref="yourCustomFilter" />, you cannot replace the form login filter with your custom filter by Java Config.

As a workaround, you can try with follows:

  1. Create a custom filter extends AbstractAuthenticationProcessingFilter to obtain the username and password from json string and put the parsed parameters into the request. The solution is to use HttpRequestWrapper class, which allow you to wrap one request with another. You can subclass that, and override the getParameter to return username and password which is parsed from json string. You can then pass the wrapped request to chain.doFilter.
  2. Add the custom filter before the standard UsernamePasswordAuthenticationFilter with HttpSecurity#addFilterBefore(yourCustomFilter, UsernamePasswordAuthenticationFilter.class)

As the username and password is parsed from json string to the request parameter, the standard UsernamePasswordAuthenticationFilter should be able to perform authentication.

Upvotes: 1

Related Questions