Search code examples
javaspringrestspring-security

How to secure REST API with Spring Boot and Spring Security?


I know that securing REST API is widely commented topic but I'm not able to create a small prototype that meets my criteria (and I need to confirm that these criteria are realistic). There are so many options how to secure resources and how work with Spring security, I need to clarify if my needs are realistic.

My requirements

  • Token based authenticator - users will provide its credentials and get unique and time limited access token. I would like to manage token creation, checking validity, expiration in my own implementation.
  • Some REST resources will be public - no need to authenticate at all,
  • Some resources will be accessible only for users with administrator rights,
  • Other resource will be accessible after authorization for all users.
  • I don't want to use Basic authentication
  • Java code configuration (not XML)

Current status

My REST API works very well, but now I need to secure it. When I was looking for a solution I created a javax.servlet.Filter filter:

  @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

        String accessToken = request.getHeader(AUTHORIZATION_TOKEN);
        Account account = accountDao.find(accessToken);

        if (account == null) {    
            throw new UnauthorizedException();    
        }

        chain.doFilter(req, res);

    }

But this solution with javax.servlet.filters doesn't work as I need because there is an issue with exception handling via @ControllerAdvice with Spring servlet dispatcher.

What I need

I would like to know if these criteria are realistic and get any help, how to start securing REST API with Spring Security. I read many tutorials (e.g. Spring Data REST + Spring Security) but all work in very basic configuration - users with their credentials are stored in memory in configuration and I need to work with DBMS and create own authenticator.

Please give me some ideas how to start.


Solution

  • Token based authentication - users will provide its credentials and get unique and time limited access token. I would like to manage token creation, checking validity, expiration in my own implementation.

    Actually, use Filter for token Auth - best way in this case

    Eventually, you can create CRUD via Spring Data for managing Token's properties like to expire, etc.

    Here is my token filter: http://pastebin.com/13WWpLq2

    And Token Service Implementation

    http://pastebin.com/dUYM555E

    Some REST resources will be public - no need to authenticate at all

    It's not a problem, you can manage your resources via Spring security config like this: .antMatchers("/rest/blabla/**").permitAll()

    Some resources will be accessible only for users with administrator rights,

    Take a look at @Secured annotation to class. Example:

    @Controller
    @RequestMapping(value = "/adminservice")
    @Secured("ROLE_ADMIN")
    public class AdminServiceController {
    

    The other resource will be accessible after authorization for all users.

    Back to Spring Security configure, you can configure your url like this:

        http
                .authorizeRequests()
                .antMatchers("/openforall/**").permitAll()
                .antMatchers("/alsoopen/**").permitAll()
                .anyRequest().authenticated()
    

    I don't want to use Basic authentication

    Yep, via token filter, your users will be authenticated.

    Java code configuration (not XML)

    Back to the words above, look at @EnableWebSecurity. Your class will be:

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {}
    

    You have to override the configure method. Code below, just for example, how to configure matchers. It's from another project.

        @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/assets/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                    .usernameParameter("j_username")
                    .passwordParameter("j_password")
                    .loginPage("/login")
                    .defaultSuccessUrl("/", true)
                    .successHandler(customAuthenticationSuccessHandler)
                    .permitAll()
                .and()
                    .logout()
                    .logoutUrl("/logout")
                    .invalidateHttpSession(true)
                    .logoutSuccessUrl("/")
                    .deleteCookies("JSESSIONID")
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .and()
                    .csrf();
    }