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.
Requested session ID 2C3459CB61A89AD4108E733AC8A490F3 is invalid
on spring debug log at the time Http 302 received. So I'm guessing it's something related to the httpSession and cookie stored in the browser. But still could not figure out what's actually happening. If you could provide any idea I would be very great full. Thank you very much. – Yasitha ThilakaratneifRequired
instead ofalways
has any effect. – alexmagnusabstract="true"
, hence it shouldn't really have worked. Did you actually remove it previously? – alamar<beans xmlns... /> <bean parent="ignite.cfg"/> </beans>
(example-ignite.xml file) configuration. So it worked. – Yasitha Thilakaratne