Spring Security custom authentication failure handler redirect with parameter

You didn't allow anonymous access to URL /login.html?error=true, so you are redirected to the login page (/login.html).

AbstractAuthenticationFilterConfigurer#permitAll allows access (for anyone) to failure URL but not for custom failure handler:

Ensures the urls for failureUrl(String) as well as for the HttpSecurityBuilder, the getLoginPage() and getLoginProcessingUrl() are granted access to any user.

You have to allow access explicitly with AbstractRequestMatcherRegistry#antMatchers:

Maps a List of AntPathRequestMatcher instances that do not care which HttpMethod is used.

and ExpressionUrlAuthorizationConfigurer.AuthorizedUrl#permitAll:

Specify that URLs are allowed by anyone.

You don't have to allow the exact URL /login.html?error=true, because AntPathRequestMatcher ignores the query string:

Matcher which compares a pre-defined ant-style pattern against the URL ( servletPath + pathInfo) of an HttpServletRequest. The query string of the URL is ignored and matching is case-insensitive or case-sensitive depending on the arguments passed into the constructor.

Your modified configuration:

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

    http
        .authorizeRequests()
            .antMatchers("/login.html").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login.html")
            .usernameParameter("j_username")
            .passwordParameter("j_password")
            .loginProcessingUrl("/j_spring_security_check")
            .failureHandler(customAuthenticationFailureHandler)// .failureUrl("/login.html?error=true")//.successHandler(authSuccsessHandler)
            .defaultSuccessUrl("/dashboard.html")
            .permitAll()
            .and()
        .logout()
            .invalidateHttpSession(true)
            .logoutSuccessUrl("/")
            .permitAll()
            .and()
        .exceptionHandling()
            .accessDeniedPage("/access.html")
            .and()
        .headers()
            .defaultsDisabled()
            .frameOptions()
            .sameOrigin()
            .cacheControl();

    http
        .csrf().disable();
}