How to configure spring security 3.2 to use dao authentication and custom authentication filter using java config

java, java-ee-7, spring-java-config, spring-security

Solution

In order to use a customized class replacing the UsernamePasswordAuthenticationFilter do the following:

create a new class `FormLoginConfigurer` with the following content (the original `org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer` is unfortunately final and cannot be extended), notice the call to `super(new CustomAuthenticationProcessingFilter(),null)`:

package demo;

import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

public class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H,FormLoginConfigurer<H>,UsernamePasswordAuthenticationFilter> {

public FormLoginConfigurer() {
    super(new CustomAuthenticationProcessingFilter(),null);
    usernameParameter("username");
    passwordParameter("password");
}

public FormLoginConfigurer<H> loginPage(String loginPage) {
    return super.loginPage(loginPage);
}

public FormLoginConfigurer<H> usernameParameter(String usernameParameter) {
    getAuthenticationFilter().setUsernameParameter(usernameParameter);
    return this;
}

public FormLoginConfigurer<H> passwordParameter(String passwordParameter) {
    getAuthenticationFilter().setPasswordParameter(passwordParameter);
    return this;
}

@Override
public void init(H http) throws Exception {
    super.init(http);
    initDefaultLoginFilter(http);
}

@Override
protected RequestMatcher createLoginProcessingUrlMatcher(
        String loginProcessingUrl) {
    return new AntPathRequestMatcher(loginProcessingUrl, "POST");
}

private String getUsernameParameter() {
    return getAuthenticationFilter().getUsernameParameter();
}

private String getPasswordParameter() {
    return getAuthenticationFilter().getPasswordParameter();
}

private void initDefaultLoginFilter(H http) {
    DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageGeneratingFilter.class);
    if(loginPageGeneratingFilter != null && !isCustomLoginPage()) {
        loginPageGeneratingFilter.setFormLoginEnabled(true);
        loginPageGeneratingFilter.setUsernameParameter(getUsernameParameter());
        loginPageGeneratingFilter.setPasswordParameter(getPasswordParameter());
        loginPageGeneratingFilter.setLoginPageUrl(getLoginPage());
        loginPageGeneratingFilter.setFailureUrl(getFailureUrl());
        loginPageGeneratingFilter.setAuthenticationUrl(getLoginProcessingUrl());
    }
}

}

remove the `formLogin()` call from your `configure(HttpSecurity)` method and use the following initialization instead:

 FormLoginConfigurer formLogin = new FormLoginConfigurer();
 http.apply(formLogin);
 formLogin.loginPage("/auth/login")
         .permitAll();

the authentication manager will be provided to your instance automatically

- you can customize the `SessionAuthenticationStrategy` used in your class by calls to `http.sessionManagement()`, or you can add logic to your new `FormLoginConfigurer` which updates whatever you need

Another option is to register your `CustomUsernamePasswordAuthenticationFilter` filter as an additional filter:

in the `configure(HttpSecurity http)` method call:

 http.addFilter(authFilter());

make sure to configure all options of the filter manually

- beware that system will also add another instance of the UsernamePasswordAuthenticationFilter after yours

In order to add a custom `AuthenticationProvider`:

override method `configure(AuthenticationManagerBuilder auth)` and add the provider:

 @Override
 protected void configure(AuthenticationManagerBuilder auth) throws Exception {
     auth.authenticationProvider(customAuthenticationManagerBean());
 }

Problem

