Spring Security Interceptor - spring

I am upgrading Spring framework from 2.5 to 5.3.9. Everything is working except where I call secure controllers that supposed to call interceptor but UserInfo loginUserInfo = (UserInfo) session.getAttribute("loginUserInfo") is getting null as SecurityInterceper not being called.
Configuration file:
<beans:bean id="securityInterceptor" class="dhs.pfWaldo.interceptor.SecurityInterceptor">
<beans:property name="defaultUser">
<beans:value>${pfWaldo.defaultUser}</beans:value>
</beans:property>
</beans:bean>
<beans:bean id="secureUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<beans:property name="interceptors" ref ="securityInterceptor"/>
<beans:property name="mappings">
<beans:props>
<beans:prop key="/secure/homeTrainingProvider.html">homeTrainProviderSecureController</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
SecurityInterSepter.java
package xxx.abc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import xxx.abc.security.UserInfo;
public class SecurityInterceptor implements HandlerInterceptor {
private static final Log log = LogFactory.getLog(SecurityInterceptor.class);
private String defaultUser;
#Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception {
boolean retVal = true;
HttpSession session = request.getSession(true);
String AuthHeader = request.getHeader("Authorization");
String serverName = request.getServerName();
Controller:
#Controller
public class HomeTrainProviderSecureController {
private String logout_url;
private CompanyIdDAO dao;
private CompanySearchValidator validator;
#RequestMapping(value = "/secure/homeTrainingProvider.html", method = RequestMethod.GET)
protected ModelAndView homeTrainProviderSecureInit(Model model,HttpServletRequest request,
HttpServletResponse response) throws Exception {
HttpSession session = request.getSession(true);
Constants.logout_url = getLogout_url();
UserInfo loginUserInfo = (UserInfo) session.getAttribute("loginUserInfo");
String userid = loginUserInfo.getUserId();

Related

Spring mvc messagesource failed in annotation

I am able to retrieve message with this code
public class UserApp {
public static void main(String[] args) {
ApplicationContext appContext
= new ClassPathXmlApplicationContext("application-configuration.xml");
System.out.println(appContext.getMessage("NotEmpty.userForm.name",
new Object[] { 28,"http://www.mkyong.com" }, Locale.US ));
}
}
But failed with the same application-configuration.xml using ContextConfiguration Annotation. it is showing me
Caused by: org.springframework.context.NoSuchMessageException: No message found under code 'NotEmpty.userForm.name' for locale 'en_US'.
#Controller
#ContextConfiguration("/application-configuration.xml")
public class UserController {
private static final Logger logger =
LoggerFactory.getLogger(UserController.class);
#Autowired
ApplicationContext appContext;
#RequestMapping(value = "/users/add", method = RequestMethod.GET)
public String showAddUserForm(Model model) {
String temp = appContext.getMessage("NotEmpty.userForm.name",
new Object[] { 28,"http://www.mkyong.com" }, Locale.US ));
}
}
application-configuration.xml
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename">
<beans:value>locale/messages</beans:value>
</beans:property>
</beans:bean>
Did i use the wrong annotation for this?

Spring JAAS Authentication with database authorization

I am using Spring security 4.0. My login module is configured in Application server so I have to do authentication using JAAS but my user details are stored in database, so once authenticated user object will be created by querying database. Could you please let me know how to achieve this i.e. LDAP authentication and load user details from database. Also how cache the user object using eh-cache, so that the user object can be accessed in the service / dao layer.
This can be achieved using CustomAuthentication Provider. Below are the codes.
import java.util.Arrays;
import java.util.List;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.authentication.jaas.JaasGrantedAuthority;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.sun.security.auth.UserPrincipal;
public class CustomAutenticationProvider extends DaoAuthenticationProvider implements AuthenticationProvider {
private AuthenticationProvider delegate;
public CustomAutenticationProvider(AuthenticationProvider delegate) {
this.delegate = delegate;
}
#Override
public Authentication authenticate(Authentication authentication) {
Authentication a = delegate.authenticate(authentication);
if(a.isAuthenticated()){
a = super.authenticate(a);
}else{
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
return a;
}
private List<GrantedAuthority> loadRolesFromDatabaseHere(String name) {
GrantedAuthority grantedAuthority =new JaasGrantedAuthority(name, new UserPrincipal(name));
return Arrays.asList(grantedAuthority);
}
#Override
public boolean supports(Class<?> authentication) {
return delegate.supports(authentication);
}
/* (non-Javadoc)
* #see org.springframework.security.authentication.dao.DaoAuthenticationProvider#additionalAuthenticationChecks(org.springframework.security.core.userdetails.UserDetails, org.springframework.security.authentication.UsernamePasswordAuthenticationToken)
*/
#Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
if(!authentication.isAuthenticated())
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
}
UserDetails required for DAOAuthentication
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import com.testjaas.model.User;
import com.testjaas.model.UserRepositoryUserDetails;
#Component
public class AuthUserDetailsService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername called !!");
com.testjaas.model.User user = new User();
user.setName(username);
user.setUserRole("ROLE_ADMINISTRATOR");
if(null == user) {
throw new UsernameNotFoundException("User " + username + " not found.");
}
return new UserRepositoryUserDetails(user);
}
}
RoleGrantor - This will be a dummy class required for Spring JAAS authentication
import java.security.Principal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.security.authentication.jaas.AuthorityGranter;
public class RoleGranterFromMap implements AuthorityGranter {
private static Map<String, String> USER_ROLES = new HashMap<String, String>();
static {
USER_ROLES.put("test", "ROLE_ADMINISTRATOR");
//USER_ROLES.put("test", "TRUE");
}
public Set<String> grant(Principal principal) {
return Collections.singleton("DUMMY");
}
}
SampleLogin - This should be replaced with your login module
import java.io.Serializable;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
public class SampleLoginModule implements LoginModule {
private Subject subject;
private String password;
private String username;
private static Map<String, String> USER_PASSWORDS = new HashMap<String, String>();
static {
USER_PASSWORDS.put("test", "test");
}
public boolean abort() throws LoginException {
return true;
}
public boolean commit() throws LoginException {
return true;
}
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
this.subject = subject;
try {
NameCallback nameCallback = new NameCallback("prompt");
PasswordCallback passwordCallback = new PasswordCallback("prompt",false);
callbackHandler.handle(new Callback[] { nameCallback,passwordCallback });
this.password = new String(passwordCallback.getPassword());
this.username = nameCallback.getName();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean login() throws LoginException {
if (USER_PASSWORDS.get(username) == null
|| !USER_PASSWORDS.get(username).equals(password)) {
throw new LoginException("username is not equal to password");
}
subject.getPrincipals().add(new CustomPrincipal(username));
return true;
}
public boolean logout() throws LoginException {
return true;
}
private static class CustomPrincipal implements Principal, Serializable {
private final String username;
public CustomPrincipal(String username) {
this.username = username;
}
public String getName() {
return username;
}
}
}
Spring XML configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<security:http auto-config="true">
<security:intercept-url pattern="/*" access="isAuthenticated()"/>
</security:http>
<!-- <security:authentication-manager>
<security:authentication-provider ref="jaasAuthProvider" />
</security:authentication-manager> -->
<bean id="userDetailsService" class="com.testjaas.service.AuthUserDetailsService"></bean>
<bean id="testService" class="com.testjaas.service.TestService"/>
<bean id="applicationContextProvider" class="com.testjaas.util.ApplicationContextProvider"></bean>
<security:authentication-manager>
<security:authentication-provider ref="customauthProvider"/>
</security:authentication-manager>
<bean id="customauthProvider" class="com.testjaas.security.CustomAutenticationProvider">
<constructor-arg name="delegate" ref="jaasAuthProvider" />
<property name="userDetailsService" ref="userDetailsService" />
</bean>
<bean id="jaasAuthProvider" class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
<property name="loginConfig" value="classpath:pss_jaas.config" />
<property name="authorityGranters">
<list>
<bean class="com.testjaas.security.RoleGranterFromMap" />
</list>
</property>
<property name="loginContextName" value="JASSAuth" />
<property name="callbackHandlers">
<list>
<bean class="org.springframework.security.authentication.jaas.JaasNameCallbackHandler" />
<bean class="org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler" />
</list>
</property>
</bean>
</beans>
Sample jaas config
JASSAuth {
com.testjaas.security.SampleLoginModule required;
};

Stream directly to response output stream in handler method of Spring MVC 3.1 controller

I have a controller method that handles ajax calls and returns JSON. I am using the JSON library from json.org to create the JSON.
I could do the following:
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public String getJson()
{
JSONObject rootJson = new JSONObject();
// Populate JSON
return rootJson.toString();
}
But it is inefficient to put together the JSON string, only to have Spring write it to the response's output stream.
Instead, I can write it directly to the response output stream like this:
#RequestMapping(method = RequestMethod.POST)
public void getJson(HttpServletResponse response)
{
JSONObject rootJson = new JSONObject();
// Populate JSON
rootJson.write(response.getWriter());
}
But it seems like there would be a better way to do this than having to resort to passing the HttpServletResponse into the handler method.
Is there another class or interface that can be returned from the handler method that I can use, along with the #ResponseBody annotation?
You can have the Output Stream or the Writer as an parameter of your controller method.
#RequestMapping(method = RequestMethod.POST)
public void getJson(Writer responseWriter) {
JSONObject rootJson = new JSONObject();
rootJson.write(responseWriter);
}
#see Spring Reference Documentation 3.1 Chapter 16.3.3.1 Supported method argument types
p.s. I feel that using OutputStream or Writer as an parameter is still much more easier to use in tests than a HttpServletResponse - and thanks for paying attention to what I have written ;-)
In the end, I wrote an HttpMessageConverter for this. With it, I can do the following:
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public JSONObject getJson()
throws JSONException
{
JSONObject rootJson = new JSONObject();
// Populate JSON
return rootJson;
}
Here is my HttpMessageConverter class:
package com.example;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
public class JsonObjectHttpMessageConverter
extends AbstractHttpMessageConverter<JSONObject>
{
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
public JsonObjectHttpMessageConverter()
{
super(new MediaType("application", "json"), new MediaType("text", "javascript"));
}
#Override
protected boolean supports(Class<?> clazz)
{
return JSONObject.class.equals(clazz);
}
#Override
protected JSONObject readInternal(Class<? extends JSONObject> clazz,
HttpInputMessage inputMessage)
throws IOException,
HttpMessageNotReadableException
{
throw new UnsupportedOperationException();
}
#Override
protected void writeInternal(JSONObject jsonObject,
HttpOutputMessage outputMessage)
throws IOException,
HttpMessageNotWritableException
{
PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputMessage.getBody(),
getContentTypeCharset(outputMessage)));
try
{
jsonObject.write(writer);
writer.flush();
}
catch (JSONException e)
{
throw new HttpMessageNotWritableException(e.getMessage(), e);
}
}
private Charset getContentTypeCharset(HttpMessage message)
{
MediaType contentType = message.getHeaders().getContentType();
Charset charset = (contentType != null) ? contentType.getCharSet() : null;
return (charset != null) ? charset : DEFAULT_CHARSET;
}
}
The HttpMessageConverter must be registered with Spring. This can be done in the dispatcher-servlet.xml file like this:
<beans ...>
...
<mvc:annotation-driven conversion-service="conversionService" validator="validator">
<mvc:argument-resolvers>
...
</mvc:argument-resolvers>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
<value>*/*</value>
</list>
</property>
<property name="writeAcceptCharset" value="false" />
</bean>
<bean class="com.example.JsonObjectHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
...
</beans>
As you can see, I have other HttpMessageConverter objects registered too. The order does matter.
Note that if you use the OutputStream or Writer it requires you to write the headers yourself.
One workaround is to use InputStreamResource/ResourceHttpMessageConverter

No Session found for current thread (HIBERNATE)

OK JAVA guru ))
I really new to spring and I got into this trouble with "No session found the current thread" when I refer to the following page JSP security after login. Up to this point everything is working.
I need your help guys!!!!!
Here is my controller for that page:
package employee.controller;
import employee.service.AdminService;
import employee.service.UserService;
import org.apache.log4j.Logger;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.annotation.Resource;
/**
* #author serge
*
* Handles and retrieves the common or admin page depending on the URI template.
* A user must be log-in first he can access these pages. Only the admin can see
* the adminpage, however.
*/
#Controller
#RequestMapping("/main")
public class MainController {
protected static Logger logger = Logger.getLogger("controller");
#Resource(name = "adminService")
private AdminService adminService;
#Resource(name = "userService")
private UserService userService;
/**
* Handles and retrieves a /WEB-INF/jsp/employee-page.jsp
*
* containing all employee
*
* #return the name of the JSP page
*/
#Secured("ROLE_USER")
#RequestMapping(value = "/employee-list",method = RequestMethod.GET)
public String getEmployeeListPage(Model model) {
logger.debug("Received request to show all employee page");
// Retrieve all employee and attach to model
model.addAttribute("all-employee", userService.findAllEmployee());
return "employee-page";
}
/**
* Handles and retrieves /WEB-INF/jsp/admin-page.jsp that only admins can see
*
* #return the name of the JSP page
*/
#Secured("ROLE_ADMIN")
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public String getAdminPage() {
logger.debug("Received request to show admin page");
return "admin-page";
}
}
This is user service that had been called from controller:
package employee.service.impl;
import employee.DAO.EmployeeInfoDAO;
import employee.model.EmployeeInfo;
import employee.service.UserService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* #author serge
*
* Reader level
*
* Service to Retrieve info about Employees
*/
#Service("userService")
#Transactional
public class UserServiceImpl implements UserService {
protected static Logger logger = Logger.getLogger("service");
private EmployeeInfoDAO emplInfoDAO;
#Autowired
public void setEmployeeDao(EmployeeInfoDAO emplInfoDAO) {
this.emplInfoDAO = emplInfoDAO;
}
/**
* Retrieving Employee Information by id
*
* #return EmployeeInfo object
*/
#Override
#Transactional
#Secured("ROLE_USER")
public EmployeeInfo findEmployeeByID(Integer id) {
logger.debug("Retrieving Employee with id= " + id);
EmployeeInfo employeeInfo = new EmployeeInfo();
employeeInfo.setId(id);
emplInfoDAO.find(employeeInfo);
return employeeInfo;
}
/**
* Retrieving all Employees
*
* #return List of EmployeeInfo object
*/
#Override
#Secured("ROLE_USER")
#Transactional(readOnly = true)
public List<EmployeeInfo> findAllEmployee() {
logger.debug("Retrieving all Employee");
return emplInfoDAO.findAll();
}
/**
* Retrieving Employees by last name
*
* #return List of EmployeeInfo object
*/
#Override
#Secured("ROLE_USER")
#Transactional(readOnly = true)
public List<EmployeeInfo> findAllByLastName(String lastName, Object paramValue) {
lastName = "lastName";
logger.debug("Retrieving Employee by last name: " + paramValue);
return emplInfoDAO.findAllByParam(lastName, paramValue);
}
/**
* Retrieving Employees by first name
*
* #return List of EmployeeInfo object
*/
#Override
#Secured("ROLE_USER")
#Transactional(readOnly = true)
public List<EmployeeInfo> findAllByFirstName(String firstName, Object paramValue) {
firstName = "firstName";
logger.debug("Retrieving Employee by first name: " + paramValue);
return emplInfoDAO.findAllByParam(firstName, paramValue);
}
}
And this is custom DAO support, not sure if this is right way to do that.... :
package employee.DAO.impl;
import employee.DAO.DAO;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
public class CustomHibernateDaoSupport<T> implements DAO<T> {
//was extending HibernateDaoSupport
private Class<T> clazz;
private SessionFactory sessionFactory;
public CustomHibernateDaoSupport(Class<T> clazz) {
this.clazz = clazz;
}
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
#Override
#Transactional
public void save(T entity) {
getCurrentSession().save(entity);
}
#Override
#Transactional
public void update(T entity) {
getCurrentSession().update(entity);
}
#Override
#Transactional
public void delete(Serializable key) {
Object entity = getCurrentSession().get(clazz, key);
if (entity != null) {
getCurrentSession().delete(entity);
}
}
#Override
#Transactional
public T find(Serializable key) {
return (T) getCurrentSession().get(clazz, key);
}
#Override
#Transactional
public List<T> findAll() {
return getCurrentSession().createCriteria(clazz).list();
}
#Override
#Transactional
public List<T> findAllByParam(final String paramName, final Object paramValue) {
return getCurrentSession().createCriteria(clazz)
.add(Restrictions.eq(paramName, paramValue))
.list();
}
}
And of course 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: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">
<!-- Activates annotations -->
<context:annotation-config />
<mvc:annotation-driven/>
<!-- Scans for annotated components in base-package-->
<context:component-scan base-package="employee" />
<bean class="employee.service.impl.AdminServiceImpl"/>
<bean class="employee.service.impl.UserServiceImpl"/>
<!-- Shared Hibernate SessionFactory in a Spring application context. -->
<bean id = "transactionManager" class = "org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="annotatedClasses">
<list>
<value>employee.model.UserInfo</value>
<value>employee.model.EmployeeInfo</value>
<value>employee.model.EmployeeDiv</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- for database, imports the properties from database.properties -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties"/>
</bean>
</beans>
after a successful login, I called /employee-list and got this instead of the page:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.HibernateException: No Session found for current thread
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
...
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
employee.DAO.impl.CustomHibernateDaoSupport.getCurrentSession(CustomHibernateDaoSupport.java:31)
employee.DAO.impl.CustomHibernateDaoSupport.findAll(CustomHibernateDaoSupport.java:64)
...
Please help me understand where is my mistake, maybe I made a wrong configuration?
If you have dispatch-servlet.xml, add the
<tx:annotation-driven />
Or there is an alternative:
Please see this:
this blog

