I'm extending UsernamePasswordAuthenticationFilter
so that I can add custom field to save them into the session.
public class AuthFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
//String dbValue = request.getParameter("dbParam");
//request.getSession().setAttribute("dbValue", dbValue);
System.out.println("attempting to authentificate");
while (request.getAttributeNames().hasMoreElements()) {
String e = (String) request.getAttributeNames().nextElement();
System.out.println("param name : " + e + " and param value : " + request.getAttribute(e));
}
return super.attemptAuthentication(request, response);
}
}
And my WebSecurityConfig
@Configuration
@EnableWebMvcSecurity
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public AuthFilter customUsernamePasswordAuthenticationFilter()
throws Exception {
AuthFilter customUsernamePasswordAuthenticationFilter = new AuthFilter();
customUsernamePasswordAuthenticationFilter
.setAuthenticationManager(authenticationManagerBean());
return customUsernamePasswordAuthenticationFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
http.exceptionHandling().accessDeniedPage("/403").and()
.authorizeRequests().antMatchers("/login", "/public/**").permitAll()
.antMatchers("/users/**").hasAuthority("ADMIN")
.anyRequest()
.authenticated().and().formLogin().loginPage("/login")
.defaultSuccessUrl("/index").permitAll().and().logout()
.permitAll();
http.sessionManagement().maximumSessions(1)
.expiredUrl("/login?expired").and()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/");
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.eraseCredentials(false)
.userDetailsService(userDetailsService);
}
Mapping filter: 'customUsernamePasswordAuthenticationFilter' to: [/*]
So I know for sure that the filter is correctly added, but I can never print out what's inside, so it's not called during authentification.
I use Thymeleaf and no xml configuration.
as @M. Deinum suggested,
i changed my UsernamePasswordAuthenticationFilter
, to AbstractAuthenticationProcessingFilter
, called super(new AntPathRequestMatcher("/login","POST"));
Changed addFilterAfter
to addFilterBefore
, and a bit of code, and it worked !
Assuming you are using the latest Spring Boot (1.2.3) you are using Spring Security 3.2.7 This version maps the UsernamePasswordAuthenticationFilter
to /j_spring_security_check
. However when using java based configuration this is changed to /login
.
Yours is still mapped to the old URL. To fix this extend AbstractAuthenticationProcessingFilter
add a default no-args constructor which calls the super constructor which takes a RequestMatcher
. Drawback of this is that if you still require (or want to extend) the functionality of the UsernamePasswordAuthenticationFilter
you would have to duplicate it.
public AuthFilter() {
super(new AntPathRequestMatcher("/login","POST"));
}
Another solution is to still extend the UsernamePasswordAuthenticationFilter
and call setRequiresAuthenticationRequestMatcher
from there.
public AuthFilter() {
super();
setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST"));
}
Or you call that method from your factory method.
@Bean
public AuthFilter customUsernamePasswordAuthenticationFilter()
throws Exception {
AuthFilter customUsernamePasswordAuthenticationFilter = new AuthFilter();
customUsernamePasswordAuthenticationFilter
.setAuthenticationManager(authenticationManagerBean());
customUsernamePasswordAuthenticationFilter
.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST"));
return customUsernamePasswordAuthenticationFilter;
}
There're is also another problem with your configuration, your filter will never be executed because it is executed after the default UsernamePasswordAuthenticationFilter
and authentication already happened your filter will never execute. Make sure it executes before the default filter.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
...
}
In order to make your custom UsernamePasswordAuthenticationFilter implementation work, add .loginProcessingUrl("/dologin") to HttpSecurity in your WebSecurityConfig, here "/dologin" is action attribute value of the html form element:
@Override
//@Order(Ordered.HIGHEST_PRECEDENCE)
public void configure(HttpSecurity http) throws Exception { // @formatter:off
http
...
...
.formLogin().loginPage("/login")
--> .loginProcessingUrl("/dologin") <-- add here
...
--> .addFilterBefore(new AuthFilter(authenticationManagerBean()),UsernamePasswordAuthenticationFilter.class)
}
Next is to provide custom UsernamePasswordAuthenticationFilter implementation:
public class AuthFilter extends UsernamePasswordAuthenticationFilter {
AuthenticationManager authenticationManager;
private boolean continueChainBeforeSuccessfulAuthentication = false;
public AuthFilter( AuthenticationManager authenticationManager){
this.authenticationManager = authenticationManager;
//idk why I have to do this, otherwise it's null
super.setAuthenticationManager(authenticationManager);
}
public AuthFilter() {}
private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
//path to which this filter will intercept
RequestMatcher customFilterUrl = new AntPathRequestMatcher("/dologin"); <--
//dofilter method is copied from AbstractAuthenticationProcessingFilter
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
//if no match then go to next filter
if (!customFilterUrl.matches(request)) {
chain.doFilter(request, response);
} else {
Authentication authResult;
try {
authResult = this.attemptAuthentication(request, response);
if (authResult == null) {
return;
}
this.sessionStrategy.onAuthentication(authResult, request, response);
} catch (InternalAuthenticationServiceException var8) {
this.logger.error("An internal error occurred while trying to authenticate the user.", var8);
this.unsuccessfulAuthentication(request, response, var8);
return;
} catch (AuthenticationException var9) {
this.unsuccessfulAuthentication(request, response, var9);
return;
}
if (this.continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
successfulAuthentication(request, response, chain, authResult);
}
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response)
throws AuthenticationException {
System.out.println("Your prints"); <--
return super.attemptAuthentication(request,response);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With