I have googled spring security examples using dao authentication and custom authentication filter, but which are I found, all the examples are using xml file configuration, My question is how to configure custom filter i.e. UsernamePasswordAuthenticationFilter my xml based securityConfig file looks like: ``` <http auto-config="false" use-expressions="true"> <intercept-url pattern="/" access="permitAll" /> <intercept-url pattern="/auth/login.html" access="permitAll" /> <intercept-url pattern="/auth/logout.html" access="permitAll" /> <intercept-url pattern="/auth/accessDenied.html" access="permitAll" /> <intercept-url pattern="/admin/**" access="hasAnyRole('ROLE_ADMIN')" /> <intercept-url pattern="/user/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" /> <access-denied-handler error-page="/auth/accessDenied.html"/> <form-login login-page='/auth/login.html' default-target-url="/" authentication-success-handler-ref="myAuthenticationSuccessHandler" authentication-failure-url="/auth/loginfailed.html" /> <logout success-handler-ref="myLogoutSuccessHandler" invalidate-session="true" delete-cookies="JSESSIONID" /> <remember-me key="uniqueAndSecret" token-validity-seconds="86400" /> <session-management session-fixation-protection="migrateSession" session-authentication-error-url="/auth/loginfailed.html"> <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/auth/login.html" session-registry-alias="sessionRegistry"/> </session-management> </http> <beans:bean id="myAuthenticationSuccessHandler" class="com.asn.handler.AsnUrlAuthenticationSuccessHandler" /> <beans:bean id="myLogoutSuccessHandler" class="com.asn.handler.AsnLogoutSuccessHandler" /> <beans:bean id="userDetailsService" class="com.asn.service.UserDetailsServiceImpl"/> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref="userDetailsService"> <password-encoder ref="encoder"/> </authentication-provider> <!-- <authentication-provider> <user-service> <user name="user1" password="user1Pass" authorities="ROLE_USER" /> <user name="admin1" password="admin1Pass" authorities="ROLE_ADMIN" /> </user-service> </authentication-provider> --> </authentication-manager> <!-- For hashing and salting user passwords --> <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/> ``` I want to convert the configuration's into Java configuration based.. i have tried like this which is doesn't work: SecurityConfig class: ``` @Configuration @EnableWebMvcSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Resource private UserDetailsService userDetailsService; @Autowired private PasswordEncoder encoder; /*@Autowired public void configureGlobal(AuthenticationManagerBuilder auth)throws Exception { logger.info("configureGlobal(AuthenticationManagerBuilder auth) invoked.."); auth.userDetailsService(userDetailsService).passwordEncoder(encoder); }*/ @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable().authorizeRequests() .antMatchers("/resources/**","/assets/**","/files/**").permitAll() .antMatchers("/auth","/").permitAll() .anyRequest().authenticated() //every request requires the user to be authenticated .and() .formLogin() //form based authentication is supported .loginPage("/auth/login") .permitAll() .and() .logout() .permitAll(); http.exceptionHandling().accessDeniedPage("/auth/accessDenied"); http.sessionManagement().sessionFixation().migrateSession() .sessionAuthenticationStrategy(concunSessContAuthStr()); } @Bean(name="sessionRegistry") public SessionRegistryImpl sessionRegistryBean(){ logger.info("sessionRegistryBean() invoked.."); return new SessionRegistryImpl(); } @Bean public UsernamePasswordAuthenticationFilter authFilter() throws Exception{ logger.info("authFilter() invoked.."); CustomUsernamePasswordAuthenticationFilter upaf = new CustomUsernamePasswordAuthenticationFilter(); upaf.setAuthenticationManager(".."); //here, how to set AuthenticationManager ?? upaf.setSessionAuthenticationStrategy(concunSessContAuthStr()); return upaf; } @Bean public DaoAuthenticationProvider customAuthenticationManagerBean() { DaoAuthenticationProvider dap = new DaoAuthenticationProvider(); dap.setUserDetailsService(userDetailsService); dap.setPasswordEncoder(encoder); return dap; } @Bean public ConcurrentSessionControlAuthenticationStrategy concunSessContAuthStr(){ logger.info("concunSessContAuthStr() invoked.."); ConcurrentSessionControlAuthenticationStrategy cscas= new ConcurrentSessionControlAuthenticationStrategy(sessionRegistryBean()); cscas.setMaximumSessions(2); cscas.setExceptionIfMaximumExceeded(true); return cscas; } } ``` Any Suggestions how to configure? Thank You!

Original source