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

107,547

Solution 1

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();
}

Solution 2

Spring security also very useful for providing authentication and authorization to the REST URLs. We no need to specify any custom implementations.

First, you need to specify the entry-point-ref to restAuthenticationEntryPoint in your security configuration as below.

 <security:http pattern="/api/**" entry-point-ref="restAuthenticationEntryPoint" use-expressions="true" auto-config="true" create-session="stateless" >

    <security:intercept-url pattern="/api/userList" access="hasRole('ROLE_USER')"/>
    <security:intercept-url pattern="/api/managerList" access="hasRole('ROLE_ADMIN')"/>
    <security:custom-filter ref="preAuthFilter" position="PRE_AUTH_FILTER"/>
</security:http>

Implementation for the restAuthenticationEntryPoint might be as below.

 @Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

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

After this you need to specify RequestHeaderAuthenticationFilter. It contains the RequestHeader key. This is basically used for identifying the user`s authentication. Generally RequestHeader carries this information while making the REST calls. For example consider below code

   <bean id="preAuthFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <property name="principalRequestHeader" value="Authorization"/>
    <property name="authenticationManager" ref="authenticationManager" />
  </bean>

Here,

<property name="principalRequestHeader" value="Authorization"/>

"Authorization" is the the key presented the incoming request. It holds the required user`s authentication information. Also you need to configure the PreAuthenticatedAuthenticationProvider to fulfill our requirement.

   <bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
  <bean id="userDetailsServiceWrapper"
      class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
    <property name="userDetailsService" ref="authenticationService"/>
  </bean>
</property>
</bean>

This code will work for securing the REST urls by means of Authentication and authorization without any custom implementations.

For Complete code please find the below link:

https://github.com/srinivas1918/spring-rest-security

Share:
107,547

Related videos on Youtube

Artegon
Author by

Artegon

Updated on December 21, 2020

Comments

  • Artegon
    Artegon over 3 years

    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.

  • Felipe A.
    Felipe A. over 6 years
    can you help me in my question please? stackoverflow.com/questions/46065063/…
  • AlikElzin-kilaka
    AlikElzin-kilaka about 6 years
    Any example project that includes all the requirements?
  • Mr.DevEng
    Mr.DevEng about 6 years
    Video is usefull.How to do the same advanced authentication for ReST API. Here only describing about Web. Is there any video tutorial for advanced authentication in REST API.
  • Jeet Singh Parmar
    Jeet Singh Parmar about 6 years
    If you saw the 2nd video(Advanced Authentication), then in that I am doing the same authentication using REST client(for REST API) as well.
  • Oliver
    Oliver about 5 years
    @Oleksandr: Thats a long shot, but can you tell me why you have started a thread in RESTAuthenticationTokenProcessingFilter class's updateLastLogin(...) method?
  • Oleksandr Loushkin
    Oleksandr Loushkin about 5 years
    @z3d4s, actually it's an old example (4 years), for now i will suggest to use OffsetDateTime, another approaches, etc :) new thread i proposed to use to decrease processing time for user requests, because it can take additional time during saving into the database.
  • Oliver
    Oliver about 5 years
    Ahhh I see, thats a genius solution! Thanks!