Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building a Spring security interceptor for a rest service

I have a basic REST service exposing various APIs based on Spring MVC and the @RestController mechanism. Now I am trying to add an interceptor for Spring security in order to require login (through a particular REST request) before any other request can be accessed. The idea is that the interceptor checks the active session of the request, and points it to the login service if an active login is not found. If an active login is found the interceptor lets the request through to the proper URL. I've been playing around with the XML files but all I keep getting is redirection loops. :( It's worthwhile noting that I do not have a view associated with this server at all. Access is done via http requests from a GUI that I don't have access to.

Here's my configuration thus far: Web.xml:

    <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/root-context.xml, /WEB-INF/spring/application-security.xml</param-value>
    </context-param>

    <filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/aisrv/*</url-pattern>
</filter-mapping>

    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Processes application requests -->
    <servlet>
        <servlet-name>aisrvServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/aisrvServlet/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>aisrvServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

Servlet-Context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <context:component-scan base-package="com.bmc.ai.server" />
    <!--- Specific beans for my server -->
</beans:beans>

application-security.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <http pattern="/resources/**" security="none" />

    <http auto-config="true" use-expressions="true">
   <!--       <intercept-url pattern="/login" access="ROLE_ADMIN" /> -->

  <!--       <intercept-url pattern="/logout" access="permitAll" />
        <intercept-url pattern="/accessdenied" access="permitAll" /> -->

        <intercept-url pattern="/**" access="ROLE_USER" requires-channel="https"/>
<!--          <http-basic /> -->
         <form-login default-target-url="/test"  /> 
   <!--     <logout logout-success-url="/logout" />  -->
    </http>

    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <user-service>
                <user name="user" password="123" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

</beans:beans>

I'm sure this is something pretty basic and easy to fix, but I can't seem to find my hand and legs in it. Any help would be greatly appreciated.

============EDIT======================= Following the example from Varun I've modified my application-security.xml like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <http pattern="/resources/**" security="none" />

     <http auto-config="true" use-expressions="true">
  <!-- other filters -->
  <custom-filter ref="myCustomFilter" before="SESSION_MANAGEMENT_FILTER" />  
    <intercept-url pattern="/**" access="ROLE_USER" requires-channel="https"/>
</http>


<beans:bean id="myCustomFilter" class="com.company.server.impl.security.RestFilter">

</beans:bean>


<!--     <http auto-config="true" use-expressions="true">
         <intercept-url pattern="/login" access="ROLE_ADMIN" />

        <intercept-url pattern="/logout" access="permitAll" />
        <intercept-url pattern="/accessdenied" access="permitAll" />

        <intercept-url pattern="/**" access="ROLE_USER" requires-channel="https"/>
         <http-basic />
         <form-login default-target-url="/test"  /> 
       <logout logout-success-url="/logout" /> 
    </http>-->

    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <user-service>
                <user name="user" password="123" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

</beans:beans>

and added the following RestFiletClass:

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.filter.GenericFilterBean;

import com.company.server.controller.ExcpetionHandling.GenericErrorExeception;
import com.company.server.interfaces.comm.ICorbaClient;

public class RestFilter extends GenericFilterBean {

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

         HttpServletResponse response = ((HttpServletResponse) res);
            HttpServletRequest request = ((HttpServletRequest) req);
            ICorbaClient corba = (ICorbaClient)request.getSession().getAttribute("corba");
            if(corba.getSuccessfulLogin()){
                System.out.println("Authorized through filter");
                chain.doFilter(req, res);
            }else{
                throw new GenericErrorExeception("User unauthorized", null, HttpServletResponse.SC_UNAUTHORIZED);
            }
    }

}

However, spring appears to skip the filter altogether. Do I need to add it somewhere or do something more with it?

like image 981
bharel Avatar asked Oct 21 '22 04:10

bharel


1 Answers

You need to add a custom filter in your spring security xml. In the example below a pre-built filter has been modified, but you can checkout the classes as reference to build your own filter.

<http use-expressions="true">
  <!-- other filters -->
  <custom-filter ref="myCustomFilter" before="SESSION_MANAGEMENT_FILTER" />  
</http>


<beans:bean id="myCustomFilter" class="com.mycompany.RestFilter">

</beans:bean>

public class RestFilter extends GenericFilterBean {

   // @Override of Filter.doFilter() method
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
      // Implement
   }
}

Spring security will automatically call this filter before the predefined SESSION_MANAGEMENT_FILTER and run your code.

like image 128
Varun Achar Avatar answered Oct 22 '22 19:10

Varun Achar