0

I'm trying to add security in my Spring MVC (4.2.5 version) web application. Actually I have developed the login using external API to match username and password typed in my web page form with the correct ones, and it works correctly.

Now I want to add Spring Security (4.1.3 version) in order to grant full access to the site only to authorized users. Anonymous users, instead, should only access the index page (the one with login form).

Unfortunately when I add the springSecurityFilterChain I get a 404 error on every uri, even on localhost:8080/BetEx/ so neither the welcome-file in my web.xml works (without springSecurityFilterChain it works correctly).

Project structure

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>BetEx</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

    <!-- Spring MVC -->
    <servlet>
        <servlet-name>betex-controller</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>betex-controller</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- Spring Security Configuration File -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
         org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      </param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-security.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Spring Security -->
    <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>
    </filter-mapping>
</web-app>

spring-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.2.xsd">

   <http use-expressions="true">
      <intercept-url pattern="/index*" access="isAnonymous()" />
      <intercept-url pattern="/**" access="isAuthenticated()"/>

      <form-login
         login-page='/index.html'
         default-target-url="/home.html"
         authentication-failure-url="/index.html?error=true" />

      <logout logout-success-url="/index.html" />

   </http>
    <authentication-manager>
        <authentication-provider user-service-ref="customUserDetailsService" >
            <password-encoder hash="bcrypt" />
        </authentication-provider>
    </authentication-manager>
</beans:beans>

betex-controller-servlet.xml

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

    <context:component-scan base-package="controller" />

    <mvc:annotation-driven/>

    <mvc:resources mapping="/resources/**" location="/resources/"/>

    <bean id="templateResolver"
        class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
        <property name="prefix" value="/WEB-INF/html/" />
        <property name="suffix" value=".html" />
        <property name="templateMode" value="HTML5" />
    </bean>

    <bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
        <property name="templateResolver" ref="templateResolver" />
    </bean>

    <bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
        <property name="templateEngine" ref="templateEngine" />
        <property name="order" value="1" />
    </bean>

</beans>

LoginController

@Controller
public class LoginController {

    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public ModelAndView showLoginForm() {
        Customer user = new Customer();
        return new ModelAndView("index", "user", user);
    }

    @RequestMapping(value = "/index", method = RequestMethod.POST)
    public ModelAndView doLogin(@ModelAttribute("user") @Valid Customer user, BindingResult bindingResult) {

        if(bindingResult.hasErrors()) {
            return new ModelAndView("index");
        }

        else {

            /* Send http request and read http response */
            /* Set username and password to user object */

            /* Auth security service */
            UserAuthenticationService userAuthService = new UserAuthenticationService();
            userAuthService.addUserInfo(user);

            return new ModelAndView("users/home", "user", user);
        }
    }

    @RequestMapping(value = "/logout")
    public ModelAndView doLogout() {

        this.request = new HttpPostRequest();
        request.sendRequest(LOGOUT_END_POINT, APP_KEY, new JsonRequest(), token);

        return new ModelAndView("redirect:index");
    }
}

I want that:

  • Every user should see index.html
  • Only authorized users should see the other pages (inside users folder)

I don't know if it's useful but I'm using Thymeleaf for templating.

Server starts but the following exception is launched:

GRAVE: Exception starting filter springSecurityFilterChain
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1175)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1060)
    at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:326)
    at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:235)
    at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:199)
    at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279)
    at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:260)
    at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:105)
    at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4828)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5508)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1575)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1565)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

How can I fix? Thanks in advance.

andy
  • 269
  • 1
  • 12
  • 22
  • It seems like your ThymeleafViewResolver cannot find the index.html template. Can you post the code where you are setting up your ThymealfViewResolver? – Mechkov Oct 10 '16 at 15:44
  • is your index.html under /WEB-INF/html/ ? – Mechkov Oct 10 '16 at 15:48
  • exactly, but before adding Spring Security it worked, and it still works deleting the filter-mapping from web.xml (the pages are correctly shown, but obviously security doesn't work). I've edited my answer with the missing xml – andy Oct 10 '16 at 15:48
  • yes, I have an index.html inside BetEx/WebContent and the other (the ones shown when thymeleaf resolve the view) inside BetEx/WebContent/WEB-INF/html – andy Oct 10 '16 at 15:50
  • How are you requesting your app? localhost/myApp/index? You have another index.html under WebContent, so it should not even go through the SecurityFilter. If it did you would have gotten a 401...Unauthorized – Mechkov Oct 10 '16 at 15:59
  • both localhost:8080/BetEx/ or localhost:8080/BetEx/index gives 404 error – andy Oct 10 '16 at 16:10
  • What happens if you remove this line from your Security config? – Mechkov Oct 10 '16 at 16:15
  • I'm sorry, I just realized that the server start, but an exception is thrown. I edited the question – andy Oct 10 '16 at 16:37
  • Did you include Spring Security dependencies in the project? org.springframework.security spring-security-web 4.1.3.RELEASE – Mechkov Oct 10 '16 at 17:59
  • Yes, I have spring-security-config, spring-security-web and spring-security-core in my pom.xml – andy Oct 10 '16 at 18:32

2 Answers2

0

I dont seem to notice how you are loading your other beans from the application context? Try to include both contexts in the same config. Like this:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/betex-controller-servlet.xml,
                 /WEB-INF/spring-security.xml</param-value>
</context-param>

<!-- Processes application requests -->
<servlet>
    <servlet-name>betex-controller</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value></param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

EDIT

Instead of this:

<context-param>
    <param-name>contextClass</param-name>
    <param-value>
     org.springframework.web.context.support.AnnotationConfigWebApplicationContext
  </param-value>
</context-param>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring-security.xml</param-value>
</context-param>

try this:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring-security.xml</param-value>
</context-param>

<!-- Processes application requests -->
<servlet>
    <servlet-name>betex-controller</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value></param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
Mechkov
  • 4,294
  • 1
  • 17
  • 25
  • sorry but I can't understand what to do: have to create a new .xml? – andy Oct 10 '16 at 19:54
  • Edited my post. Try it. What i did is specifically set the contextConfig for your dispatcherServlet to use. Make sure you remove your "DispatcherServlet" portion from the web.xml to test with the code i provided. – Mechkov Oct 10 '16 at 20:02
  • I tried to remove the code in servlet tag from my web.xml, replacing with yours but it doen't work and many exception were launched. I misundertood what I have to do? – andy Oct 10 '16 at 23:09
  • What are the exceptions you are seeing? Did you remove your code and replace with mine? Also do you have a Java configuration file for the Spring context? – Mechkov Oct 11 '16 at 12:54
  • No I haven't Java configuration file, only the posted xml. That's my web.xml after your suggestions, and the corresponding exceptions [link](http://pastebin.com/mgjjEUf1) . Removing the ContextLoaderListener, instead, server starts without any error, but when I try to open localhost:8080/BetEx/ I get the "No bean named 'springSecurityFilterChain' is defined" exception. Finally, last night, trying to solve that problem I come this far [link](http://stackoverflow.com/questions/39968752/http-status-500-filter-execution-threw-an-exception-dofilter-and-invokedeleg) – andy Oct 11 '16 at 13:38
0

I again checked the configuration files and read the documentation of Spring Security. There was nothing wrong with my settings. In the end I simply solved downgrading from 4.1.3 to 4.0.3 version.

Now the pages are visible, no exceptions is thrown and all is work fine..

andy
  • 269
  • 1
  • 12
  • 22