Spring Security does not display login page - spring

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>

Related

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.

HTTP 404 Not Found after successful Spring Security authentication

I am trying to implement Spring Security Authentication and Authorization using Database. Spring security authentication is working good. But I am getting HTTP 404 NOT FOUND page with URL /Sample_App/j_spring_security_check, instead of default-target-url it should goto.
Here is my spring-security file
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<beans:import resource="im-jndi-datasource.xml" />
<http pattern="/inventory/auth/login" security="none"/>
<http pattern="/inventory/auth/deny" security="none"/>
<http pattern="/images/**" security="none"/>
<http pattern="/css/**" security="none"/>
<http pattern="/js/**" security="none"/>
<http auto-config="true">
<intercept-url pattern="/inventory/**" access="ROLE_ADMIN" />
<form-login
login-page="/inventory/auth/login"
default-target-url="/inventory/landing/loadDashBoardPage"
authentication-failure-url="/inventory/auth/login?error"
username-parameter="username"
password-parameter="password" />
<access-denied-handler error-page="/inventory/auth/deny"/>
<logout logout-success-url="/logout" />
<session-management
session-authentication-error-url="/inventory/auth/login"
invalid-session-url="/inventory/auth/login">
<concurrency-control max-sessions="1" error-if-maximum-exce eded="true"/>
</session-management>
</http>
<authentication-manager>
<authentication-provider>
<!-- <security:user-service> <security:user name="dineshonjava" password="sweety"
authorities="ROLE_USER" /> </security:user-service> -->
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username, password, status as enabled from bbp_user where username=?"
authorities-by-username-query="select us.username, ur.rolename as authority from bbp_user us, bbp_users_and_roles bur, bbp_role ur
where us.user_id = bur.user_id and bur.role_id =ur.role_id and us.username =? " />
</authentication-provider>
</authentication-manager>
</beans:beans>
Here is the part of spring-servlet.xml file
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/eimsgo-security.xml</param-value>
</context-param>
<servlet>
<servlet-name>spring</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>WEB-INF/spring-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/inventory/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I use tiles2.TilesViewResolver and ContentNegotiatingViewResolver
Here is my tiles-context xml
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/views.xml</value>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="atom" value="application/atom+xml"/>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json"/>
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
My welcome file index.jsp hits the LoginController.java with URL (/inventory/auth/login)
LoginController.java
#Controller
#RequestMapping("/auth")
public class LoginController {
#RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout,
#RequestParam(value = "invalid", required = false) String invalid) {
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
if(invalid != null) {
model.addObject("invalid", "Invalid session!!");
}
model.setViewName("home_creation");
return model;
}
}
After successful login, it should goto /inventory/landing/loadDashBoardPage as per default-target-url defined in the security xml file.
Where /landing is one of my Spring Controller, and loadDashBoarPage is method level mapping. The loadDashBoardPage interacts with the database and set the Map object and retuns the View string "DashBoardPage". TilesViewResolver now should render this page.
InventoryController.java
#Controller
#RequestMapping("/landing")
public class InventoryController {
#RequestMapping(value = { "/loadDashBoardPage" }, method = { GET, POST })
public String loadDashBoardPage(Map<String, Object> model,
HttpServletRequest request, HttpSession session) {
List lobList = new ArrayList();
InventoryService inventoryService = (InventoryService) InventoryApplicationContext
.getBean("inventoryService");
lobList = inventoryService.loadLob();
model.put("lob", lobList);
model.put("leftTreee", inventoryService.loadDataforNavigator());
return "DashBoardPage";
}
Please find the log below
2014-12-05 22:55:27,419 [http-bio-8090-exec-8] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Initiating transaction commit
2014-12-05 22:55:27,420 [http-bio-8090-exec-8] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Committing JDBC transaction on Connection [jdbc:oracle:thin:#10.237.31.14:1521:xe, UserName=ADMIN, Oracle JDBC driver]
2014-12-05 22:55:27,422 [http-bio-8090-exec-8] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [jdbc:oracle:thin:#10.237.31.14:1521:xe, UserName=ADMIN, Oracle JDBC driver] after transaction
2014-12-05 22:55:27,422 [http-bio-8090-exec-8] DEBUG org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
2014-12-05 22:55:27,425 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.view.ContentNegotiatingViewResolver - Requested media types are [image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, /] (based on Accept header)
2014-12-05 22:55:27,425 [http-bio-8090-exec-8] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'DashBoardPage.atom'
2014-12-05 22:55:27,426 [http-bio-8090-exec-8] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'DashBoardPage.json'
2014-12-05 22:55:27,429 [http-bio-8090-exec-8] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'DashBoardPage.html'
2014-12-05 22:55:27,430 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.view.ContentNegotiatingViewResolver - Returning [org.springframework.web.servlet.view.tiles2.TilesView: name 'DashBoardPage'; URL [DashBoardPage]] based on requested media type '/'
2014-12-05 22:55:27,430 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.tiles2.TilesView: name 'DashBoardPage'; URL [DashBoardPage]] in DispatcherServlet with name 'spring'
2014-12-05 22:55:27,430 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.view.tiles2.TilesView - Added model object 'lob' of type [java.util.ArrayList] to request in view with name 'DashBoardPage'
2014-12-05 22:55:27,431 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.view.tiles2.TilesView - Added model object 'leftTreee' of type [java.util.HashMap] to request in view with name 'DashBoardPage'
2014-12-05 22:55:27,431 [http-bio-8090-exec-8] DEBUG org.apache.tiles.impl.BasicTilesContainer - Render request recieved for definition 'DashBoardPage'
2014-12-05 22:55:27,432 [http-bio-8090-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request
2014-12-05 22:55:27,432 [http-bio-8090-exec-8] DEBUG org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
2014-12-05 22:55:27,432 [http-bio-8090-exec-8] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
Spring Security authenticates successfully here and the view resolver is not rendering the requested page.
Instead I am getting http://abc.xyz.com/Sample_App/j_spring_security_check
It should allow the user to goto the URL as defined in the default-target-url
/Sample_App/inventory/landing/loadDashBoardPage
Please advise!!
I resolved the issue myself. Spring Security tightly intercepts all the URLs including CSS, Images, JavaScripts, JSP files and everything.
The problem here is, I am using TilesViewResolver
<definition name="LogoutPage" template="/jsp/logout.jsp">
<put-attribute name="header" value="/jsp/tiles/logoutHeader.jsp" />
<put-attribute name="footer" value="/jsp/tiles/footer.jsp" />
<put-attribute name="content" value="/jsp/logout_creation.jsp" />
</definition>
I forget to configure the spring security that intercept all the sub-URLs that these tiles pages use with authentication based on roles.

Creating secure pages in Spring

I am creating a website using Spring and want all pages under the folder "/admin" to be secure. However don't really know where to start and only have one complicated example to go on.
At work, we store the details in a database but I was hoping it could be more simple than that, maybe stored in context.xml or something? I am confronted with this page:
web.xml:
<security-constraint>
<display-name>admin pages</display-name>
<web-resource-collection>
<web-resource-name>Administration Pages</web-resource-name>
<description/>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>userAdmin</role-name>
</auth-constraint>
<!-- <user-data-constraint>
<description/>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>-->
</security-constraint>
and in tomcat-users.xml I have the following password information:
<user password="password" roles="tomcat,role1,manager-script,manager-gui,admin,manager" username="user"/>
But when I try and access the page /admin/adminindex.htm, I get a forbidden error:
Access to the specified resource (Access to the requested resource has been denied) has been forbidden.
Ideally I would like to store user details in the database but can't progress with either at the moment.
I would look into Spring Security, which offers a plethora of options for securing websites (including DB-backed or JNDI-backed security). The tutorial may prove a good starting point.
This is how I secure applications using Spring Security, here is the 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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-servlet.xml
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/myapp/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
spring-security.xml
<security:http auto-config="true" use-expressions="true" access-denied-page="/" create-session="never" disable-url-rewriting="true">
<security:intercept-url pattern="/myapp/auth/login" access="permitAll" />
<security:intercept-url pattern="/myapp/main/**" access="hasRole('ROLE_USER')" />
<security:form-login login-page="/" authentication-failure-url="/myapp/auth/login?error=true" default-target-url="/myapp/main/default"/>
<security:logout invalidate-session="true" logout-success-url="/myapp/auth/login" logout-url="/myapp/auth/logout" />
</security:http>
In order to authenticate using a Database you can use an Authentication Manager like this in spring-security.xml
<security:authentication-manager>
<security:authentication-provider user-service-ref="userService">
<security:password-encoder ref="passwordEncoder" />
</security:authentication-provider>
</security:authentication-manager>
Where "userService" is a service you define that has access to the Database, your service must implement org.springframework.security.core.userdetails.UserDetailsService and write the method
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException, DataAccessException {
UserDetails user = null;
try {
// Replace loadUserFromDB with your Data access method to pull the user and encrypted password from the database
Users u = loadUserFromDB(userName);
if(u != null)
user = new User(u.getEmail(), u.getPassword().toLowerCase(), true, true, true, true, getAuthorities(0));
} catch (Exception e) {
e.printStackTrace();
}
return user;
}
Spring security will use this method to secure your pages. Make sure to include this method:
public Collection<GrantedAuthority> getAuthorities(Integer access) {
// Create a list of grants for this user
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(1);
authList.add(new GrantedAuthorityImpl("ROLE_USER"));
authList.add(new GrantedAuthorityImpl("ROLE_ANONYMOUS"));
return authList;
}
I would start with this: http://docs.spring.io/autorepo/docs/spring-security/3.0.x/reference/springsecurity.html You can also check out this project that already has the basic code to start using Spring Security
https://github.com/pgardunoc/spring-security

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.

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

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.

Resources