1
votes

Environment :

Spring 4.1

Spring security 4.0

Issue :

I am developing a simple REST service using Spring 4.1. And using Spring security for authentication purpose. I am using HTTP Basic Authentication.

The issue is , basic authentication is not working even after all configuration is correct. I am using postman to send a request to server. REST client can call the REST controller method without Authorization header. The method gets executed successfully without any authentication error.

Since I am using Tomcat 6 , I am not using servlet 3.0 features , so web.xml does exist. The method level security has been implemented using @Secured annotation on REST controller layer.

Can anybody please help as to where I am going wrong ?

Code :

web.xml :

<web-app>
    <display-name>Archetype Created Web Application</display-name>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener> 

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/mvc-dispatcher-servlet-security.xml</param-value>
    </context-param>

    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
        </init-param>       
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <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>/*</url-pattern>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>REQUEST</dispatcher>      
    </filter-mapping>

</web-app>

mvc-servlet-dispatcher-security.xml :

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

    <http use-expressions="true" create-session="stateless">
        <http-basic/>
       <csrf disabled="true"/> 
    </http>

    <global-method-security secured-annotations="enabled"/>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="XYZ" password="12345" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>

</beans:beans>

mvc-dispatcher-servlet.xml :

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- Specifying base package of the Components like Controller, Service, DAO -->
    <context:component-scan base-package="org.ngo" />
    <!-- Getting Database properties -->
    <context:property-placeholder location="classpath:application.properties"/>

    <mvc:annotation-driven/>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>              
            </props>
        </property>
        <property name="packagesToScan" value="org.ngo.abhishek.entity"></property>
    </bean>

    <!-- Transaction -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

The REST controller :

@RestController
@RequestMapping("/abhishek")
public class AbhishekController {

    @Autowired
    private AbhisheskService abhishekService;

    @RequestMapping(method=RequestMethod.POST,consumes="application/json")
    @Secured("ROLE_USER")
    public ResponseEntity<Boolean> getUserById(@RequestBody List<AbhishekDTO> abhishekDtoList) {

        boolean flag = this.abhishekService.createAbhishek(abhishekDtoList);    
        return new ResponseEntity<Boolean>(flag, HttpStatus.OK);     
    }

}
2

2 Answers

1
votes

I tried your setup and it worked for me. Since you did not provide all of your code, my best guess is either the component scan of your controller for Spring Security is not happening or maybe your browser is caching and sending the Basic Auth credentials without you realizing it.

1
votes

After getting a clue from Stiletto , I removed @Secured("ROLE_USER") and used expression based security check. It worked (using intercept url). So the issue was with where @Secured has been placed.

Since @Secured was in dispatcher servlet context (child context as per Spring philosophy) and spring security scope was in applicationContext (parent context) , the spring security was getting ignored.

Putting <security:global-method-security secured-annotations="enabled"/> in mvc-dispatcher-servlet.xml resolved the issue.

Similar question on SO : Spring MVC, Method level security