unable to Spring Security working in existing application - spring

I am on day 3 of trying to get this to work and haven't had much luck.
Here's the use scenario (just summarizing using my own words here):
Within the existing application we need to integrate Spring security. User login configuration cannot change and we want to use standard annotations within spring (#Secured and #PreAuthorize) to be able to lock down access to RESTful endpoints. Internal objects can be wrapped but are not permitted to be altered.
I added all of the core dependencies in Maven for security:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.version}</version>
</dependency>
I took the custom User class that was in the system and created two wrappers for it to plug into the Spring Security Framework:
CustomAuthentication implementing org.springframework.security.core.Authentication
CustomUserDetails implementing org.springframework.security.core.userdetails.UserDetails
I then created a org.springframework.security.core.userdetails.UserDetailsService implementation that is annotated using #Service("userDetailService"). That completed the basic Java-side implementation for the Spring Security that I thought I needed in order to get things running.
I created a class com.myapp.rest.SecurityTestController that looks like this:
#Controller
#RequestMapping("/security-test")
public class SecurityTestController {
#RequestMapping("wide-open/{name}")
#ResponseBody
public String restWideOpen(#PathVariable String name, HttpSession session) {
return "Hello, " + name + ", from a wide-open RESTful service.";
}
#Secured("ROLE_XYZ")
#RequestMapping("require-auth/{name}")
#ResponseBody
public String restRequireAuthorization(#PathVariable String name, HttpSession session) {
return "Hello, " + name + ", from a RESTful service requiring authorization.";
}
}
I also updated the internal logging code to add (which was implemented as a #Conroller by the original developer):
Authentication customAuthentication = new CustomAuthentication(user);
SecurityContextHolder.getContext().setAuthentication(customAuthentication);
On logout I just simply added:
SecurityContextHolder.clearContext();
That all seems fine, compiles with not issues, etc. So I decided to move on to the configuration side of things in order to get the application working with security. Without any changes I was able to access both interfaces using the basic URL (in this case that happens to be localhost:8080/myapp/security-test/...).
So here's the configs:
web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>MyApp</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>myapp-web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myapp-web</servlet-name>
<url-pattern>/myapp/*</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>/myapp/**</url-pattern>
</filter-mapping>
</web-app>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:annotation-config />
<context:component-scan base-package="com.myapp" />
<context:property-placeholder location="/WEB-INF/servlet.properties" />
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="${maxProfileImageSize}"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="${datasource.url}"/>
<property name="username" value="${datasource.username}"/>
<property name="password" value="${datasource.password}"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="typeAliasesPackage" value="com.myapp.bean" />
</bean>
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="resourceLoaderPath" value="/WEB-INF/views/velocity/"/>
<property name="configLocation" value="/WEB-INF/velocity.properties"/>
</bean>
<bean id="properties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="/WEB-INF/servlet.properties"/>
</bean>
</beans>
applicationContext-security.xml
<beans ...>
<sec:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" />
<sec:http auto-config="true" use-expressions="true">
<sec:intercept-url pattern="/myapp/login" access="permitAll" />
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider user-service-ref="userDetailService" />
</sec:authentication-manager>
</beans>
And finally: myapp-web-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:component-scan base-package="com.myapp" />
<context:annotation-config />
<context:property-placeholder location="/WEB-INF/servlet.properties" />
<mvc:annotation-driven/>
<mvc:interceptors>
<bean id="sessionInterceptor" class="com.myapp.web.interceptor.SessionInterceptor" />
</mvc:interceptors>
<bean id="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<util:list>
<ref bean="jsonHttpMessageConverter" />
</util:list>
</property>
</bean>
<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useTrailingSlashMatch" value="true" />
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
Now comes the problem:
Everything reminds exactly the same. I can access the RESTful services without having the roles be validated. When I start Tomcat in debug my UserDetailsService implementation never actually gets invoked.
What am I missing? This is completely frustrating me as I've never had problems with Spring Security like this before.
UPDATE
I figured it out.
Of all things to miss, I needed to add this to myapp-web-servlet.xml:
<sec:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" />
Now I just need to figure out how to get it to appropriately load my roles between session restarts.

I think the problem might be with your mappings:
<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Related

No EntityManager with actual transaction available for current thread : Multiple config xml files

Hello I face the following problem:
I Have a spring mvc app with the following configuration files. there are two separate spring config files one for jpa and one for spring mvc The problem is when I try to persist something in Database I get the Error:
Message Request processing failed; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
(I have the #Transactional on the service class)
if I move the from jpaConfig.xml to servlet-config.xml the application works fine. I cannot find out why this happens and I find it wrong to move this tag to mvc config file. Can you help me to understand why this is happening?
Web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:jpaContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>fitTrackerServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/servlet-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>fitTrackerServlet</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>fitTrackerServlet</servlet-name>
<url-pattern>/pdfs/**</url-pattern>
</servlet-mapping>
servlet-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="com.example"/>
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="language"/>
</bean>
</mvc:interceptors>
<mvc:resources mapping="pdfs" location="/pdfs/**"/>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" >
<property name="order" value="1" />
<property name="contentNegotiationManager" >
<bean class="org.springframework.web.accept.ContentNegotiationManager">
<constructor-arg>
<bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy" >
<constructor-arg>
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
<bean class="org.springframework.web.servlet.view.xml.MarshallingView" >
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.example.domain.Activity</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="2" />
</bean>
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages"/>
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
and the jpaContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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"
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">
<bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.example.domain"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/fitness_tracker?autoReconnect=true"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryBean"/>
</bean>
<tx:annotation-driven/>
Dao:
#Repository
public class GoalRepositoryImpl implements GoalRepository {
#PersistenceContext
private EntityManager em;
#Override
#Transactional
public Goal save(Goal goal) {
em.persist(goal);
em.flush();
return goal;
}
}
Hello Finally I found the solution with the help of a colleague.
Spring can have multiple contexts at a time.
One of them will be the root context, and all the other contexts will be child contexts.
All child contexts can access the beans defined in root context, but not the opposite.
In my web.xml I have two configuratation xml files the servlet-config.xml and the jpaContext.xml
the first one is used by the DispacherServlet which creates a child application context.
the second is used by the ContextLoaderListener which creates the root application context.
I had the component-scan element in the child context so the beans were created inside the child context. When the
service bean was trying to begin a new transaction with the annotation the annotation-driven could not see the bean
(because it was from the child context) and thus I was getting the error.
by changing the component scan in servlet-config.xml to create only the controllers :
<context:component-scan base-package="com.example.controllers"/>
and addin a new component scan to the root context (jpaContext.xml)
<context:component-scan base-package="com.example"/>
the problem solved.

Differents application Context in Spring 4

I have a login service in my application implementing UserDetailsService:
#Service
#Transactional
public class LoginService implements UserDetailsService {
#Autowired
UserService userService;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Assert.notNull(username);
UserDetails result = userService.loadUserDetailsByUsername(username);
Assert.notNull(result);
// WARNING: The following sentences prevent lazy initialisation problems!
Assert.notNull(result.getAuthorities());
result.getAuthorities().size();
return result;
}
}
The app dies with the error Exception encountered during context initialization. The start of the trace is:
Error creating bean with name 'org.springframework.security.filterChains': Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#0' while setting bean property 'sourceList' with key [0] ...
The end is:
Cannot resolve reference to bean 'loginService' while setting bean property 'userDetailsService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'loginService' is defined
So it cannot find the loginService.
My web.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
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" version="2.5">
<display-name>SimpleSpringProject</display-name>
<description>All you need!</description>
<!-- Loads Spring Security config file -->
<!--
contextConfigLocation is the context parameter where we provide the spring security beans configuration file name.
It is used by ContextLoaderListener to configure authentication in our application
-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/spring-*.xml</param-value>
</context-param>
<!-- 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>
<!-- Creates the Spring Container shared by all Servlet and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Handles Spring requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/webmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
In the contextConfigLocation I am loading 3 files: spring-security.xml, spring-datasource.xml and spring-jpa.xml.
spring-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/user/**" access="hasRole('ROLE_ADMIN')" />
<security:intercept-url pattern="/role/**" access="hasRole('ROLE_ADMIN')" />
<security:form-login
login-processing-url="/login"
login-page="/loginForm"
default-target-url="/"
authentication-failure-url="/loginForm?error"
username-parameter="username"
password-parameter="password" />
<security:logout logout-url="/logout" logout-success-url="/" delete-cookies="JSESSIONID" />
<security:csrf />
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="loginService"></security:authentication-provider>
</security:authentication-manager>
</beans>
spring-jpa.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jpa:repositories base-package="com.ssp" />
</beans>
spring-datasource.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- Enable #Transactional annotation -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- MySQL Datasource with Commons DBCP connection pooling -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/simplesp" />
<property name="username" value="root" />
<property name="password" value="betis000" />
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<!-- EntityManagerFactory -->
<bean
id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="persistenceUnit" />
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Transaction Manager -->
<bean
id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</beans>
In the DispatcherServlet I am loading webmvc.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.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">
<!-- Enable annotation-based Spring MVC controllers (eg: #Controller annotation) -->
<mvc:annotation-driven />
<!-- Classpath scanning of #Component, #Service, etc annotated class -->
<context:component-scan base-package="com.ssp" />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<mvc:resources mapping="/resources/**" location="/WEB-INF/resources/" />
<!-- Register "global" interceptor beans to apply to all registered HandlerMappings -->
<mvc:interceptors>
<!-- Set the language in variable lang -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
p:paramName="lang" />
</mvc:interceptors>
<!-- Resolve view name into jsp file located on /WEB-INF -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- Tiles -->
<bean id="tilesViewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles3.TilesView" />
</bean>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles/tiles-definitions.xml</value>
</list>
</property>
</bean>
<!-- Resolves localized messages*.properties and application.properties
files in the application to allow for internationalization. The messages*.properties
files translate messages which are part of the admin interface, the application.properties
resource bundle localizes all application specific messages such as entity
names and menu items. -->
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="i18n/messages,i18n/application" />
<!-- Store preferred language configuration in a cookie -->
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
p:cookieName="locale" p:defaultLocale="en" />
</beans>
I am thinking that I have a problem with applicationContext because if I remove the #Service annotation and define the bean LoginService in the spring-security.xml:
<bean id="loginService" class="com.ssp.service.LoginService" />
then the applications starts and when I submit a login its UserService is null, so it seems that the context of LoginService is different to the context of the beans with:
<context:component-scan base-package="com.ssp" />
If anyone wants to see the full code of the app is in https://github.com/pedrogonzalezgutierrez/simplespringproject
I think you will need wrap your loginService with userDetailsServiceWrapper, try this:
<bean id="loginService" class="path.to.LoginService" />
<bean id="preAuthenticationProvider" 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="loginService" />
</bean>
</property>
</bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="preAuthenticationProvider" />
</authentication-manager>
After research more and more I am sure that it was a problem with the application context. It seems that I had two differents context in my app. One of them was loaded by the contextConfigLocation and another one by the DispatcherServlet.
Just leave the param-value of the DispatcherServlet empty and load all the configurations by contextConfigLocation.
Also I updated the beans definitions to the version 3.2 except for Spring Security that requires 4.0

Securing REST API using Spring-security #PreAuthorize annotation and OAuth2

I'm struggling with some spring-security OAuth2 configuration.
I'm using:
Spring.version: 4.0.5.RELEASE
Spring security version: 3.2.5.RELEASE
Spring security oauth version: 2.0.2.RELEASE
Jersey version: 1.18.1
I want to secure my REST API using the PreAuthorize annotation of Spring security where I define the role that is authorized to access the method:
#Transactional
#POST
#PreAuthorize("hasRole('ROLE_ADMIN')")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response create(User user) throws BusinessException {
LOG.info("POST Request: Creation of a new user with username [{}]", user.getUsername());
UserValidator.validateUser(user);
User createdUser = userDao.create(user);
return Response.ok(createdUser).build();
}
When I call the API method with a valid bearer token for a user with role "ROLE_ADMIN", I get following exception:
09-Sep-2014 16:13:40.977 SEVERE [http-nio-8080-exec-6] com.sun.jersey.spi.container.ContainerResponse.mapMappableContainerException The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70)
at org.springframework.security.access.vote.UnanimousBased.decide(UnanimousBased.java:107)
at ...
When using postman, I see the following error description:
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
This is my security config:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
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://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd">
<context:property-placeholder location="classpath:main.properties"/>
<sec:global-method-security pre-post-annotations="enabled" />
<oauth:expression-handler id="oauthExpressionHandler" />
<!-- Definition of the Authentication Service -->
<sec:http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager">
<sec:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<sec:anonymous enabled="false"/>
<sec:http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<!-- include this only if you need to authenticate clients via request parameters -->
<sec:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<sec:access-denied-handler ref="oauthAccessDeniedHandler"/>
</sec:http>
<!-- Protected resources -->
<sec:http auto-config="true"
entry-point-ref="oauthAuthenticationEntryPoint"/>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest" />
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="dstest/client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</constructor-arg>
</bean>
<!-- Authentication in config file -->
<sec:authentication-manager id="clientAuthenticationManager">
<sec:authentication-provider user-service-ref="clientDetailsUserService"/>
</sec:authentication-manager>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider>
<sec:jdbc-user-service data-source-ref="securityDataSource"/>
</sec:authentication-provider>
</sec:authentication-manager>
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<!-- Token Store -->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
<constructor-arg ref="securityDataSource" />
</bean>
<bean id="oAuth2RequestFactory" class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
<constructor-arg ref="clientDetails"/>
</bean>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore"/>
<property name="supportRefreshToken" value="true"/>
<property name="clientDetailsService" ref="clientDetails"/>
<!-- VIV -->
<property name="accessTokenValiditySeconds" value="10"/>
</bean>
<bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
<property name="tokenStore" ref="tokenStore"/>
<property name="requestFactory" ref="oAuth2RequestFactory"/>
</bean>
<!-- Token management -->
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler" token-endpoint-url="/oauth/token">
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="dstest"
token-services-ref="tokenServices"/>
<!-- Client Definition -->
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="healthdata-client"
authorized-grant-types="password,authorization_code,refresh_token,implicit,redirect"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"
redirect-uri="/web"
scope="read,write,trust"
access-token-validity="300"
refresh-token-validity="6000"/>
</oauth:client-details-service>
</beans>
And this is my web.xml configuration:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<display-name>Spring MVC Application BASIC AUTH</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
/WEB-INF/rest-dispatcher-servlet.xml
/WEB-INF/security.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<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>
<servlet>
<servlet-name>rest-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest-dispatcher</servlet-name>
<url-pattern>/oauth/token</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Spring servlets</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>be.spring.security.api</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>be.spring;org.codehaus.jackson.jaxrs</param-value>
</init-param>
<!-- optional: JSON support apart from jaxb -->
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring servlets</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
I found the solution to my problem. Web security services are configured using the element and I had to alter my protected resource definition from:
<sec:http auto-config="true"
entry-point-ref="oauthAuthenticationEntryPoint"/>
to:
<sec:http auto-config="true">
<sec:custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER"/>
<sec:access-denied-handler
ref="oauthAccessDeniedHandler"/>
</sec:http>
The resourceServerFilter must be referenced in order to be picked up by the security mechanism and the before attribute had to be set to "PRE_AUTH_FILTER".
Also the access-denied-handler is needed if you want proper error handling in a JSON format in the case you can't access the service.

spring mvc: resources path outside the context root

I have seen the other solution on stackoverflow but it does not help. I am doing the same thing but I don't know why its not working for me.
I am uploading the images in /home/images folder on ubuntu machine and in spring-servlet.xml I have written the following lines
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:resources mapping="/images/**" location="file:/home/images/"/>
<mvc:default-servlet-handler/>
Images are getting uploaded at /home/images/ folder but I am not able to access these images
In JSP I have written
<img src="/images/image.jpg"/>
but its not showing this image I don't understand the problem here. Please let me know if anything else is required.
---Update ---
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
<context:annotation-config />
<context:component-scan
base-package="com.mycom.myproject" />
<!-- Enable annotation driven controllers, validation etc... -->
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:resources mapping="/images/**" location="file:/home/images/"/>
<mvc:default-servlet-handler/>
<!-- Declare a datasource that has pooling capabilities -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" p:driverClass="com.mysql.jdbc.Driver"
p:jdbcUrl="jdbc:mysql://localhost/dbtest" p:user="root" p:password="root"
p:acquireIncrement="10" p:idleConnectionTestPeriod="60" p:maxPoolSize="100"
p:maxStatements="50" p:minPoolSize="10" />
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="datasource" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource" />
</bean>
<!-- scan for mappers and will automatically scan the whole classpath for xmls -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="basePackage" value="com.mycom.myproject.db.mybatis.dao" />
</bean>
<!-- Configure the multipart resolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="100000"/>
</bean>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"
p:extractValueFromSingleKeyModel="true" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:project-config" />
</bean>
Web.xml
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-servlet.xml,
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<!-- 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>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
oooook, your dispatcher servlet is mapped to .htm, so you're dispatcher servlet is never gonna be invoked, since it handles those /resources/* requests and calls a ResourceHttpRequestHandler to write the static content.

Spring 3 MVC and Tiles 2 - can't display static resources when controller #RequestMapping has URI template

I am using Tiles 2, Spring 3 MVC, Tomcat ver.7 and Eclipse (Springsource Tool Suite). I hope somebody can help.
The css and pictures are not rendered by the tile view that is returned by the controller handler method "displayPropertyPage" whose #RequestMapping has a URI template ( #RequestMapping(value = "/getproperty/{propertyID}", method = RequestMethod.GET) ).
I am using the mvc:resources and mvc:default-servlet-handler tags so the default servlet serves requests for static resources. I also checked the html script generated by this tile view and it does have the css entry.
The other views returned by controller handler methods with a simple path such as ( #RequestMapping(value = "/propertylistings", method = RequestMethod.GET) ) display all static resources including
css, pictures and jquery just fine.
I noticed that the 'properties info' of the blank picture on the browser has a URL of http://localhost:8080/realtyguide/getproperty/resources/images-homes/pic1.jpg when it should be
just http://localhost:8080/realtyguide/resources/images-homes/pic1.jpg. The URL is picking up the path "/getproperty" from the handler's RequestMapping annotation.
The pictures are under the folder 'images-homes'.
My directory structure is:
src
main
webapp
resources
images-homes
css
WEB-INF
Here is my controller. The view returned is a tile definition.
#Controller
public class PropertyPageController {
private MasterTableService masterTableService;
#Autowired
public PropertyPageController(MasterTableService masterTableService) {
this.masterTableService = masterTableService;
}
#RequestMapping(value = "/getproperty/{propertyID}", method = RequestMethod.GET)
public String displayPropertyPage(#PathVariable("propertyID") String propertyID, Model model) {
model.addAttribute("mastertable", masterTableService.findByID(propertyID));
return "propertyinfo.tiledef";
}
}
Here is my Spring application servlet configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:lang="http://www.springframework.org/schema/lang"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<context:annotation-config />
<!-- Scans within the base package of the application for #Components to configure as beans -->
<context:component-scan base-package="com.springproject.realtyguide" />
<!-- Enables the Spring MVC #Controller programming model -->
<mvc:annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources -->
<mvc:resources mapping="/resources/**" location="/resources/"/>
<!-- Allows for mapping the DispatcherServlet to "/" by forwarding static resource requests to the container's default Servlet -->
<mvc:default-servlet-handler/>
<!-- Bean to provide Internationalization -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="WEB-INF/i18n/messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:META-INF/spring/database.properties" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}"
p:password="${jdbc.password}" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:META-INF/hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- __________ BEAN ENTRIES FOR TILES 2 -->
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/layouts/tiles.xml</value>
</list>
</property>
</bean>
<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver" >
<property name="order" value="0"/>
<property name="viewClass">
<value>org.springframework.web.servlet.view.tiles2.TilesView </value>
</property>
<property name="requestContextAttribute" value="requestContext"/>
<property name="viewNames" value="*.tiledef"/>
</bean>
<bean id="jstlViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="1"/>
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- __________ END OF BEAN ENTRIES FOR TILES 2 -->
<!-- Resolves localized <theme_name>.properties files in the classpath to allow for theme support -->
<bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource">
<property name="basenamePrefix" value="theme-" />
</bean>
<bean id="themeResolver" class="org.springframework.web.servlet.theme.CookieThemeResolver">
<property name="defaultThemeName" value="standard" />
</bean>
</beans>
Here is my 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"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>Realty Guide</display-name>
<!-- 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</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Handles Spring requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
I have been googling this for several days and can't find a solution.
Thanks for any help you can give.
It's the way you are referring to your resources in your views. If you refer to a resource in your view as:
resources/images-homes/pic1.jpg
it will be appended to the current controller URL. If you use:
/resources/images-homes/pic1.jpg
then it will refer to the web server root and not include your application context, assuming it is not running as root.
You need to change your resource links. I assume you are using JSP to render views. If that is the case then use c:url from the core JSTL library to provide the correct reference to your resource:
before
<img src="resources/images-homes/pic1.jpg"/>
after
<img src="<c:url value='/resources/images-homes/pic1.jpg'/>"/>

Resources