#Secured annotations work but #PostAuthorize with PermissionEvaluator doesn't - spring

The following problem has been driving me insane:
I have the following setup:
interface StudyService
#Service StudyServiceImpl implements StudyService
#Controller StudyServiceController implements StudyService
SampleDAOImpl implements SampleDAO
A permissionEvaluator CdmPermissionEvaluator
I have the following code:
class SampleDAOImpl implements SampleDAO {
...
#Secured(Roles.USER)
#PostAuthorize("hasPermission(returnObject, 'read')")
Sample load(long sampleId) {
...
}
...
}
The #Secured works, as I have to log in when that is present. However, the #PostAutorize doesn't work, even when I comment out the #Secured. I have a logging statement in CdmPermissionEvaluator.hasPermission(), and it never gets logged. This is also the case when I comment out the #Secured annotation (to avoid that the #PostAuthorize doesn't get evaluated because of the default AffirmativeBased voter).
Relevant parts of web.xml:
...
<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>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>*.rpc</url-pattern>
</servlet-mapping>
...
Relevant parts of spring-servlet.xml:
...
<security:global-method-security secured-annotations="enabled"/>
<context:annotation-config/>
<!-- Auto-detect controllers; these extend RemoteServiceServlet and are -->
<!-- annotated with #Controller -->
<context:component-scan base-package="org.gmeb.crf.server">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
...
Relevant parts of applicationContext.xml:
<context:annotation-config/>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<context:component-scan base-package="org.gmeb.crf">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
Relevant parts of applicationContext-security.xml:
<http auto-config="true" entry-point-ref="authenticationEntryPoint"
create-session="always" use-expressions="true">
<intercept-url pattern="/**" access="permitAll()"/>
<form-login authentication-success-handler-ref="authenticationSuccessHandler"
authentication-failure-handler-ref="authenticationFailureHandler"/>
<logout success-handler-ref="logoutSuccessHandler"/>
<anonymous/>
</http>
...
<global-method-security pre-post-annotations="enabled"> <!-- TODO: Add proxy-target-class="true" -->
<expression-handler ref="expressionHandler"/>
</global-method-security>
<beans:bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<beans:property name="permissionEvaluator" ref="cdmPermissionEvaluator"/>
</beans:bean>
<beans:bean id="loggerListener"
class="org.springframework.security.authentication.event.LoggerListener"/>
<context:annotation-config/>
<beans:bean id="cdmPermissionEvaluator" class="org.gmeb.crf.server.auth.CdmPermissionEvaluator">
</beans:bean>
Any idea what I'm doing wrong here?
Before I had this setup I had #PostAuthorize annotations with Spring EL expressions (no permissionEvaluator) in #Service StudyServiceImpl, and that worked. So what am I doing wrong, and what's the difference with the previous setup?
Thanks in advance,
Arnaud

This won't work because you can't mix different annotation types on a single method without getting odd results. It's therefore recommended that you stick to a single "security metadata" option for each class or interface you want to secure.
In more detail, multiple different metadata sources (secured annotations, pre-post annotations, pointcut definitions, JSR-250 annotations) may be used in an application. They are all typically handled by a DelegatingMethodSecurityMetadataSource instance which will only query its delegates until it gets a concrete answer from one of them. So if you have #Secured and #PreAuthorize defined for a method, only one will be used.
You should only have one <global-method-security> element defined in your app. You only need to place it in the -servlet.xml context file if you are applying method security to web controllers or other beans defined in there.

Related

Spring Security does not display login page

