I'm trying to develop an application with spring security login functionality while user session is distributed using apache Ignite.
Server: Apache Tomcat 8
Spring version: 4.2.2.RELEASE
Ignite version: 2.1.0
I have two errors in my application.
Logging an exception when logging out from the application. Apart from that session invalidation is done as expected.
12-Aug-2017 14:09:01.580 SEVERE [http-nio-8080-exec-2] org.apache.ignite.logger.java.JavaLogger.error Failed to update web session: null
java.lang.NullPointerException
at org.apache.ignite.cache.websession.WebSessionFilter$RequestWrapperV2.getSession(WebSessionFilter.java:1001)
at org.apache.ignite.cache.websession.WebSessionFilter.doFilterV2(WebSessionFilter.java:564)
at org.apache.ignite.cache.websession.WebSessionFilter.doFilterDispatch(WebSessionFilter.java:407)
at org.apache.ignite.cache.websession.WebSessionFilter.doFilter(WebSessionFilter.java:383)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
When two tomcat servers with same application deployments started up in two different ports, can access login page only from one server.
(If I accessed login page from first server page is loaded fine as expected. But if I tried to access login page from second server again it gives error. However once logged in application worked as expected and could access distributed session from both servers.
First access
Second access from another server
My configuration files are as follows.
Spring context configuration
<beans xmlns.... >
<context:component-scan base-package="test.ignite.spring"/>
<mvc:annotation-driven/>
<context:property-placeholder location="classpath:system.properties" ignore-resource-not-found="true" ignore-unresolvable="true"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:interceptors>
<mvc:interceptor>
<!-- Cache of HTML pages -->
<mvc:mapping path="/**"/>
<bean class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="cacheSeconds" value="0"/>
</bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
Login Controller
#Controller
public class LoginController {
#RequestMapping(value = {"login", "/"})
public String login() {
try {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
return "home";
}
return "login";
} catch (Exception e) {
return "redirect:/error/500";
}
}
#RequestMapping(value = "/home")
public String home() {
return "home";
}
}
----UPDATED----
Ignite configuration (whole file content)
<beans xmlns.... >
<bean abstract="true" id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<!-- Set to true to enable distributed class loading for examples, default is false. -->
<property name="peerClassLoadingEnabled" value="true"/>
<property name="cacheConfiguration">
<list>
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="example"/>
<property name="cacheMode" value="PARTITIONED"/>
</bean>
</list>
</property>
<!-- Enable task execution events for examples. -->
<property name="includeEventTypes">
<list>
<!--Task execution events-->
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_STARTED"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FINISHED"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FAILED"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_TIMEDOUT"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_SESSION_ATTR_SET"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_REDUCED"/>
<!--Cache events-->
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_PUT"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_READ"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_REMOVED"/>
</list>
</property>
<!-- Explicitly configure TCP discovery SPI to provide list of initial nodes. -->
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<!--
Ignite provides several options for automatic discovery that can be used
instead os static IP based discovery. For information on all options refer
to our documentation: http://apacheignite.readme.io/docs/cluster-config
-->
<!-- Uncomment static IP finder to enable static-based discovery of initial nodes. -->
<!--<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">-->
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder">
<property name="addresses">
<list>
<!-- In distributed environment, replace with actual host IP address. -->
<value>127.0.0.1:47500..47509</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
</bean>
Spring security configuration
<beans:beans xmlns.... >
<http auto-config="true" create-session="always" use-expressions="true" >
<form-login login-page="/login" default-target-url="/home" authentication-failure-url="/login?error" username-parameter="username" password-parameter="password" always-use-default-target="true"/>
<logout invalidate-session="true" logout-success-url="/login" delete-cookies="JSESSIONID"/>
<session-management session-fixation-protection="newSession" invalid-session-url="/" session-authentication-error-url="/login">
<concurrency-control session-registry-alias="sessionRegistry" max-sessions="10" expired-url="/" error-if-maximum-exceeded="true"/>
</session-management>
<access-denied-handler error-page="/403"/>
</http>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
</authentication-provider>
</authentication-manager>
</beans:beans>
web.xml
<web-app xmlns... >
<listener>
<listener-class>org.apache.ignite.startup.servlet.ServletContextListenerStartup</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<filter>
<filter-name>IgniteWebSessionsFilter</filter-name>
<filter-class>org.apache.ignite.cache.websession.WebSessionFilter</filter-class>
</filter>
<!-- You can also specify a custom URL pattern. -->
<filter-mapping>
<filter-name>IgniteWebSessionsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-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>
<!-- Specify Ignite configuration (relative to META-INF folder or Ignite_HOME). -->
<context-param>
<param-name>IgniteConfigurationFilePath</param-name>
<param-value>example-ignite.xml</param-value>
</context-param>
<!-- Specify the name of Ignite cache for web sessions. -->
<context-param>
<param-name>IgniteWebSessionsCacheName</param-name>
<param-value>example</param-value>
</context-param>
<!--SERVLETS-->
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mvc-dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:mvc-dispatcher-servlet.xml,
classpath:security-config.xml
</param-value>
</context-param>
</web-app>
I would be very thankful if you could provide any solution / idea to solve problem.
As both of your deployments are on localhost, they're going to share JSESSIONID cookie. So far so good.
However there seems to be a mismatch between Tomcat, Spring Security and Ignite which causes Spring Security to regard sessions coming from Ignite as invalid when they're anonymous (i.e. not logged on). I don't understand yet how this relates to your case where you're supposed to already be logged on.
You can probably use a workaround: Remove invalid-session-url="/" from your Spring Security configuration. This will prevent the redirect looping behavior. This will also cause users to be silently logged off instead to being guided to /login when their cookie expires.
I've deleted my previous answer as it was missing the point.
Related
I need to use Spring-mobile to detect the device. I have seen lot of examples with spring-mobile and spring mvc but none with webflow. Below is a sample webflow, I need to use device detection so I can redirect the page to mobile or table or desktop based on device.
webflow-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xmlns:faces="http://www.springframework.org/schema/faces"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd
http://www.springframework.org/schema/faces
http://www.springframework.org/schema/faces/spring-faces.xsd">
<!-- JSF Specific -->
<!-- A listener maintain one FacesContext instance per Web Flow request. -->
<bean id="facesContextListener"
class="org.springframework.faces.webflow.FlowFacesContextLifecycleListener" />
<!--- Executes flows: the central entry point into the Spring Web Flow system
- -->
<webflow:flow-executor id="flowExecutor">
<webflow:flow-execution-listeners>
<webflow:listener ref="facesContextListener" />
</webflow:flow-execution-listeners>
</webflow:flow-executor>
<!-- The registry of executable flow definitions -->
<webflow:flow-registry id="flowRegistry"
flow-builder-services="flowBuilderServices" base-path="/WEB-INF/flows">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>
<!-- Configures the Spring Web Flow JSF Integration -->
<faces:flow-builder-services id="flowBuilderServices"
development="true" />
<faces:resources />
<bean class="org.springframework.faces.webflow.JsfFlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor" />
</bean>
<bean id="faceletsViewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.faces.mvc.JsfView" />
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".xhtml" />
</bean>
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="order" value="1" />
<property name="flowRegistry" ref="flowRegistry" />
<property name="defaultHandler">
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController" />
</property>
</bean>
<!-- Dispatches requests mapped to org.springframework.web.servlet.mvc.Controller
implementations -->
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
</beans>
flow main
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<view-state id="welcome">
</view-state>
</flow>
Web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>WebFlowSample</display-name>
<!-- - Location of the XML file that defines the root application context.
- Applied by ContextLoaderListener. -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/application-config.xml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
<param-value>1</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Resource mapping -->
<servlet>
<servlet-name>Resources Servlet</servlet-name>
<servlet-class>org.springframework.js.resource.ResourceServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Resources Servlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
<!-- - Servlet that dispatches request to registered handlers (Controller
implementations). -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
<!-- In order for JSF to bootstrap correctly -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
</web-app>
Controller
/**
* Handles requests for the application home page.
*/
#Controller
#RequestMapping("/wb")
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
#RequestMapping("/create/")
public String home(Device device, Model model) {
if (device == null) {
logger.info("no device detected");
} else if (device.isNormal()) {
logger.info("Device is normal");
} else if (device.isMobile()) {
logger.info("Device is mobile");
} else if (device.isTablet()) {
logger.info("Device is tablet");
}
// where main is the flow id for welcome page
return "main";
}
}
Updated:
I need the homecontroller class to call the flow, this is not the right way. But can anyone tell how to call?
(This is a reply to your comment, but too large to be a comment itself.)
In order to add interceptors to Webflow, add them to your FlowHandlerMapping bean definition. Like this:
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
...
<property name="interceptors">
<list>
<bean class="org.springframework.mobile.device.DeviceResolverHandlerInterceptor"/>
</list>
</property>
</bean>
The following is my application-context.xml
<context:component-scan base-package="org.godfather"></context:component-scan>
<mvc:view-controller path="/main.do" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
</bean>
Question:
If I comment out <mvc:view-controller path="/main.do" /> then http://localhost:8181/tiles-app-1.1.1/header.do url is working, but if it is NOT commented out, then the url is not working, getting No mapping found for HTTP request with URI [/tiles-app-1.1.1/header.do] in DispatcherServlet with name 'mytiles' why is it so?
Web.xml
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/application-context.xml
</param-value>
</context-param>
<servlet>
<servlet-name>mytiles</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application-context.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>mytiles</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
Controller
package org.godfather;
#Controller
public class AppointmentController {
#RequestMapping("/header")
public void get() {
System.out.println("get()");
}
Thanks in advance.
You are passing the same Spring Bean definition file (/WEB-INF/application-context.xml) to the ContextLoaderListener and to the DispatcherServlet.
The DispatcherServlet should have its own Spring Bean definition file
See this question. All Spring MVC controllers and specific MVC xml should be in a different file.
I am trying to use Spring MVC 3 and Hibernate 4.1 to get declarative transaction management, providing an open session for the entire length of the request. I only have one "manager" layer for data access, which directly uses the session. This is annotated with #Transactional, and the session closes upon exiting this layer and I get a lazy load exception in the controller.
So I added the OpenSessionInViewFilter filter, and the logs state that this filter is correctly configured and they also show this filter opening a session. Unfortunately, my manager layer opens and closes its own session anyway, just as before, and I get the same lazy load exception in the controller.
Edit: noted that in my log, I get the filter session open, HibernateTransactionManager session open, HibernateTransactionManager session closed, lazy load exception, then filter session closed. So I know that there is an open session somewhere during the lazy load exception, but the object was loaded in a transaction associated with the other, closed session.
I thought that removing #Transactional from the manager class would remove session management from that layer and let the filter do its job, but then the sessionFactory().getCurrentSession() simply gets a closed session; it doesn't have access to the filter's provided open session.
How can I get access to the OpenSessionInViewFilter's clearly open session?
springapp-servlet.xml
<beans ..
<context:component-scan base-package="springapp.web" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<!-- Enables the Spring MVC #Controller programming model -->
<mvc:annotation-driven />
<bean id="userManager" class="springapp.service.SimpleUserManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<import resource="hibernate-context.xml" />
</beans>
web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springapp-servlet.xml</param-value>
</context-param>
<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springapp</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
hibernate-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans ..
">
<context:property-placeholder location="/WEB-INF/hibernate.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${hibernate.connection.driver_class}" />
<property name="url" value="${hibernate.connection.url}" />
<property name="username" value="${hibernate.connection.username}" />
<property name="password" value="${hibernate.connection.password}" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven />
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource" />
</property>
</bean>
<bean id="managerTemplate" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="packagesToScan" value="databeans" />
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
</beans>
manager.java
#Service("userManager")
#Transactional
public class SimpleUserManager implements UserManager {
#Autowired
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
..
controller.java
#Controller
#RequestMapping("/users")
public class UserController {
#Autowired
private UserManager userManager;
..
and my exception, which occurs in the controller, on the first property read of an object loaded in the manager class and passed to that controller:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.LazyInitializationException: could not initialize proxy - no Session
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:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:119)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
I've been researching this for hours.. all I can find is a mix of solutions using hibernate 3 and grainy explanations on hibernate 4 session/transaction theory without examples.
Any thoughts?
UPDATE: FIXED!
Found this:
Spring MVC OpenSessionInViewInterceptor Not Working
which unfortunately has not helped the OP there, but it helped me. Notably, this:
"it will be better to not import applicationContext.xml in dispatcher-servlet.xml, instead load it using a ContextLoaderListener"
which, applied to my configuration, is exactly everything I have posted above, but instead of
<import resource="hibernate-context.xml" />
in my springapp-servlet.xml, I modified my ContextLoaderListener to:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springapp-servlet.xml, /WEB-INF/hibernate-context.xml</param-value>
</context-param>
and that was all it took for
sessionFactory.getCurrentSession()
to return to me the OSIV-created session. And, in fact, the second session that was being created is no longer, as I found these lovely little log lines:
2012-10-04 14:43:48,743 DEBUG http-8080-1 org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
2012-10-04 14:43:48,743 TRACE http-8080-1 org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.hibernate4.SessionHolder#4146c5c0] for key [org.hibernate.internal.SessionFactoryImpl#12542011] bound to thread [http-8080-1]
2012-10-04 14:43:48,743 DEBUG http-8080-1 org.springframework.orm.hibernate4.HibernateTransactionManager - Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
2012-10-04 14:43:48,743 DEBUG http-8080-1 org.springframework.orm.hibernate4.HibernateTransactionManager - Creating new transaction with name [springapp.service.SimpleUserManager.find]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
which show that, outside of my #Transactional service layer, the OSIV-created session was alive and well, and a new transaction was simply started for it.
Hope this helps someone else. I don't even want to think about how many hours I spent working on it.
I'm stuck in this issue for a long time. I want to use #Secure to add Access Control to my controller ArticleController.java like this:
#RequestMapping(headers = "Accept=application/json")
#ResponseBody
#Secured("ROLE_ADMIN")
public ResponseEntity<String> listJson() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
List<Article> result = Article.findAllArticles();
return new ResponseEntity<String>(Article.toJsonArray(result), headers, HttpStatus.OK);
}
listJson return a Json object for Articles but only Admin can read them. OK now I configure the Spring-Security to make this work.
I use security setup function of Spring-ROO, the following configures generated:
In web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
....
<servlet>
<servlet-name>BabyPortal</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
In spring/webmvc-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-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 http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<tx:annotation-driven/>
<!-- The controllers are autodetected POJOs labeled with the #Controller
annotation. -->
<context:component-scan base-package="com.tongxinyuan.babyportal"
use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<!-- Turns on support for mapping requests to Spring MVC #Controller methods
Also registers default Formatters and Validators for use across all #Controllers -->
<mvc:annotation-driven conversion-service="applicationConversionService" />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources -->
<mvc:resources location="/, classpath:/META-INF/web-resources/"
mapping="/resources/**" />
<!-- Allows for mapping the DispatcherServlet to "/" by forwarding static
resource requests to the container's default Servlet -->
<mvc:default-servlet-handler />
<!-- Register "global" interceptor beans to apply to all registered HandlerMappings -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
p:paramName="lang" />
</mvc:interceptors>
<!-- Selects a static view for rendering without the need for an explicit
controller -->
<mvc:view-controller path="/login" />
<mvc:view-controller path="/" view-name="index" />
<mvc:view-controller path="/uncaughtException" />
<mvc:view-controller path="/resourceNotFound" />
<mvc:view-controller path="/dataAccessFailure" />
<!-- Resolves localized messages*.properties and application.properties
files in the application to allow for internationalization. The messages*.properties
files translate Roo generated messages which are part of the admin interface,
the application.properties resource bundle localizes all application specific
messages such as entity names and menu items. -->
<bean
class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
id="messageSource" p:basenames="WEB-INF/i18n/messages,WEB-INF/i18n/application"
p:fallbackToSystemLocale="false" />
<!-- Store preferred language configuration in a cookie -->
<bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
id="localeResolver" p:cookieName="locale" />
<!-- Resolves localized <theme_name>.properties files in the classpath to
allow for theme support -->
<bean
class="org.springframework.ui.context.support.ResourceBundleThemeSource"
id="themeSource" />
<!-- Store preferred theme configuration in a cookie -->
<bean class="org.springframework.web.servlet.theme.CookieThemeResolver"
id="themeResolver" p:cookieName="theme" p:defaultThemeName="standard" />
<!-- This bean resolves specific types of exceptions to corresponding logical
- view names for error views. The default behaviour of DispatcherServlet
- is to propagate all exceptions to the servlet container: this will happen
- here with all other types of exceptions. -->
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
p:defaultErrorView="uncaughtException">
<property name="exceptionMappings">
<props>
<prop key=".DataAccessException">dataAccessFailure</prop>
<prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
<prop key=".TypeMismatchException">resourceNotFound</prop>
<prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
</props>
</property>
</bean>
<!-- Enable this for integration of file upload functionality -->
<bean
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
id="multipartResolver" />
<bean
class="com.tongxinyuan.babyportal.controller.ApplicationConversionServiceFactoryBean"
id="applicationConversionService" />
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"
id="tilesViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles2.TilesView" />
</bean>
<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"
id="tilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/layouts/layouts.xml</value>
<!-- Scan views directory for Tiles configurations -->
<value>/WEB-INF/views/**/views.xml</value>
</list>
</property>
</bean>
<security:global-method-security mode="aspectj" secured-annotations="enabled" pre-post-annotations="enabled"/>
</beans>
In /spring/applicationContext-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<!-- HTTP security configurations -->
<http auto-config="true" use-expressions="true">
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" />
<logout logout-url="/resources/j_spring_security_logout" />
<!-- Configure these elements to secure URIs in your application -->
<intercept-url pattern="/choices/**" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/member/**" access="isAuthenticated()" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/*.html" access="hasRole('ROLE_ADMIN')" />
</http>
<!-- Configure Authentication mechanism -->
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_ADMIN" />
<user name="user" password="user" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Firstly I tried adding the <global-method-security mode="aspectj" secured-annotations="enabled" pre-post-annotations="enabled"/> to /spring/applicationContext-security.xml but didn't work. Then maybe the the controller is not in the same context of security context, so I add the to /spring/webmvc-config.xml which started with DispatcherServlet, didn't work.
I also added to another default applicationContext.xml, it didn't work either. I don't know how to configure the <global-method-security> that can make the method security work. It seems I only use one context, did I miss something? Hope the information is enough to make this issue clear.
PS: The generated URL method works very well: <intercept-url pattern="/*.html" access="hasRole('ROLE_ADMIN')" />.
Added:
According to #LukeTaylor 's comments: I added the <global-method-security> to webmvc-config.xml and removed the mode="aspectj", it works, and I did some experiments, still have some questions:
1) It works but only for ArticleController.java, the #Secure tag in ArticleController_Roo_Controller.aj still don't work, is that something related to "waving"?
2) Can you explain to me why mode=aspectj make it mess here?
As suggested by #Luke Taylor in the comments the tag <sec:global-method-security/> needs to be defined in the dispatcher-servlet.xml(webmvc-config.xml in this case) file. And there is no need to have attribute mode="aspectj".
Thanks.
I am trying to integrate Spring Security in my extjs project,but encountered the following error.
The entire stacktrace is.
SEVERE: Exception starting filter springSecurityFilterChain
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:510)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1056)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:274)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1049)
at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:217)
at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:145)
at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:179)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:269)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:250)
at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:368)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:98)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4211)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4837)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1028)
at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:773)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1028)
at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:278)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
at org.apache.catalina.core.StandardService.startInternal(StandardService.java:429)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:662)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:140)
at org.apache.catalina.startup.Catalina.start(Catalina.java:592)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:290)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:418)
Apr 30, 2012 1:05:00 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: Error filterStart
My web.xml is as follows
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>extjs-crud-grid-spring-hibernate</display-name>
<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>
<listener>
<listener- class>org.springframework.web.context.ContextLoaderListener</listener- class>
</listener>
<servlet>
<servlet-name>extjs-crud-grid-spring-hibernate</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/applicationContext-security.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>extjs-crud-grid-spring-hibernate</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
applicationContext.xml is
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<!-- Annotated controller beans may be defined explicitly, using a standard Spring bean definition in the
dispatcher's context. However, the #Controller stereotype also allows for autodetection, aligned with Spring 2.5's
general support for detecting component classes in the classpath and auto-registering bean definitions for them. -->
<context:component-scan base-package="com.loiane" />
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<!-- misc -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- Configures Hibernate - Database Config -->
<import resource="db-config.xml" />
applicationContext-security.xml
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
<security:global-method-security />
<security:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint">
<security:intercept-url pattern="/index.jsp" filters="none" />
<security:intercept-url pattern="/*.action" access="ROLE_USER" />
</security:http>
<bean id="authenticationProcessingFilter" class="com.loiane.security.MyAuthenticationProcessingFilter">
<security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />
<property name="defaultTargetUrl" value="/index.jsp" />
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<security:authentication-manager alias="authenticationManager" />
<bean id="authenticationProcessingFilterEntryPoint"
class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/index.jsp" />
<property name="forceHttps" value="false" />
</bean>
<!--
Usernames/Passwords are
rod/koala
dianne/emu
scott/wombat
peter/opal
These passwords are from spring security app example
-->
<security:authentication-provider>
<security:password-encoder hash="md5"/>
<security:user-service>
<security:user name="options" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</beans>
I have referred other threads but with no solution.
Can someone correct me where is the problem in the configuration?
Thanks for the time.
EDIT:
A new issue is with mapping.
Here is my controller class.I have my web.xml above.I am using SPring Security.
I am not able to navigate to the main.jsp after successful login.I have added the #RequestMapping annotation above the method.
Controller Class
#Controller
public class ContactController extends MultiActionController {
private ContactService contactService;
#RequestMapping(value="/contact/main.action")
public ModelAndView main(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("main.jsp");
}
#RequestMapping(value="/contact/view.action")
public #ResponseBody Map<String,? extends Object> view() throws Exception {
try{
List<Contact> contacts = contactService.getContactList();
return getMap(contacts);
} catch (Exception e) {
return getModelMapError("Error retrieving Contacts from database.");
}
}
#RequestMapping(value="/contact/create.action")
public #ResponseBody Map<String,? extends Object> create(#RequestParam Object data) throws Exception {
try{
List<Contact> contacts = contactService.create(data);
return getMap(contacts);
} catch (Exception e) {
return getModelMapError("Error trying to create contact.");
}
}
About the issue with the controller: you actually don't have a mapping for
/extjs-crud-grid-spring-hibernate/main.action
What you are mapping in that controller is, for example:
/extjs-crud-grid-spring-hibernate/contact/main.action
If you need to access the first URI you should remove "contact" from the controller and only map it with "/main.action".
About Spring Security, I'm sure that this tutorial is useful (or almost any that you can find googling), but if you really want to learn about it, I strongly recommend the Spring books: Spring recipes and Spring Security 3.
try instead of:
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/applicationContext-security.xml
</param-value>
to do the following in /WEB-INF/applicationContext.xml:
<import resource="applicationContext-security.xml"/>
I was getting same issue. I tried security:intercept-url pattern="/**" access="ROLE_USER"
Remove criteria on pattern, my problem has been solved. Spring security itself append /spring_security_login url and provide it's login page.
Try it...