2

I still new with Spring especially spring security. This application is Restful application.

Following is snippet from @RestController :

@RequestMapping(value = "/new", method = RequestMethod.POST)
    @PreRegistration("new")
    @ResponseBody
    public ResponseEntity<Void> newUser(@RequestBody @Valid TempUser user, UriComponentsBuilder ucBuilder) {

        registerService.addUser(user);

        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/register/{userName}").buildAndExpand(user.getUserName()).toUri());
        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
    }

Following is the snippet from CustomAuthenticationProvider:

@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("system")) {
        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");
    }
}

SecurityConfig :

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .requestCache()
            .requestCache(new NullRequestCache())
            .and()
        .httpBasic()
            .and()
        .csrf().disable();
}

What I try to achieve is when the CustomAuthenticationProvider thrown an exception (e.g "bad credential" or "Full authentication required...", I want to customize the response and return to the Response Body in JSON format.

What I have done is to create a new exception and invoke it using AOP. But it seems like not working. I also tried to use @ControllerAdvice, but it seems like not working as well since the CustomAuthenticationProvider is outside the controller (I guess).

rjdkolb
  • 10,377
  • 11
  • 69
  • 89
lxnx
  • 194
  • 2
  • 17

2 Answers2

2

There is a better way for this. You should add authenticationEntryPoint in spring security config and class, which implements AuthenticationEntryPoint interface. Something like this:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/login").permitAll()
            .anyRequest().authenticated()
            .and()
        .requestCache()
            .requestCache(new NullRequestCache())
            .and()
        .httpBasic()
        // --> begin change: new lines added
            .and()
        .exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint())
        // <-- end change
            .and()
        .csrf().disable();

}

AuthExceptionEntryPoint class, for producing JSON Jackson ObjectMapper used:

public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, 
                         AuthenticationException authException) 
                         throws IOException, ServletException {

        List<String> errors = new ArrayList<>();
        errors.add("Unauthorized");
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.writeValue(response.getOutputStream(), errors);
        } catch (Exception e) {
            throw new ServletException();
        }
    }
}

More information about spring security config you can read on Spring docs

Javasick
  • 2,753
  • 1
  • 23
  • 35
  • 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:46
  • 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
  • I tried to print authException : org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource – lxnx May 10 '16 at 09:40
  • try to add `.antMatchers("/login").permitAll()` after `.authorizeRequests()` is security config (that must be URL where login mapped) – Javasick May 10 '16 at 09:42
  • I try to access /login after adding the .antMatchers and it works. - does it means that in only work for login form and not possible for httpBasic? – lxnx May 10 '16 at 09:48
  • I updated the comment. Chenge it to antMutchers. You disable all yours mapping for anuthorized users, so when you go to login - it is restricted. – Javasick May 10 '16 at 09:49
  • Sorry, can you explain further. I already tested it with ".antMatchers" and access the /login and it throw 404 instead of invalid credential. – lxnx May 10 '16 at 09:54
  • When yours config was `.authorizeRequests() .anyRequest().authenticated()` thar was meaning, that all requests for any page/mapping need already successfully authentification user, so, we need to allow access to `login` URL. `FormLogin` is for pages, if you use RESTful API you can allow it using ant matchers. I updated my post - try to use it – Javasick May 10 '16 at 10:53
0

You may be able to create a custom filter that can catch an AccessDeniedException and add the filter after ExceptionTranslationFilter in the configuration file in the following way:

http.addFilterAfter(customExceptionTranslationFilter, ExceptionTranslationFilter.class)

After catching the exception, you can use the response object to respond in the way you'd like.

You can then also add the ability to work with other exception you may want to throw in your Controllers.

Harsh Poddar
  • 2,394
  • 18
  • 17
  • it seems like when I added "addFilterAfter", the request will be permanently invalid. Even the login is correct. Any idea? – lxnx May 09 '16 at 10:22