I'm trying to securize my application (Spring 4.3.10 + Hibernate 5.2.10) using Spring Security (4.2.3).
I configure spring security with the Digest authentification method the following way :
spring-security.xml :
<security:http create-session="stateless" use-expressions="true" >
<security:intercept-url pattern="/**" access="isAuthenticated()"/>
<security:intercept-url pattern="/login*" access="isAnonymous()" />
<security:http-basic/>
<security:form-login login-page="/login" authentication-failure-url="/login"/>
<security:custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER"/>
</security:http>
<bean id="digestEntryPoint" class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
<property name="realmName" value="my_realm"/>
<property name="key" value="my_key"/>
</bean>
<bean id="digestFilter" class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
<property name="userDetailsService" ref="jdbcDaoImpl"/>
<property name="authenticationEntryPoint" ref="digestEntryPoint"/>
</bean>
<bean id="jdbcDaoImpl" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
I added the DelegatingFilterProxy in the web.xml :
<filter>
<filter-name>digestFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>digestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I created a basic controller to show the login page (did not managed to use the default one) :
#Controller
#RequestMapping("/login")
public class LoginController {
#GetMapping
public String login() {
return "login";
}
}
I have also a login.jsp in the WEB-INF that contains the form, and the default mysql schema for the users and authorities tables as describe in the reference documentation.
My problem is that Spring Security never display the login page. I put a breakpoint into the doFilter method of the DigestAuthentificationFilter, and it seems that the header "Authorization" is null and spring just continue the filter chain without doing anything. It seems that the filter is expecting a Digest header...
My question is then, who put this Authorization header ? And why spring do not ask for authentifaction is the header is null ?
I think there is something that I don't understand...
Thanks for your help !
I solved my problem. I specified digestFilter as the filter-name for the DelegatingFilerProxy because I thought I had to bind it to the custoim filter I declared in the spring-security.xml. But Spring actually use a filters chain and add many more filters to it behind the scene. Thus, it did not use the filters chain created by spring but only the digest filter that cannot work alone.
I modified the web.xml as follow :
<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>

Facing issues while implementing Spring Security with http-basic authentication for spring rest API

