3

This question is actually related to this issue problem.

Based on the suggestion from @harsh-poddar, I added the filter accordingly.

However, after adding that it seems like I can't login even with valid credential.

Following is the related code:

SecurityConfig

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

//  @Bean
//  public CustomAuthenticationEntryPoint customAuthenticationEntryPoint() {
//      return new CustomAuthenticationEntryPoint();
//  }

@Bean
public CustomExceptionTranslationFilter customExceptionTranslationFilter() {
    return new CustomExceptionTranslationFilter(new CustomAuthenticationEntryPoint());
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        //Note : Able to login without this filter, but after adding this, valid credential also fails
        .addFilterAfter(customExceptionTranslationFilter(), ExceptionTranslationFilter.class)
//      .exceptionHandling()
//          .authenticationEntryPoint(new customAuthenticationEntryPoint())
//          .and()
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .requestCache()
            .requestCache(new NullRequestCache())
            .and()
        .httpBasic()
            .and()
        .csrf().disable();
}

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(new CustomAuthenticationProvider());
    }
}

CustomAuthenticationProvider

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

public CustomAuthenticationProvider() {
    super();
}

@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException  {
    final String name = authentication.getName();
    final String password = authentication.getCredentials().toString();
    if (name.equals("admin") && password.equals("password")) {
        final List<GrantedAuthority> grantedAuths = new ArrayList<>();
        grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
        final UserDetails principal = new User(name, password, grantedAuths);
        final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
        return auth;
    } else {
        throw new BadCredentialsException("NOT_AUTHORIZED");
    }
}

    @Override
    public boolean supports(final Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

}

CustomExceptionTranslationFilter

@Component
public class CustomExceptionTranslationFilter extends ExceptionTranslationFilter {

    public CustomExceptionTranslationFilter(AuthenticationEntryPoint authenticationEntryPoint) {
        super(authenticationEntryPoint);
    }
}

CustomAuthenticationEntryPoint

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized.");
    }
}

p/s : sorry for the basic question, I'm really new in spring & spring security.

Community
  • 1
  • 1
lxnx
  • 194
  • 2
  • 17
  • See my answer in previos question http://stackoverflow.com/questions/37063342/spring-security-with-restcontroller-jsonish-customauthenticationprovider-resp/37063583#37063583 – Javasick May 10 '16 at 08:12
  • @D0dger : thank you for the answer given. But still the same error remains. Login with valid credential also trigger "AuthExceptionEntryPoint". Any hint where can I check to debug this? – lxnx May 10 '16 at 08:50
  • Turn on logging for `org.springframework.security` package and attach it to question (when valid credentials not working) – Javasick May 10 '16 at 09:33

1 Answers1

5

The intended design for AuthenticationEntryPoint is to start/initiate an authentication. However, your implementation CustomAuthenticationEntryPoint does not do this. Instead, it simply sends back an unauthorized response. Please see javadoc for AuthenticationEntryPoint for more details on implementation specifics.

Based on your configuration you are using HTTP Basic for authentication:

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .httpBasic();
}

This specific configuration will automatically configure BasicAuthenticationEntryPoint which is an implementation of AuthenticationEntryPoint. The BasicAuthenticationEntryPoint will challenge the user with a http response header of WWW-Authenticate: Basic realm="User Realm" to authenticate, as per server protocol.

However, the fact that you are configuring your own CustomAuthenticationEntryPoint it will ultimately override the BasicAuthenticationEntryPoint which is not what you want to do.

The other post recommended this configuration which again is not what you want to do.

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .httpBasic()
            .and()
        .exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint());
}

If your main goal is to provide a custom response to the user when authentication fails than I would propose a form login configuration with a configured AuthenticationFailureHandler. Here is the configuration:

http
    .authorizeRequests()
        .anyRequest().authenticated()
        .and()
    .formLogin().failureHandler(new DefaultAuthenticationFailureHandler())
        .and()
    .csrf().disable();   // NOTE: I would recommend enabling CSRF

Your implementation of DefaultAuthenticationFailureHandler would be:

public class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        // Set status only OR do whatever you want to the response
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
    }
}

The AuthenticationFailureHandler is specifically designed to handle a failed authentication attempt.

Community
  • 1
  • 1
Joe Grandja
  • 618
  • 4
  • 12
  • thanks for the suggestion. I've tried this and found that, every request been redirected (302) to "/login". For your info, this is a web service communicate via @RestController. – lxnx May 11 '16 at 05:32