Spring #Transactional not working

I previously had a post on this issue that was resolved. However since rebuilding the project with auto wired beans and less XML configuration I find I am revisiting this issue. I have followed the way my previous project implemented this but it doesn't work. Can someone help me with why or what I should change to make it work?
I am on purpose using a non existent table name in the insert user details method to deliberately throw an exception. However the statements for insert user and insert user roles are not rolled back. Please help.
My current design for the registration is like this.
Part of servlet.xml:
<context:component-scan base-package="com.doyleisgod.golfer.controllers"/>
<context:component-scan base-package="com.doyleisgod.golfer.dao"/>
<context:component-scan base-package="com.doyleisgod.golfer.services"/>
<context:component-scan base-package="com.doyleisgod.golfer.validators"/>
Part of application context:
<context:annotation-config />
<tx:annotation-driven />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Registration controller:
package com.doyleisgod.golfer.controllers;
import javax.validation.Valid;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.doyleisgod.golfer.formdata.RegistrationForm;
import com.doyleisgod.golfer.services.IRegistrationService;
import com.doyleisgod.golfer.validators.RegistrationFormValidator;
/**
* Description: Registration controller provides and processes the registration form.
* #author Chris Doyle
*/
#Controller
#RequestMapping("/registration.htm")
public class RegistrationController {
protected final Log logger = LogFactory.getLog(getClass());
#Autowired private IRegistrationService iRegistrationService;
#Autowired private RegistrationFormValidator registrationFormValidator;
// sets a customer validator for the registration form
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(registrationFormValidator);
}
// Description: Method called by a get request to the registration controller. Returns the
#RequestMapping(method=RequestMethod.GET)
public String registration (Model model){
model.addAttribute(new RegistrationForm());
return "registration";
}
// Description: Method called by a post request to the registration controller. Method calls validation on the registration form using custom validator and returning
// any errors back to the user.
#RequestMapping(method=RequestMethod.POST)
public String processRegistration (#Valid RegistrationForm registrationForm, BindingResult bindingResult, Model model){
logger.info("Received the following registration form details");
logger.info(registrationForm.toString());
if (bindingResult.hasErrors()) {
logger.warn("Registration Validation Failed");
model.addAttribute("validationError", "Please correct the fields marked with errors");
return "registration";
}
try {
iRegistrationService.registerUser(registrationForm);
} catch (Exception e) {
logger.error("An Exception has occured processing the registration form");
model.addAttribute("exceptionError", "An exception has occured, please try again.");
e.printStackTrace();
return "registration";
}
return "redirect:login.htm?registration=sucessful";
}
}
Registration service:
package com.doyleisgod.golfer.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import com.doyleisgod.golfer.dao.IRegistrationDAO;
import com.doyleisgod.golfer.formdata.RegistrationForm;
#Service("IRegistrationService")
public class RegistrationService implements IRegistrationService {
#Autowired private IRegistrationDAO iRegistrationDAO;
private final boolean enabled = true;
private final String roles = "ROLE_USER";
#Override
#Transactional (rollbackFor = Exception.class)
public void registerUser(RegistrationForm registrationForm) throws Exception {
System.out.println("inside the registerUser method. is wrapped in transaction: "+TransactionSynchronizationManager.isActualTransactionActive());
String username = registrationForm.getUsername();
String password = registrationForm.getPassword();
String firstname = registrationForm.getFirstname();
String lastname = registrationForm.getLastname();
String email = registrationForm.getEmail();
int handicap = Integer.parseInt(registrationForm.getHandicap());
String encryptedPassword = ((new ShaPasswordEncoder()).encodePassword(password, username));
iRegistrationDAO.insertUser(username, encryptedPassword, enabled);
iRegistrationDAO.insertRoles(username, roles);
iRegistrationDAO.insertUserDetails(username, firstname, lastname, email, handicap);
}
#Override
public boolean checkUser(String username) {
return iRegistrationDAO.checkUserName(username);
}
}
Registration DAO:
package com.doyleisgod.golfer.dao;
import javax.annotation.Resource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionSynchronizationManager;
#Repository("iRegistrationDAO")
public class RegistrationDAO extends JdbcTemplate implements IRegistrationDAO {
#Resource private BasicDataSource dataSource;
#Override
public boolean checkUserName(String username) {
int db_user = queryForInt("select count(username) from users where username = ?", username);
if (db_user == 1 ){
return true;
}
return false;
}
#Override
public void insertUser(String username, String password, boolean enabled) throws Exception {
System.out.println("inside the insertuser method. is wrapped in transaction: "+TransactionSynchronizationManager.isActualTransactionActive());
update("insert into users (username, password, enabled) VALUES (?,?,?)", username, password, enabled);
}
#Override
public void insertRoles(String username, String roles) throws Exception {
update("insert into user_roles (username, authority) VALUES (?,?)", username, roles);
}
#Override
public void insertUserDetails(String username, String firstname, String lastname, String email, int handicap) throws Exception {
update("insert into user_detailss (username, first_name, last_name, email_address, handicap)" +
"VALUES (?,?,?,?,?)", username, firstname, lastname, email, handicap);
}
public void setDataSource(BasicDataSource dataSource) {
this.dataSource = dataSource;
}
public BasicDataSource getDataSource() {
return dataSource;
}
}
The reason that moving the context:component-scan tags to the application context xml fixed the transactional behavior is: <tx:annotation-driven /> is a post-processor that wraps #Transactional annotated bean methods with an AOP method interceptor which handles transactional behavior. Spring post-processors, only operate on the specific application context they are defined in.
In your case, you have defined the <tx:annotation-driven /> post-processor in the application context, while the beans annotated with #Transactional are in the servlet application context. Thus, the <tx:annotation-driven /> post-processor only operated on the application context beans, not the servlet context beans. When the context:component-scan tags were moved to the application context, then the <tx:annotation-driven /> post-processor wrapped their transactional methods appropriately.
Hope that makes some sense.
[Edit]
What is the difference between the Application Context and a Servlet Context?
What is a Spring post-processor and how does it work?
What is AOP in Spring?

Resources