Hi i am new to spring security and trying to implement it in my project.
I am trying to use UserDetailsService of spring security to achieve the security.
well i have configured every thing from web.xml to spring-security.xml
i am facing an compilation issue while autowiring the DAO class in the class that implements UserDetailsService. If i do not autowire then the code is compiling successfully and when i am testing the code from postman i am getting an error as follow's
12:13:45.738 [http-nio-8080-exec-3] DEBUG o.s.s.a.DefaultAuthenticationEventPublisher - No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException
12:13:45.738 [http-nio-8080-exec-3] DEBUG o.s.s.w.a.w.BasicAuthenticationFilter - Authentication request for failed: org.springframework.security.authentication.InternalAuthenticationServiceException
and below is my web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
classpath:spring-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>/*</url-pattern>
</filter-mapping>
and my spring-security.xml files contains
<?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"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:annotation-config/>
<bean id="authenticationEntryPoint" class="user.app.security.DemoAppEntryPoint">
<constructor-arg name="loginFormUrl" value="/auth/login"/>
</bean>
<security:http use-expressions="true" create-session="stateless" entry-point-ref="authenticationEntryPoint" >
<security:intercept-url pattern="/auth/login" access="hasAnyRole('UserAppAdmin','HR','manager')" />
<security:intercept-url pattern='/user/**' access="hasAnyRole('UserAppAdmin','HR','manager')"/>
<security:http-basic />
<security:csrf disabled="true"/>
</security:http>
<bean id="userappAuthenticationProvider" class="user.app.security.UserappAuthenticationProvider" />
<security:authentication-manager>
<security:authentication-provider user-service-ref="userappAuthenticationProvider">
</security:authentication-provider>
</security:authentication-manager>
</beans>
my UserappAuthenticationProvider class
public class UserappAuthenticationProvider implements UserDetailsService{
// Is it neccessary to autowire this object
// And this is causing problem when i am trying to autowire it's giving compilation error
private FarmerDAO farmerdao;
#Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
UserLogin farmer = farmerdao.getUserByLogin(userName);
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
UserApp principal = null;
principal = new UserApp(authorities,farmer.getUserId(), farmer.getUserName(), farmer.getRtn(), farmer);
String role=farmer.getRole();
System.out.println(farmer);
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return principal;
}
}
The compilation error is as follow if autowire:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [user.app.service.FarmerDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
And one thing when i am testing from postman and debugging the application.
the request comes till the line
FarmerLogin farmer = farmerService.getUserByLogin(userName);
of UserappAuthenticationProvider class and throws the error as show at the beginning of the post.
Please suggest me if i am missing some part so, that i can successfully authenticate the user.
In the code you've provided here, there is no sign of defining the farmerdao bean in the xmls, and the userappAuthenticationProvider does not have any setter for it and its bean did not set the property to it. so I think this is your problem.
In my experience, it is better to use one mode, xml or annotation. and I prefer xml.
the result will be like this :
<bean id="farmerdao" class="user.app.security.FarmerDaoImpl">
<!-- set the required attributes to connect your dao to the DB -->
<bean>
<bean id="userappAuthenticationProvider" class="user.app.security.UserappAuthenticationProvider">
<property name="farmerdao" ref="farmerdao"/>
</bean>
and of course you need to define a setter for farmerdao in your UserappAuthenticationProvider.

Can't get OpenEntityManagerInViewFilter to work in JBoss 6.1

I am trying to add open-session-in-view behavior to an existing pure JPA application. Using Spring in the service-tier is not an option. I would like to wrap the view in Spring's OpenEntityManagerInViewFilter, and not have to modify the EJB layer.
I am not having any luck getting OpenEntityManagerInViewFilter (Spring 3.2.2) to work in JBoss 6.1. The filter is definitely being invoked, but I am still getting a LazyInitializationException in the view.
The filter and the session-bean are using a different instance (and class) of the EntityManager. The filter is getting a org.hibernate.ejb.EntityManagerImpl, while the session-bean is getting a org.jboss.jpa.tx.TransactionScopedEntityManager. I am not sure what Spring configuration is responsible for this.
Here is the relevant code/config:
war/WEB-INF/classes/test.web.servlet.TestServlet
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private ServiceLocal service;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
long parentId = Long.parseLong(req.getParameter("parentId"));
Parent parent = service.retrieveParent(parentId);
// this call throws a LazyInitializationException
// because parent.children.session is NULL
parent.getChildren().iterator().next().getName();
req.setAttribute("parent", parent);
RequestDispatcher requestDispatcher = this.getServletContext().getRequestDispatcher("/WEB-INF/jsp/view.jsp");
requestDispatcher.forward(req, resp);
}
}
ejb/test.ejb.session.ServiceBean
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ServiceBean implements ServiceLocal, Service {
#PersistenceContext(name="test")
private EntityManager entityManager;
#Override
public Parent retrieveParent(Long parentId) {
return entityManager.find(Parent.class, parentId);
}
}
war/WEB-INF/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_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>test-war</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring.xml</param-value>
</context-param>
<filter>
<filter-name>osiv-filter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<init-param>
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
<servlet>
<servlet-name>test-servlet</servlet-name>
<servlet-class>test.web.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test-servlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<filter-mapping>
<filter-name>osiv-filter</filter-name>
<servlet-name>test-servlet</servlet-name>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
</web-app>
war/WEB-INF/spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceUnitName" value="test" />
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.manager_lookup_class">
org.hibernate.transaction.JBossTransactionManagerLookup
</prop>
</props>
</property>
</bean>
</beans>
ejb/META-INF/persistence.xml
<persistence
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="test" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MSSQLDS</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="jboss.entity.manager.factory.jndi.name" value="java:/testEntityManagerFactory" />
<property name="jboss.entity.manager.jndi.name" value="java:/testEntityManager" />
</properties>
</persistence-unit>
</persistence>
I don't think it's necessary to use a custom EntityManagerFactory to lookup the EntityManagerFactory via JDNI, the element should take care of that.
I have given your setup a little bit more thought and i don't think that the spring OpenEntityManagerInViewFilter will work for you. It binds an entity manager to the current thread so that spring's transaction management code can reuse it. The problem is that spring doesn't handle the transaction management of your service bean as this is handled by the the application server. The application server doesn't detect the entity manager bound to the thread by spring and creates another one; resulting in 2 different instances.
To make it work you should either define your service bean(s) in spring so that spring handles the transaction management or use jboss seam (JBoss Seam: How to Open jpa/hibernate session in view)
If you are sure that the open session in view filter is working then you might want to take a look at the transaction demarcation for service.retrieveParent(parentId);. The LazyInitializationException would make sense if the service/dao uses a different persistence context to load the parent entity.
I am not familiar with the spring/jboss setup and therefore missed some things.
I assume that your service bean is managed by the JBoss server and not by spring. By defining the LocalContainerEntityManagerFactoryBean you are actually configuring an EntityManagerFactory in Spring (very similar to the one managed by the application server). The open session in view filter is injected with the an EntityManager that's managed by Spring while it should have been injected by an entity manager managed by the application server.
I think that the following spring configuration will fix your problem (don't forget to adjust the jndi-name attribute):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<context:annotation-config/>
<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence-units/test"/>
<tx:jta-transaction-manager/>
LazyInitializationException means that hibernate tried to get the data of a lazy collection/object but the session was already closed.
If this line parent.getChildren().iterator().next().getName(); is throwing the error, it means that childrens is a lazy collection with actually no useful data, and by calling iterator().next() hibernate tried to load the entire collection.

Properties file not getting loaded

I have Two projects, CarpoolDB and Carpool.
CarpoolDB : contains backend stuff and has
carpool-application-context.xml
<context:annotation-config />
<context:component-scan base-package="com.onmobile" />
<context:property-placeholder location="classpath:server.properties" />
server.properties
cm.db.driverClassName=com.mysql.jdbc.Driver
cm.db.url=jdbc:mysql://localhost:3306/carpool1
cm.db.username=abc
cm.db.password=xyz
I make a jar of carpoolDB and place in Carpool Application
Carpool: contains UI thing and for backend contact carpoolDB jar and has
carpool-application-context1.xml
<import resource="classpath:carpool-application-context.xml"/>
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpool.authentication" />
spring-servlet.xml
<context:property-placeholder location="classpath:carpool.properties" />
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpool.controller, com.onmobile.carpool.util" />
carpool.properties
cm.email.sender.mail.smtp.host=mail.on.com
Now, I have one class com.onmobile.carpool.util.EmailSender, it has one property smtpHost and want the value to get injected by Spring using #Value but it is not getting injected.
#Controller
public class EmailSender {
public static final Log logger = LogFactory.getLog(EmailSender.class);
#Value("${cm.email.sender.mail.smtp.host}")
private String smtpHost;
}
I am getting error as
java.lang.IllegalArgumentException: Could not resolve placeholder 'cm.email.sender.mail.smtp.host'
carpool.properties is present in src folder.
Why it is not picking the cm.email.sender.mail.smtp.host from carpool.properties file. is there any relation with properties file present in jar file.
Actually properties file is loaded as I can't see in logs like file not found but field is not getting autowired.
Posting updated complete configuration files after removing import
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/carpool-application-context1.xml
/WEB-INF/applicationContext-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>/*</url-pattern>
</filter-mapping>
<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>/jsp/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>
carpool-application-context1.xml
<!-- Configure annotated beans -->
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpooldb.db" />
<context:property-placeholder location="classpath:carpool.properties" />
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<beans:property name="driverClassName"><beans:value>${cm.db.driverClassName}</beans:value></beans:property>
<beans:property name="url"><beans:value>${cm.db.url}</beans:value></beans:property>
<beans:property name="username"><beans:value>${cm.db.username}</beans:value></beans:property>
<beans:property name="password"><beans:value>${cm.db.password}</beans:value></beans:property>
<beans:property name="testOnBorrow"><beans:value>true</beans:value></beans:property>
<beans:property name="testOnReturn"><beans:value>true</beans:value></beans:property>
<beans:property name="validationQuery"><beans:value>select 1</beans:value></beans:property>
<beans:property name="maxIdle"><beans:value>-1</beans:value></beans:property>
<beans:property name="maxActive"><beans:value>-1</beans:value></beans:property>
<beans:property name="maxOpenPreparedStatements"><beans:value>-1</beans:value></beans:property>
<beans:property name="maxWait"><beans:value>30000</beans:value></beans:property>
</beans:bean>
//session factory bean and other configuration
spring-servlet.xml
<context:property-placeholder location="classpath:carpool.properties" />
<context:annotation-config />
<context:component-scan base-package="com.onmobile.carpool.authentication, com.onmobile.carpool.controller, com.onmobile.carpool.util" />
<!-- Declare a view resolver -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
<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>
carpool.properties
cm.db.driverClassName=com.mysql.jdbc.Driver
cm.db.url=jdbc:mysql://localhost:3306/carpool
cm.db.username=abc
cm.db.password=xyz
user.profile.pic.base.folder=D:\\carpoolRepository\\carpoolProfilePicUpload
google.places.autocomplete.response.xml.base.folder=D:\\carpoolRepository\\googleMapXML
#EMAIL - FORGOT PASSWORD
cm.email.sender.mail.smtp.host=mail.on.com
I am trying to inject value of cm.email.sender.mail.smtp.host in EmailSender "smtpHost" property way mentioned above, when i read it it says null.
other properties like cm.db.driverClassName etc get properly injected in carpool-application-context1.xml.
I am attaching the snap containing location for configuration files
You have <context:component-scan base-package="com.onmobile" /> in the carpool-application-context.xml which is imported from carpool-application-context1.xml so that forces your controller to be created in the root web app context, because "com.onmobile" includes "com.onmobile.carpool.controller", and there is no property-placeholder config for the root context.
You have a property placeholder configurer in the servlet context(spring-servlet.xml). Property placeholder configurers(defined by the context:property-placeholder tag) are bean postprocessors and work on per container basis, so they can't modify the bean definitions of context they are not defined in. So it can't modify the bean definition of controller instance declared in the root context(carpool-application-context.xml, carpool-application-context1.xml). So because of the double scanning your controller is created twice - both in root and servlet context, and only one is processed by the correct placeholder configurer.
As a fix, you can use filter expressions in component-scan to pick up #Controller annotated classes only only in the spring-servlet.xml, and exclude it from carpool-application-context.xml/carpool-application-context1.xml
See #Service are constructed twice for examples of filters
Please keep your Spring configuration simple, your configuration is very puzzling.
update you are confusing controllers (which are annotated with #Controller and I think should be better put into aaa.bbb.controllers package) with services which should be annotated with #Service in the util package. My advice is to move your services to the root web app context(carpool-application-context1.xml) and put the property placeholder configurer declaration there.

URL Mapping issue - Spring web MVC

I'm a newbie with Spring and web MVC module. Basically, i have the following :
web.xml
<servlet>
<servlet-name>abc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>abc-dispatcher</servlet-name>
<url-pattern>/user/*</url-pattern>
</servlet-mapping>
abc-dispatcher-servlet.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="myPkg" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
And i have a controller, related parts are :
#Controller
public class ABCController {
#RequestMapping("/user/welcome")
public String printWelcome(ModelMap model) {
//code
}
Now whenever i try to access http://localhost:8080/myapp/user/welcome
it gives me 404.
Logs say that "mapped url '/user/welcome' onto handler 'ABCController' but it failed to map URI [/MYAPP/user/welcome] in DispatcherServlet with name 'abc-dispatcher' .
Totally confused. I have checked all the threads where we specify a mapping twice, but that's not the case here. I must be missing something!
Thanks for the help!
The URL should be http://localhost:8080/myapp/user/user/welcome. Indeed, unless the alwaysUseFullPath property of the handler is set to true, the servlet-mapping is prepended to the request mapping URL to form the full path.
See http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#mvc-handlermapping for details:
alwaysUseFullPath
If true , Spring uses the full path within the current Servlet context to find an appropriate handler. If false (the default), the
path within the current Servlet mapping is used. For example, if a
Servlet is mapped using /testing/* and the alwaysUseFullPath property
is set to true, /testing/viewPage.html is used, whereas if the
property is set to false, /viewPage.html is used.
It's' been added context:component-scan element into the sample context file snippet but there is no <annotation-driven/> element that says spring framework to look for controllers annotated with #Controller
For me, the problem was that I was using the deprecated DefaultAnnotationHandlerMapping, and even if setting the alwaysUseFullPath to true, it didn't take effect, however replacing DefaultAnnotationHandlerMapping in benefit of RequestMappingHandlerMapping with the alwaysUseFullPath set to true solved the problem.
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="alwaysUseFullPath" value="true"></property>
</bean>

Resources