Giter Club home page Giter Club logo

hazelcast-wm's Introduction

Table of Contents

Filter Based Web Session Replication

Sample Code: Please see our sample application for Filter Based Web Session Replication.

You can also check Hazelcast Guides: Session Replication with Spring Boot and Hazelcast.

Note: Hazelcast 5.0+ is compatible with Hazelcast-WM 5.0. For older Hazelcast versions, use the latest Hazelcast-WM 3.x.x or 4.x.x releases.

Assume that you have more than one web server (A, B, C) with a load balancer in front of it. If server A goes down, your users on that server will be directed to one of the live servers (B or C), but their sessions will be lost.

We need to have all these sessions backed up somewhere if we do not want to lose the sessions upon server crashes. Hazelcast Web Manager (WM) allows you to cluster user HTTP sessions automatically.

Session Clustering Requirements

The following are required before you can enable Hazelcast Session Clustering:

  • Target application or web server should support Java 1.8 or higher.

  • Target application or web server should support Servlet 4.0 or higher spec. Note that this library supports, "javax" namespace, not the new "jakarta" one.

  • Session objects that need to be clustered have to be Serializable.

  • In the client/server architecture, session classes do not have to be present in the server classpath.

Setting Up Session Clustering

To set up Hazelcast Session Clustering:

  • Put the hazelcast and hazelcast-wm jars in your WEB-INF/lib folder. Optionally, if you wish to connect to a cluster as a client, add hazelcast-client as well.

  • Put the following XML into the web.xml file. Make sure Hazelcast filter is placed before all the other filters if any; you can put it at the top.

<filter>
  <filter-name>hazelcast-filter</filter-name>
  <filter-class>com.hazelcast.web.WebFilter</filter-class>

  <init-param>
    <param-name>map-name</param-name>
    <param-value>my-sessions</param-value>
  </init-param>
  <init-param>
    <param-name>session-ttl-seconds</param-name>
    <param-value>10</param-value>
  </init-param>
  <init-param>
      <param-name>keep-remote-active</param-name>
      <param-value>false</param-value>
  </init-param>
  <init-param>
    <param-name>sticky-session</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>cookie-name</param-name>
    <param-value>hazelcast.sessionId</param-value>
  </init-param>
  <init-param>  
    <param-name>cookie-domain</param-name>
    <param-value>.mywebsite.com</param-value>
  </init-param>
  <init-param>  
    <param-name>cookie-secure</param-name>
    <param-value>false</param-value>
  </init-param>
  <init-param>  
    <param-name>cookie-http-only</param-name>
    <param-value>false</param-value>
  </init-param>
  <init-param>  
    <param-name>config-location</param-name>
    <param-value>/WEB-INF/hazelcast.xml</param-value>
  </init-param>
  <init-param>  
    <param-name>instance-name</param-name>
    <param-value>default</param-value>
  </init-param>
  <init-param>  
    <param-name>use-client</param-name>
    <param-value>false</param-value>
  </init-param>
  <init-param>  
    <param-name>client-config-location</param-name>
    <param-value>/WEB-INF/hazelcast-client.xml</param-value>
  </init-param>
  <init-param>  
    <param-name>shutdown-on-destroy</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>  
    <param-name>deferred-write</param-name>
    <param-value>false</param-value>
  </init-param>
  <init-param>
    <param-name>cookie-path</param-name>
    <param-value>/</param-value>
  </init-param>
  <init-param>
      <param-name>cookie-max-age</param-name>
      <param-value>-1</param-value>
    </init-param>
  <init-param>
    <param-name>use-request-parameter</param-name>
    <param-value>false</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>hazelcast-filter</filter-name>
  <url-pattern>/*</url-pattern>
  <dispatcher>FORWARD</dispatcher>
  <dispatcher>INCLUDE</dispatcher>
  <dispatcher>REQUEST</dispatcher>
</filter-mapping>

<listener>
  <listener-class>com.hazelcast.web.SessionListener</listener-class>
</listener>
  • Package and deploy your war file as you would normally do.

It is that easy. All HTTP requests will go through Hazelcast WebFilter and this WebFilter will put the session objects into the Hazelcast distributed map when needed.

Following are the descriptions of parameters included in the above XML.

  • map-name: Name of the distributed map storing your web session objects.
  • session-ttl-seconds: Time-to-live value (in seconds) of the distributed map storing your web session objects. It can be any integer between 0 and Integer.MAX_VALUE. Its default value is 1800, which is 30 minutes.
  • sticky-session: If set to true, all requests of a session are routed to the member where the session is first created. This provides better performance. If set to false, when a session is updated on a member, entry for this session on all members is invalidated. You have to know how your load balancer is configured before setting this parameter. Its default value is true.
  • keep-remote-active: If set to true, it's guaranteed that whenever a session is used the idle-time of this session on the distributed map is reset. The cluster map is already notified for all modification operations but this option might be required when consecutive read-attribute operations are performed without any modification. Since these attributes will be fetched from the local cache (for sticky sessions), the session on the distributed map might be evicted even if the session is active. Note that this is useless when non-sticky sessions are used or max-idle-second is not set for the cluster map. Its default value is false.
  • cookie-name: Name of the session ID cookie.
  • cookie-domain: Domain of the session ID cookie. Its default value is based on the incoming request.
  • cookie-path: Path of the session ID cookie. Its default value is based on the context path of the incoming request.
  • cookie-secure: Specifies whether the cookie only be sent using a secure protocol. Its default value is false.
  • cookie-http-only: Specifies whether the attribute HttpOnly can be set on cookie. Its default value is false.
  • cookie-max-age: Specifies the maximum age of the cookie in seconds. Its default value is -1, meaning the cookie is not stored persistently and will be deleted when the browser exits.
  • config-location: Location of Hazelcast configuration. It can be specified as a servlet resource, classpath resource or as a URL. Its default value is hazelcast-default.xml or hazelcast.xml in the classpath.
  • instance-name: Name of an existing Hazelcast instance, if you want to use it. Its default value is null. If you do not have an instance, then you should create one.
  • use-client: Specifies whether you want to connect to an existing cluster as a client. Its default value is false.
  • client-config-location: Location of the client's configuration. It can be specified as a servlet resource, classpath resource or as a URL. Its default value is null.
  • shutdown-on-destroy: Specifies whether you want to shut down the Hazelcast instance during the undeployment of your web application. Its default value is true.
  • deferred-write: Specifies whether the sessions in each instance will be cached locally. Its default value is false.
  • use-request-parameter: Specifies whether a request parameter can be used by the client to send back the session ID value. Its default value is false.

Using High-Density Memory Store

Hazelcast Enterprise HD

As you see in the above declarative configuration snippet, you provide the name of your map which will store the web session objects:

<init-param>
   <param-name>map-name</param-name>
   <param-value>my-sessions</param-value>
</init-param>

If you have Hazelcast Enterprise HD, you can configure your map to use Hazelcast's High-Density Memory Store. By this way, the filter based web session replication will use a High-Density Memory Store backed map.

Please refer to the Using High-Density Memory Store with Map section to learn how you can configure a map to use this feature.

Supporting Spring Security

Sample Code: Please see our sample application for Spring Security Support.

If Spring based security is used for your application, you should use com.hazelcast.web.spring.SpringAwareWebFilter instead of com.hazelcast.web.WebFilter in your filter definition.

...

<filter>
  <filter-name>hazelcast-filter</filter-name>
  <filter-class>com.hazelcast.web.spring.SpringAwareWebFilter</filter-class>
    ...
</filter> 

...

SpringAwareWebFilter notifies Spring by publishing events to Spring context. The org.springframework.security.core.session.SessionRegistry instance uses these events.

As before, you must also define com.hazelcast.web.SessionListener in your web.xml. However, you do not need to define org.springframework.security.web.session.HttpSessionEventPublisher in your web.xml as before, since SpringAwareWebFilter already informs Spring about session based events like create or destroy.

Client Mode vs. P2P Mode

Hazelcast Session Replication works as P2P by default. To switch to Client/Server architecture, you need to set the use-client parameter to true. P2P mode is more flexible and requires no configuration in advance; in Client/Server architecture, clients need to connect to an existing Hazelcast Cluster. In case of connection problems, clients will try to reconnect to the cluster. The default retry count is 3. In the client/server architecture, if servers goes down, Hazelcast web manager will keep the updates in the local and after servers come back, the clients will update the distributed map.

Note that, in the client/server mode of session replication, session-ttl-seconds configuration does not have any effect. The reason is that the filter based session replication uses IMap and a Hazelcast client cannot change the configuration of a distributed map. Instead, you should configure the max-idle-seconds element in your hazelcast.xml on the server side.

...
  <map name="my-sessions">
        <!--
           How many seconds do you want your session attributes to be stored on server?
           Default is 0.
         -->
       <max-idle-seconds>20</max-idle-seconds>
  </map>
...

Also make sure that name of the distributed map is same as the map-name parameter defined in your web.xml configuration file.

Caching Locally with deferred-write

If the value for deferred-write is set as true, Hazelcast will cache the session locally and will update the local session when an attribute is set or deleted. At the end of the request, it will update the distributed map with all the updates. It will not update the distributed map upon each attribute update, but will only call it once at the end of the request. It will also cache it, i.e. whenever there is a read for the attribute, it will read it from the cache.

Updating an attribute when deferred-write=false:

If deferred-write is false, any update (i.e. setAttribute) on the session will directly be available in the cluster. One exception to this behavior is the changes to the session attribute objects. To update an attribute cluster-wide, setAttribute must be called after changes are made to the attribute object.

The following example explains how to update an attribute in the case of deferred-write=false setting:

session.setAttribute("myKey", new ArrayList());
List list1 = session.getAttribute("myKey");
list1.add("myValue"); 
session.setAttribute("myKey", list1); // changes updated in the cluster

SessionId Generation

SessionId generation is done by the Hazelcast Web Session Module if session replication is configured in the web application. The default cookie name for the sessionId is hazelcast.sessionId. This name is configurable with a cookie-name parameter in the web.xml file of the application. hazelcast.sessionId is just a UUID prefixed with “HZ” characters and without a “-“ character, e.g. HZ6F2D036789E4404893E99C05D8CA70C7.

When called by the target application, the value of HttpSession.getId() is the same as the value of hazelcast.sessionId.

Defining Session Expiry

Hazelcast automatically removes sessions from the cluster if sessions are expired on the Web Container. This removal is done by com.hazelcast.web.SessionListener, which is an implementation of javax.servlet.http.HttpSessionListener. Session is not removed instantly because it might be active in other nodes of the cluster. It's done after the period of time specified by session-ttl-seconds on WebFilter passes (or max-idle-seconds element in your hazelcast.xml on the server side if client/server mode is used).

Default session expiration configuration depends on the Servlet Container that is being used. You can also define it in your web.xml.

    <session-config>
        <session-timeout>60</session-timeout>
    </session-config>

Using Sticky Sessions

Hazelcast holds whole session attributes in a distributed map and in a local HTTP session. Local session is required for fast access to data and distributed map is needed for fail-safety.

  • If sticky-session is not used, whenever a session attribute is updated in a member (in both member local session and clustered cache), that attribute should be invalidated in all other members' local sessions, because now they have dirty values. Therefore, when a request arrives at one of those other members, that attribute value is fetched from clustered cache.

  • To overcome the performance penalty of sending invalidation messages during updates, you can use sticky sessions. If Hazelcast knows sessions are sticky, invalidation will not be sent because Hazelcast assumes there is no other local session at the moment. When a server is down, requests belonging to a session hold in that server will routed to other server, and that server will fetch session data from clustered cache. That means that when using sticky sessions, you will not suffer the performance penalty of accessing clustered data and can benefit recover from a server failure.

Marking Transient Attributes

If you have some attributes that you do not want to be distributed, you can mark those attributes as transient. Transient attributes are kept in the server and when the server is shutdown, you lose the attribute values. You can set the transient attributes in your web.xml file. Here is an example:

...
   <init-param>
            <param-name>transient-attributes</param-name>
            <param-value>key1,key2,key3</param-value>
   </init-param>
...

Using Request Parameter Instead of Cookie for Sending Back the Session ID

If you have a Servlet that serves REST style POST requests and you don't want the clients to use cookies for sending back the session ID, you can enable use-request-parameter setting and clients can send back the session ID as a request parameter. You can enable it in your web.xml file:

...
   <init-param>
            <param-name>use-request-parameter</param-name>
            <param-value>true</param-value>
   </init-param>
...

Note that this causes Hazelcast's WebFilter to consume the ServletRequest#getInputStream (as it needs to examine request parameters) so it will not be available to any servlet that is filtered by this WebFilter.

Upgrading from v4.0

There is a guide available to help you upgrade your hazelcast-wm from v4.0 to v5.0. You can find it here.

hazelcast-wm's People

Contributors

ahmetmircik avatar akoledzhikov avatar asimarslan avatar bilalyasar avatar cszmajda avatar dependabot[bot] avatar devopshazelcast avatar donnerbart avatar dpocock avatar emrahkocaman avatar emre-aydin avatar enozcan avatar fuadm avatar fwassmer avatar hasancelik avatar jackpgreen avatar jerrinot avatar jhinch-at-atlassian-com avatar kaaloo avatar kulchytskyy avatar kwart avatar mdogan avatar metanet avatar mheemskerk avatar mst-appear avatar noctarius avatar pveentjer avatar serdaro avatar somannadc avatar srknzl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hazelcast-wm's Issues

Sessions is created for every request even when getSession(false) is called

Following issue has been created by @nkrijnen
Original Link : hazelcast/hazelcast#8549

The getSession method in WebFilter.RequestWrapper does not respect the boolean create parameter. As you can see, the parameter is not used anywhere in the method:

        @Override
        public HazelcastHttpSession getSession(final boolean create) {
            hazelcastSession = readSessionFromLocal();
            if (hazelcastSession == null) {
                hazelcastSession = getOrCreateHazelcastSession();
            }
            return hazelcastSession;
        }

https://github.com/hazelcast/hazelcast/blob/v3.6.3/hazelcast-wm/src/main/java/com/hazelcast/web/WebFilter.java#L460

We are currently using Hazelcast version 3.6.3.
This piece of code is identical in the latest master:

https://github.com/hazelcast/hazelcast-wm/blob/master/src/main/java/com/hazelcast/web/WebFilter.java#L473

Expected behavior

The javadoc for javax.servlet.http.HttpServletRequest#getSession(boolean) describes the expected behavior:

create - true to create a new session for this request if necessary; false to return null if there's no current session

Why is this a problem?

For most request, our software does not require a session, so we make sure to only call getSession(true) when the authentication requires a session. In all other cases we require correct Servlet-spec behavior for getSession(false). Hazelcast is now forcing a new session to be created with every request, which causes massive amounts of sessions that are not needed. All these sessions drain resources and cause server to slow down, even break.

Session issues with Spring

Hazelcast WM 3.7.1

We have discovered two issues when using Hazelcast wm with Spring.

1. Session fixation vulnerability

Say you visit the login page of a server. After this initial request two cookies are provided: the JSession ID (or 'Tomcat Session ID' as it is referred to in my patch) and the Hazelcast session ID. If the JSession ID is then modified (to be made incorrect) or removed from the client and then you authenticate with the server when the original Hazelcast session will not be destroyed.

2. Stale cached hazelcast session issue

Say you have two server nodes behind a load balancer. Prior to authentication you have a request handled by both nodes so that each one has the initial hazelcast session ID cached locally against a JSession ID. Say node '1' performs the authentication of a login request. When a request is next sent to node '2' it will attempt to use the locally cached hazelcast session ID which was mapped to the JSession ID to the initial request to node '2'. The observed effect of this is that the request to node '2' will fail as it is not authenticated.

I have provided a patch to the SpringAwareWebFilterTest for the two scenarios above.

SpringAwareWebFilterTest.java.patch.zip

Session hijack potential

If access is made with a JSESSIONID and hazelcast.sessionId pairing, it is not validated that these are associated with each other. This gives the potential to access someone else's session.

Changing session id upon login with Spring (session fixation protection)

Hi,

I'm trying to set up session clustering with my Spring Security application.
I configured SpringAwareWebFilter, SessionListener and SessionRegistry.

Session clustering works but I am not able to set up proper session fixation protection. I want to force changing session id on login but my Hazelcast's session id never change with Hazelcast 3.6.2.
I managed to get desired behavior with version 3.4.1.

After some debugging, it seems to me that there is no appropriate code in WebFilter 3.6.2 - after successful login old session got invalidated but new session is created with old id that is cached in SessionRegistry - clusteredSessionId attribute. With 3.4.1 version there is a code that calls creation of new session by passing null as session id (so new one is generated).

I tried this on different environments: Tomcat 7 and 8, embedded Tomcat (using Spring Boot), XML config, Java config.. In general, I want to use latest stable versions of tools like Spring, Spring Boot etc.

[Test-Failure] TomcatClientFailOverTest.whenClusterIsDown_enabledDeferredWrite

org.junit.ComparisonFailure: expected:<[value]> but was:<[null]>
	at org.junit.Assert.assertEquals(Assert.java:115)
	at org.junit.Assert.assertEquals(Assert.java:144)
	at com.hazelcast.wm.test.WebFilterClientFailOverTests.whenClusterIsDown_enabledDeferredWrite(WebFilterClientFailOverTests.java:49)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at com.hazelcast.test.DumpBuildInfoOnFailureRule$1.evaluate(DumpBuildInfoOnFailureRule.java:37)
	at com.hazelcast.test.jitter.JitterRule$1.evaluate(JitterRule.java:104)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at com.hazelcast.wm.test.WebTestRunner.run(WebTestRunner.java:64)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.createRequestAndRun(JUnitCoreWrapper.java:108)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.executeEager(JUnitCoreWrapper.java:78)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.execute(JUnitCoreWrapper.java:54)
	at org.apache.maven.surefire.junitcore.JUnitCoreProvider.invoke(JUnitCoreProvider.java:144)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)

https://hazelcast-l337.ci.cloudbees.com/job/WM-master-freestyle/301/testReport/junit/com.hazelcast.wm.test/TomcatClientFailOverTest/whenClusterIsDown_enabledDeferredWrite_Executing__client___deferred_/

JvmRoute is not updated after HttpSession failover

From @cmuramoto on October 19, 2014 18:36

Hello!

On my journey to migrate Terracotta Sessions to Hazelcast's I noticed one small difference during session failover: the jvmRoute appended to the JSESSIONID cookie does not get replaced when using Hazelcast.

The failover works fine, however since the jvmRoute does not change, Apache will keep trying to access the dead node and since it can't, it will end up routing the request to another available node, which kills session affinity!

My test scenario:

  1. JBoss Instances (2 nodes, old, 4.3, jvmRoutes web-01 and web-02)
  2. App deployed with Hazelcast 3.3.1
  3. Apache (1 node, mod_jk 1.2.28)

Steps to reproduce:

  1. Have both Applications and Apache running
  2. Log In into the application, then note the jsessionId, e.g., xyzw.web-01
  3. Kill the node whose session has affinity with (web-01)
  4. Continue using the application
  5. Check that failover works (OK!), however the JSESSIONID cookie keeps pointing to the dead node
  6. Check that Apache keeps trying to access the dead node (e.g. via jkstatus)

I wasn't able to perform load tests yet, however I believe the cluster will be degraded not only due to a member failure, but also due to loss session affinity, and probably this might lead to bugs if WebFilter is configured with

<init-param>
            <param-name>sticky-session</param-name>
            <param-value>true</param-value>
</init-param>

I used to believe that the container was the one be responsible for updating the cookie, but at least in this version of JBoss this is not working. :( Upon further investigation I noticed that Terracotta has some logic to guard against 'server hops' (session migration) and they do so by forcing cookie updates:

//Code from TerracottaSessionManager
private void writeCookieIfHop(HttpServletRequest req, HttpServletResponse res, SessionId id) {
    if (id.isServerHop()) {
      Cookie cookie = this.cookieWriter.writeCookie(req, res, id);
      if (this.debugSessions)
        this.logger.info("writing new cookie for hopped request: " + getCookieDetails(cookie));
    }
  }

And apparently, according to Hazelcast docs, this should be handled by the framework as well:

"...As jvmRoute parameter of session ID is different than that of target Tomcat instance, Hazelcast Session Replication Module updates the session ID of the session with the new jvmRoute parameter..."

However I could not find anything related in the hazelcast-wm module to cope with session migration. Perhaps the doc is referring to the Valve-based (enterprise) solution?

Anyway, I ended up solving my problem with the following piece of code:

private void fixJVMRoute(HttpServletRequest request, HttpServletResponse response) {
        //JVM_ROUTE is set as a System Property, which is picked up by JBoss and reflected in server.xml
        if (JVM_ROUTE != null) {
            Cookie cookie = request.getCookie("JSESSIONID");
            String value;

            if (cookie != null && (value = cookie.getValue()) != null && !value.endsWith(JVM_ROUTE)) {
                cookie.setPath("/");

                final int ix = value.lastIndexOf('.');

                if (ix > 0) {
                    cookie.setValue(value.substring(0, ix + 1) + JVM_ROUTE);
                } else {
                    cookie.setValue(value + "." + JVM_ROUTE);
                }

                response.addCookie(cookie);
            }
        }
    }

Another possible solution to this issue would be marking set_session_cookie=True in the Apache Load Balancer config, however I wasn't able to test it because this property is available only on mod_jk 1.2.38 onwards and I'm using 1.2.28.

I don't know if this is a enterprise-only feature, but if that's the case, it would be nice to warn open-source users about this particular detail!

Copied from original issue: hazelcast/hazelcast#3890

Options to dynamically configure WebFilter

In order to configure the WebFilter from a subclass there is a constructor allowing to pass properties which will take precedence over the FilterConfig properties ; this is fine when your are able to build at construction time the Properties object. Proxying or changing the FilterConfig is not possible since the init method is marked final.

It would be nice to allow for a more dynamic version ; probably exposing a protected Properties getProperties(FilterConfig config) method would be enough. This way one could override WebFilter and still be able to use for example CDI injected features in order to override the properties.
With the above proposal, subclasses can benefit from the FilterConfig & thus ServletContext to behave differently and to populate accordingly the Properties.

Does it make sense to add such a protected method or are there other ways to achieve such a dynamic behavior?

Show serialization errors

If something to be serialized throws an exception because it is not serializable then this exception is swallowed up and nothing is logged.

If this happens there should be some output to the log.

See the catch block in com.hazelcast.web.HazelcastHttpSession.setAttribute(String, Object)

Property names are private

In https://github.com/hazelcast/hazelcast-wm/blob/master/src/main/java/com/hazelcast/web/WebFilterConfig.java#L47 the property names are private strings

Means we have to do

    properties.put("use-client", "true");

If we could do

    properties.put(WebFilterConfig.USE_CLIENT, "true");

then it's less error prone.

This would be consistent with the approach of the main Hazelcast codebase, such as https://github.com/hazelcast/hazelcast/blob/master/hazelcast/src/main/java/com/hazelcast/spi/properties/GroupProperty.java#L64

How to set cookie Max-Age and path using WebFilter

Moved from hazelcast/hazelcast#2626


I need cookie Max-Age and path not default.

Looking at the code, cannot find any getParam. (WebFilter.java line.183)

private void initCookieParams() {
    String cookieName = getParam("cookie-name");
    if (cookieName != null) {
        sessionCookieName = cookieName;
    }
    String cookieDomain = getParam("cookie-domain");
    if (cookieDomain != null) {
        sessionCookieDomain = cookieDomain;
    }
    String cookieSecure = getParam("cookie-secure");
    if (cookieSecure != null) {
        sessionCookieSecure = Boolean.valueOf(cookieSecure);
    }
    String cookieHttpOnly = getParam("cookie-http-only");
    if (cookieHttpOnly != null) {
        sessionCookieHttpOnly = Boolean.valueOf(cookieHttpOnly);
    }
}

still more hard coding Max-Age (WebFilter.java line.330)

sessionCookie.setMaxAge(-1);

Session ID management error by Hazelcast 3.5 Filter based replication

This issue is a copy of hazelcast/hazelcast#5660

After a logout request that invalidates the session and setMaxAge(0) on JSESSIONID cookie, a 500 HTTP error is raised at the next logging request (checked on FireFox and on IE). This NPE is raised with the 3.5 edition but not with the 3.5 Early Access version. The difference is that the Early Access edition generates a new session Id but the Hazelcast 3.5 version keeps the previous Id of the invalidated session.

Filter based Web session replication by Hazelcast 3.5 or 3.5 EA
Server version: Apache Tomcat/8.0.17
OS Name: Linux
Java version: 1.7.0_60-b19

Note: code and logs are available but support by this issue interface.

SessionState misses creation time

The SessionState object does not include the Creation Time or Last Accessed Time attributes

If the session isn't sticky and another Hazelcast client accesses the session, it gets the wrong value for creation time

Might be related to #44

Allow WebFilter configuration parameters to be set in both FilterConfig and properties

It is convenient to configure WebFilter in both web.xml

   <init-param>
      <param-name>sticky-session</param-name>
      <param-value>false</param-value>
   </init-param>
   <init-param>
      <param-name>cookie-name</param-name>
      <param-value>hazelcast.sessionId</param-value>
   </init-param>

and Spring bean

  <bean id="sessionsReplicationFilter" class="com.hazelcast.web.spring.SpringAwareWebFilter">
    <constructor-arg index="0">
      <props>
        <prop key="config-location">${session.hazelcast.config}</prop>
      </props>
    </constructor-arg>
  </bean>

Recently I upgraded hazelcast-wm from 3.7.1 to 3.8 and discovered that parameters from web.xml are ignored. Quick investigation shows that getValue-method https://github.com/hazelcast/hazelcast-wm/blob/master/src/main/java/com/hazelcast/web/WebFilterConfig.java#L254 missing containsKey-check that we had early in ff07d03#diff-f623257421f1eeeee37dadb8a93459c2L397
Are any reasons to skip filter parameters if properties were initialized or it was just missed during refactoring?

Sessions are invalidated when idle timeout is set altough there is active comm between client and server

Hi!

I run into a problem, where I used WebFilter to put sessions into a cluster map. I set 3600 seconds (1 hour) idle time on the map. Everything was working correctly until I discovered, that despite the client was communicating continuously with the server, the hazelcast sessions were removed after 1 hour from the session map, making a migration from one node to another impossible (I use sticky session, but when a node fails (or I stop it) it forces the user to reauthenticate since the session information is already gone from the session map).

During testing and monitoring the map entries with hazelcast management center I discovered, that after the first session initialization and login the session is not accessed any more in the cluster map (no get/put operations), so after 1 hour (in my test 3 minutes) the session was removed from the session map because of idle time expired. I checked the WebFilter code, and discovered, that actually it uses some kind of internal cache (local cache) to access hazelcast sessions, so normally with sticky session the session on the cluster map is never accessed again, so it can expire.

Extension: my app does not really store huge informations on the session attribute map, so this is why it is not written and read continuously, the session attribute is only storing basic spring authentication data, and such things.

Now I managed to overcame the problem to add a custom filter, which simply increases a request counter in the session attribute map at every request and so I managed to trigger put operation on the cluster session map to update the session cluster-wide, which reset the idle timer, so the session is not getting evicted from the cluster map.

However would be good to get it working without such a hack, so WebFilter should also access the cluster session from the cluster instead of getting it from a local cache, or at least notify somehow the cluster map, that the entry should reset the idle timer. Or to provide some kind of init parameter to trigger this functionality.

Some session parameters are not distributed

From @mesutcelik on September 23, 2014 8:7

If you check WebFilter.java , you will see that some parameters of HazelcastHttpSession are not distributed.

        public long getCreationTime() {
            return originalSession.getCreationTime();
        }

        public long getLastAccessedTime() {
            return originalSession.getLastAccessedTime();
        }

        public int getMaxInactiveInterval() {
            return originalSession.getMaxInactiveInterval();
        }

        public void setMaxInactiveInterval(int maxInactiveSeconds) {
            originalSession.setMaxInactiveInterval(maxInactiveSeconds);
        }

Copied from original issue: hazelcast/hazelcast#3639

Missing null pointer check when removing an attribute

entry.setDirty(false) was recently added to HazelcastHttpSession (row 203), but I'm guessing that entry can be null since there's a null check above. But the new line is missing a null check.

public void removeAttribute(final String name) {
        LocalCacheEntry entry = localCache.get(name);
        if (entry != null && entry != WebFilter.NULL_ENTRY) {
            entry.setValue(null);
            entry.setRemoved(true);
            entry.setDirty(true);
            entry.setReload(false);
        }
        if (!deferredWrite) {
            try {
                webFilter.getClusteredSessionService().deleteAttribute(id, name);
                entry.setDirty(false);
            } catch (Exception e) {
                LOGGER.warning("Unexpected error occurred.", e);
            }
        }
    }

This can cause NPE like this:

15-Sep-2017 14:38:40.503 VARNING [ajp-nio-8009-exec-10] com.hazelcast.web.HazelcastHttpSession.null Unexpected error occurred.
 java.lang.NullPointerException
	at com.hazelcast.web.HazelcastHttpSession.removeAttribute(HazelcastHttpSession.java:203)
	at org.apache.jasper.runtime.PageContextImpl.doRemoveAttribute(PageContextImpl.java:396)
	at org.apache.jasper.runtime.PageContextImpl.removeAttribute(PageContextImpl.java:377)
	at org.apache.jasper.runtime.JspContextWrapper.removeAttribute(JspContextWrapper.java:226)
	at org.apache.taglibs.standard.tag.common.core.SetSupport.exportToVariable(SetSupport.java:188)
	at org.apache.taglibs.standard.tag.common.core.SetSupport.doEndTag(SetSupport.java:84)

[Test-Failure] JettyClientFailOverTest.whenClusterIsDown_enabledDeferredWrite

org.junit.ComparisonFailure: expected:<[value]> but was:<[null]>
	at org.junit.Assert.assertEquals(Assert.java:115)
	at org.junit.Assert.assertEquals(Assert.java:144)
	at com.hazelcast.wm.test.WebFilterClientFailOverTests.whenClusterIsDown_enabledDeferredWrite(WebFilterClientFailOverTests.java:49)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at com.hazelcast.test.DumpBuildInfoOnFailureRule$1.evaluate(DumpBuildInfoOnFailureRule.java:37)
	at com.hazelcast.test.jitter.JitterRule$1.evaluate(JitterRule.java:104)
	at com.hazelcast.test.metrics.MetricsRule$1.evaluate(MetricsRule.java:62)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at com.hazelcast.wm.test.WebTestRunner.run(WebTestRunner.java:60)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.createRequestAndRun(JUnitCoreWrapper.java:108)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.executeEager(JUnitCoreWrapper.java:78)
	at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.execute(JUnitCoreWrapper.java:54)
	at org.apache.maven.surefire.junitcore.JUnitCoreProvider.invoke(JUnitCoreProvider.java:144)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)

http://jenkins.hazelcast.com/view/Plugins/job/WM-master/611/
http://jenkins.hazelcast.com/view/Plugins/job/WM-master/612/

NoClassDefFoundError com/hazelcast/web/entryprocessor/SessionUpdateEntryProcessor

I'm trying to create a cluster using hazelcast filter based web session replication.
The replication seems work fine but i get for every operation the following exception.

I'm use hazelcast-4.0.jar and hazelcast-wm-4.0.jar into a preexistent Webapplication deployed on Apache Tomcat/9.0.30 with JSF Mojarra 2.2.8, PrimeFaces 6.2, Spring 4.

[http-nio-18080-exec-1] com.hazelcast.web.HazelcastHttpSession.null Unexpected error occurred.
        com.hazelcast.client.UndefinedErrorCodeException: Class name: java.lang.NoClassDefFoundError, Message: com/hazelcast/web/entryprocessor/SessionUpdateEntryProcessor
                at com.hazelcast.web.WebDataSerializerHook.getIdentifiedDataSerializable(WebDataSerializerHook.java:79)
                at com.hazelcast.web.WebDataSerializerHook.access$000(WebDataSerializerHook.java:33)
                at com.hazelcast.web.WebDataSerializerHook$1.create(WebDataSerializerHook.java:70)
                at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.readInternal(DataSerializableSerializer.java:143)
                at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.read(DataSerializableSerializer.java:106)
                at com.hazelcast.internal.serialization.impl.DataSerializableSerializer.read(DataSerializableSerializer.java:51)
                at com.hazelcast.internal.serialization.impl.StreamSerializerAdapter.read(StreamSerializerAdapter.java:48)
                at com.hazelcast.internal.serialization.impl.AbstractSerializationService.toObject(AbstractSerializationService.java:187)
                at com.hazelcast.client.impl.protocol.task.map.MapExecuteOnKeyMessageTask.prepareOperation(MapExecuteOnKeyMessageTask.java:42)
                at com.hazelcast.client.impl.protocol.task.AbstractPartitionMessageTask.processInternal(AbstractPartitionMessageTask.java:45)
                at com.hazelcast.client.impl.protocol.task.AbstractAsyncMessageTask.processMessage(AbstractAsyncMessageTask.java:71)
                at com.hazelcast.client.impl.protocol.task.AbstractMessageTask.initializeAndProcessMessage(AbstractMessageTask.java:145)
                at com.hazelcast.client.impl.protocol.task.AbstractMessageTask.run(AbstractMessageTask.java:108)
                at com.hazelcast.spi.impl.operationservice.impl.OperationRunnerImpl.run(OperationRunnerImpl.java:181)
                at com.hazelcast.spi.impl.operationexecutor.impl.OperationThread.process(OperationThread.java:172)
                at com.hazelcast.spi.impl.operationexecutor.impl.OperationThread.process(OperationThread.java:140)
                at com.hazelcast.spi.impl.operationexecutor.impl.OperationThread.run(OperationThread.java:123)

Forwarding request breaks session clustering

  1. Spring MVC forwards the request when you return "forward:/api/createSession" from your controller's request handler method - by using javax.servlet.RequestDispatcher#forward
  2. Tomcat's javax.servlet.RequestDispatcher implementation org.apache.catalina.core.ApplicationDispatcher wraps the request in an org.apache.catalina.core.ApplicationHttpRequest instance in its doForward method.
  3. ApplicationHttpRequest implements getSession() method and has no knowledge about the Hazelcast session. When getSession() is called on the request, it doesn't get the session from Hazelcast.

Different version of Tomcat have the same problem. We might look into how other containers behave, but ultimately we need to make sure it works on all containers.

See #47 for more history on the issue.

We have a reproducer thanks to @michael-kalpana
forward-bug-patch.zip

WebFilter may prevent requests from accessing request inputstream

This issue is a copy of hazelcast/hazelcast#3829

If a request is sent with the POST method and does not include a hazelcast session cookie (or other pre-existing requestedSessionId), WebFilter will currently call getParameter(HAZELCAST_SESSION_COOKIE_NAME). As per the ServletRequest documentation, getParameter and getInputStream can interfere with each other.

In my particular case, I'm seeing problems with HazelCast 3.3.1, Jetty 8.1.16.v20140903, and REST-style POST requests (which will never have a session). I have deferred-write set to true

possible data-loss using sticky-session=true / compatibility enhancement

Current implementation of sticky-sessions requires the load-balancer (lb) to stick to a node after a failover. However, there are some edge-cases which might lead to data-loss and incompatibilities with some lbs.

Example:

  1. lb routes user1 to node1
  2. user1 writes "data1" for key "test" into session
  3. node1 becomes unreachable
  4. lb re-routes user1 to node2
  5. user1 writes "data2" for key "test" into session
  6. node1 becomes reachable again - was not restarted

A - lb provides required stickyness:
7. node2 becomes unreachable
8. lb re-routes user1 to node1
9. data2 from 5. is lost

B - different behavior of lb e.g. nginx:
7. lb instantly re-routes user1 back to original node1
8. data2 from 5. is lost

What happens:

  • After the first failover (4.) session data will be available on node2 because hazelcast fetches the session from the map (creates a new local HazelcastHttpSession).
  • After the second "failover" in A.8 or different lb behavior in B.7, a local HazelcastHttpSession already exists and no data is fetched from the map
  • The value for key "test" is "data1" again -> "data2" is lost

Proposal:

  • remove entries and/or set reload flag on all other nodes, when a node must create a new sticky HazelcastHttpSession (once)

This would make HazelcastHttpSession compatible with nginx upstream configuration and eliminates rare edge cases, in which a node was temporarily unavailable and previously routed users are re-routed back.

HttpServletRequest#getSession(false) still returns a session after #14

Hi,

I have been testing with hazelcast-wm 3.7.1 (via hazelcast 3.8-SNAPSHOT) and found a condition where getSession(false) returns a session even though #14 should be fixed.

To reproduce:

  • user logs in via username/password to a web application using spring security and hazelcast
  • user makes an api call (which is going to take a long time to return)
  • while the 1st api call is ongoing, the user logs out. This request is handled in a new thread
  • From the logs I can see "Published destroy session event"
  • Now the first API call finishes and we hit the method saveContext in HttpSessionSecurityContextRepository::SaveToSessionResponseWrapper

In this code we call:
httpSession = request.getSession(false);

which recreates the session and now because we have a session then further down in the code we do:
httpSession.setAttribute(springSecurityContextKey, context);

which saves the thread local context with a fully populated Authentication object into the session.
Now the user is effectively logged back in without having to supply a username/password.

I managed to reproduce this and fix it with the following change in WebFilter:

@@ -442,7 +445,11 @@ public class WebFilter implements Filter {

         @Override
         public HazelcastHttpSession getSession(final boolean create) {
+
             hazelcastSession = readSessionFromLocal();
+            if (create == false) {
+                return hazelcastSession;
+            }
             String hazelcastSessionId = findHazelcastSessionIdFromRequest();
             if (hazelcastSession == null && !res.isCommitted() && (create || hazelcastSessionId != null)) {
                 hazelcastSession = createNewSession(HazelcastRequestWrapper.this, hazelcastSessionId);

However this was only a quick test just to prove to myself that honouring the create flag would be sufficient. There could well be other side effects I have not considered.

Please let me know if i can help with logs or reproducing,

Thanks
Philip

multiple user session created on sping logout

Hi,

I am experiencing following issues on hazelcast with spring security. We are running application with following technology stack:

  • Java - 1.8
  • Hazelcast verison:-3.7.5
  • Hazelcast-WM version:- 3.8
  • Spring-security:- 4.2.3
  • Spring -security-web:-4.0.1

Issue#1:

  • Multiple users session created when user log-out the application

Description:

  • We are using generic web session replication for managing user sessions in centralised hazelcast server. So after populating user session in cache, if user go for the logout I have noticed hazelcast api internally creating number of new user sessions in centralised cache server. Over here new sessions are not consistent in number sometime it is creating 2 but sometime more than that.

Issue#2:

  • Throwing java.lang.IllegalStateException: invalidate: Session already invalidated exception when user log-out the application, and again to try to log-in.

Description:

  • After populating user session in cache, if user go for the logout and try to login again in a same browser window, we are getting following exception:-
java.lang.IllegalStateException: invalidate: Session already invalidated
	org.apache.catalina.session.StandardSession.invalidate(StandardSession.java:1249)
	org.apache.catalina.session.StandardSessionFacade.invalidate(StandardSessionFacade.java:190)
	com.hazelcast.web.HazelcastHttpSession.invalidate(HazelcastHttpSession.java:178)
	org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler.logout(SecurityContextLogoutHandler.java:65)
	org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:112)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:133)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:152)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
	org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
	org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
	org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
	org.jasig.cas.client.session.SingleSignOutFilter.doFilter(SingleSignOutFilter.java:97)
	org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	com.hazelcast.web.WebFilter.doFilter(WebFilter.java:287)

However above exception is not consistent, because sometime user is able to log-in again but if we try to logout after that, we got this exception again. Most likely we are getting this issue after user logout. I got similar issue reported in following URL:-

hazelcast/hazelcast#3742

But it seems like its added fixes are not available hazelcast-wm-3.8. Following are the used configuration:-

<web-app>

	<filter>
	    <filter-name>hazelcast-filter</filter-name>
	    <filter-class>com.hazelcast.web.spring.SpringAwareWebFilter</filter-class>
	    <init-param>
	        <param-name>map-name</param-name>
	        <param-value>sessions</param-value>
	    </init-param>
	    <init-param>
	        <param-name>sticky-session</param-name>
	        <param-value>true</param-value>
    	</init-param>
	    <init-param>
	        <param-name>cookie-name</param-name>
	        <param-value>hazelcast.sessionId</param-value>
	    </init-param>
	    <init-param>
	        <param-name>debug</param-name>
	        <param-value>true</param-value>
	    </init-param>
	     <init-param>
	        <param-name>use-client</param-name>
	        <param-value>true</param-value>
    	</init-param>
	    <init-param>  
		    <param-name>instance-name</param-name>
		    <param-value>axis-centralize-cache</param-value>
		</init-param>
	    <init-param>
	        <param-name>shutdown-on-destroy</param-name>
	        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>hazelcast-filter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>REQUEST</dispatcher>
</filter-mapping>

<listener>
    <listener-class>com.hazelcast.web.SessionListener</listener-class>
</listener>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:context/applicationContext.xml</param-value>
	</context-param>

  	<filter>
		<filter-name>characterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>

 	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter>
	
  
	<filter-mapping>
		<filter-name>characterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

      	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<servlet>
		<servlet-name>webservices</servlet-name>
		<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
		<init-param>
			<param-name>transformWsdlLocations</param-name>
			<param-value>true</param-value>
		</init-param>
		<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>webservices</servlet-name>
		<url-pattern>*.wsdl</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>webservices</servlet-name>
		<url-pattern>/b2b-soap-endpoints/*</url-pattern>
	</servlet-mapping>

	<session-config>
		<session-timeout>60</session-timeout>
	</session-config>
</web-app>

request.getSession() returns null

HttpServletRequest#getSession(). The JavaDoc says:

Returns the current session associated with this request, or if the request does not have a session, creates one.

To me it feels like this method should never return null. The Hazelcast wrapped HttpServletRequest returns null if the request is committed, according to this code:

if (hazelcastSession == null && !res.isCommitted() && (create || hazelcastSessionId != null)) {
    hazelcastSession = createNewSession(HazelcastRequestWrapper.this, hazelcastSessionId);
}

I have a custom filter that does some different kinds of logging. It includes request.getSession().getId(). This gives me an NPE if the request is committed, which happens sometimes out of my control.

For now I'll just wrap this in a null check, but maybe it's something that should be fixed?

Add sesssion cookie path override

When using multiple contexts in a web container, a session cookie will always have a Path of the context it's created in. This makes it impossible to have container wide sessions, where the path should be /.

There should be some setting to allow for this, either as a boolean override, to use root, or to allow setting a specific path.

Missing JavaDoc (last CheckStyle issue)

There are just two classes which need a JavaDoc on the class level to get rid of all CheckStyle suppressions for this project. That's a nice low hanging fruit :)

hazelcast-wm/src/main/java/com/hazelcast/web/HazelcastHttpSession.java:34: Missing a Javadoc comment.
hazelcast-wm/src/main/java/com/hazelcast/web/WebDataSerializerHook.java:29: Missing a Javadoc comment.

If someone could write some wise words there we can delete this last suppression:

    <!-- Web -->
    <suppress checks="JavadocType" files="com/hazelcast/web/"/>

Undocumented local integrity implications of com.hazelcast.web.WebFilter's deferred-write parameter

From @BGehrels on August 14, 2014 18:39

Due to the LocalCache not being enabled when not setting deferred-write=true, subsequent calls to session.getAttribute("myKey") will neither return the same instance, nor will changes to the returned object be visible to subsequent calls.

session.setAttribute("myKey", new ArrayList()); // Will serialize the ArrayList
List list1 = session.getAttribute("myKey"); // Will deserialize the original List
list1.add("myValue"); // Will not be serialized

List list2 session.getAttribute("myKey"); // Will deserialize the original List again
System.out.println(list1 == list2); // false
System.out.println(list1.getSize()) // 1
System.out.println(list2.getSize()) // 0

After reading the Servlet Spec, I'm not sure if this behaviour is compliant. The spec is not very verbose regarding this topic. But: Since the behaviour differs when switching deferred-write parameter on and off, it should at least be clearly documented (with a big red warning sign).

Took me quite some time digging through Spring Web Flows source code.

Copied from original issue: hazelcast/hazelcast#3269

No DataSerializerFactory registered for namespace: -1000

In Hazelcast web session cluster(Client-Server Architecture), the exception(No DataSerializerFactory registered for namespace: -1000) occurs.

But,in Hazelcast web session cluster(Embedded Architecture), the same exception doesn't occur.

I checked the following page and I'm using the latest version of Hazelcast.
But the exception isn't resolved.

「"No DataSerializerFactory registered" for simplest http session replication test #2353」
hazelcast/hazelcast#2353

「Adding a standalone hazelcast node to my web session cluster give "No DataSerializerFactory registered for namespace"」
https://groups.google.com/forum/#!topic/hazelcast/_iw2MBQhpU8

unexpected IllegalStateException thrown when originalSession expires

HazelcastHttpSession.isNew() throws IllegalStateException when delegated to an invalidated originalSession.

prerequisites:

  • containersession (originalSession) timeout is smaller than max-idle-seconds of the hazelcast map storing sessions for HazelcastHttpSession

Steps to reproduce:

  1. create a valid containersession (originalSession) and HazelcastHttpSession
    -> containersession id and hazelcast session id will be stored in cookie
  2. let originalSession timeout
    -> cookies are untouched
  3. call HazelcastHttpSession.isNew() before max-idle-seconds of hazelcast map is reached
    -> HazelcastHttpSession will be retrieved through cookie
  4. "unexpected" IllegalStateException is thrown

expected behavior:
calling HazelcastHttpSession.isNew() returns false, when:

  • HazelcastHttpSession is valid
  • HazelcastHttpSession is not new
  • HazelcastHttpSession is fetched through the hazelcast session cookie
  • originalSession is invalidated

expected because:

  • repeating steps 1-4 without HazelcastHttpSession does not throw an IllegalStateException
    -> actually isNew() would return true and session data is lost, but no exception

comments:

  • The originalSession is stored during creation of HazelcastHttpSession and stays there.
  • After the timeout of originalSession the application container will create a new containersession, but the HazelcastHttpSession continues to point to the old invalidated original Session.
  • Delegating HazelcastHttpSession.isNew() to the originalSession throws an IllegalStateException (which is expected by spec), but not programatically, because HazelcastHttpSession is valid and the new containersession is valid.

Attribute value is read from local cache instead of cluster map after attribute removal

The following test code in com.hazelcast.wm.test.WebFilterSlowTests describes the issue:

    public void testAttributeRemoval() throws Exception {
        ...
        assertEquals("true", executeRequest("write", serverPort1, cookieStore));
        assertEquals(1, map.size());
        assertEquals("value", executeRequest("read", serverPort2, cookieStore));
        assertEquals("true", executeRequest("remove", serverPort2, cookieStore));
        assertEquals("null", executeRequest("read", serverPort1, cookieStore));
        //overwrite previously removed value
        assertEquals("true", executeRequest("write", serverPort1, cookieStore));
        assertEquals(1, map.size());
        assertEquals("value", executeRequest("read", serverPort2, cookieStore));
   }

The last read operation will return previously removed value. The issue happens only if deferred write and sticky sessions are disabled. Looks like that removeAttribute() in com.hazelcast.web.HazelcastHttpSession doesn't clear dirty-flag after attribute deletion.

session object is null, but not always.

I am using resin as a web server and hazelcast-wm 4.0 and hazelcast 4.0
I receive a NullPointerException on the session object. The error does not reappear after we refresh.
The session object is randomly null for the first time.

Code in a JSP:

user = (User) session.getAttribute("user");

Error:

java.lang.NullPointerException
                                                       	at _jsp._jsp._user._socialNetworksites__jsp._jspService(_socialNetworksites__jsp.java:1444)
                                                       	at _jsp._jsp._user._socialNetworksites__jsp._jspService(_socialNetworksites__jsp.java:1393)
                                                       	at com.caucho.jsp.JavaPage.service(JavaPage.java:64)
                                                       	at com.caucho.jsp.Page.pageservice(Page.java:548)
                                                       	at com.caucho.server.dispatch.PageFilterChain.doFilter(PageFilterChain.java:194)
                                                       	at com.hazelcast.web.WebFilter.doFilter(WebFilter.java:305)
                                                       	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:89)
                                                       	at com.caucho.server.httpcache.ProxyCacheFilterChain.doFilter(ProxyCacheFilterChain.java:161)
                                                       	at com.caucho.server.webapp.DispatchFilterChain.doFilter(DispatchFilterChain.java:131)
                                                       	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:314)
                                                       	at com.caucho.server.webapp.RequestDispatcherImpl.include(RequestDispatcherImpl.java:440)
                                                       	at com.caucho.server.webapp.RequestDispatcherImpl.include(RequestDispatcherImpl.java:359)
                                                       	at com.hazelcast.web.WebFilter$HazelcastRequestWrapper$1.include(WebFilter.java:370)
                                                       	at com.hazelcast.web.WebFilter$HazelcastRequestWrapper$1.include(WebFilter.java:370)
                                                       	at com.hazelcast.web.WebFilter$HazelcastRequestWrapper$1.include(WebFilter.java:370)
                                                       	at com.caucho.jsp.PageContextImpl.include(PageContextImpl.java:1091)
                                                       	at _jsp._jsp._user._qp_22dlogin__jsp._jspService(_qp_22dlogin__jsp.java:1609)
                                                       	at _jsp._jsp._user._qp_22dlogin__jsp._jspService(_qp_22dlogin__jsp.java:1394)

the session is null in the above case.

--EDIT--

I tried fetching "request.getSession(true)" and it gave me null randomly.

Possible to make a new release?

Would it be possible to make a new release of this? There has been several dependency version bumps by dependabot and others after version 4.0.

Sessions are not removed from Spring SessionRegistry when session timeout

The session should be removed from Spring's SessionRegistry when the session is timed out. However, it is not removed right now in order to save the session if it is not timed out on another node yet. The following test fails when session timeout is set to 1 min, and also this issue causes OOME after a while because of the accumulating session objects in the registry.

@Test
public void test_sessionTimeout() throws Exception {
    Set<ApplicationContext> applicationContextSet =
            SpringApplicationContextProvider.getApplicationContextSet();
    Iterator<ApplicationContext> i = applicationContextSet.iterator();
    ApplicationContext applicationContext1 = i.next();
    ApplicationContext applicationContext2 = i.next();
    SessionRegistry sessionRegistry1 = applicationContext1.getBean(SessionRegistry.class);
    SessionRegistry sessionRegistry2 = applicationContext2.getBean(SessionRegistry.class);

    SpringSecuritySession sss = login(null, false);

    request("hello", serverPort1, sss.cookieStore);

    String sessionId = sss.getSessionId();
    String hazelcastSessionId = sss.getHazelcastSessionId();

    IMap<String, Object> map = hz.getMap(DEFAULT_MAP_NAME);
    assertEquals("Session should be saved", 1, map.size());

    Thread.sleep(TimeUnit.SECONDS.toMillis(90L));

    assertTrue("Session timeout on both nodes should have removed the IMap entries", map.isEmpty());

    assertTrue(
            "Native session must not exist in both Spring session registry of Node-1 and Node-2 after timeout",
            sessionRegistry1.getSessionInformation(sessionId) == null &&
                    sessionRegistry2.getSessionInformation(sessionId) == null);

    assertTrue(
            "Hazelcast session must not exist in both Spring session registry of Node-1 and Node-2 after timeout",
            sessionRegistry1.getSessionInformation(hazelcastSessionId) == null &&
                    sessionRegistry2.getSessionInformation(hazelcastSessionId) == null);

}

compatibility between tomcat 10 and hazelcast-wm

Hi, I've a problem using tomcat 10 and hazelcast-wm. Tomcat 10 upgrade java servlet to 5.0.0 and now using jakarta e non javax (naming is changed). I see that hazelcast-wm instead uses javax.
Is there any way to use jakarta with hazelcast?

Replication requires session attributes

Not sure this is an issue or not, but I noticed that session replication does not actually happen if you don't add something to the session.

This means, if you're not using sticky sessions, you'll get a new session ID on every request. This seems a little strange to me, but maybe it's not an issue?

Sessions map entries not removing when session-fixation-protection is "migrateSession"

Faced with the problem that sessions map is not cleaning completely when sessions expire.
Looks like issue is not resolved completely.

In the debug mode I am able to see that original session in the hz session is invalid, but is still present in the sessions ConcurrentHashMap:

((Session)((HazelcastHttpSession)((java.util.concurrent.ConcurrentHashMap.MapEntry)sessions.entrySet().toArray()[0]).getValue()).originalSession)._state == INVALID

in this case
private final ConcurrentMap<String, HazelcastHttpSession> sessions = new ConcurrentHashMap(1000)
will grow in the size and will cause memory leak.

The requests with basic auth hit this method (after successful basic authentication):

`
package org.springframework.security.web.authentication.session;

abstract class AbstractSessionFixationProtectionStrategy implements
SessionAuthenticationStrategy, ApplicationEventPublisherAware {
...
/**
* Applies session fixation
*
* @param request the {@link HttpServletRequest} to apply session fixation protection
* for
* @return the new {@link HttpSession} to use. Cannot be null.
*/
abstract HttpSession applySessionFixation(HttpServletRequest request);
...
}
`
The method above is changing the session id, but the Hazelcast doesn’t know about it.
Hazelcast trying to remove the session based on the old session id, cannot find the session and that's why the session is not removing and memory leak occurs.

Conf:
<hazelcastVersion 3.8.3 /hazelcastVersion>
<springVersion 4.3.7.RELEASE springVersion>
<springSecurityVersion 4.2.3.RELEASE springSecurityVersion>

Setting hazelcast logging type results in inconsistent logging

hazelcast.logging.type is supposed to configure the logging framework. This does not work as intended.

The code in com.hazelcast.web.WebFilter is executed before the config file is read. This means that the static logger factory field is set to the StandardLoggerFactory because the type is null at that time. This results in every log call to WebFilter.LOGGER (for example in com.hazelcast.web.HazelcastHttpSession) to log to standard out.

Only the code using the LoggingService is using the configured logger factory.

A workaround is to set the logging type as a VM argument.

Session map entries not removed when session expires

Hazelcast is not removing destroyed sessions from the underlying map used for session clustering. I'm using Hazelcast 3.8 with WebFilter and SessionListener for session clustering.

WebFilter is configured to connect to an external Hazelcast cluster and store sessions in a map. Here's a subset of the web.xml filter configuration.

<init-param>
    <param-name>use-client</param-name>
    <param-value>true</param-value>
 </init-param>
 <init-param>
    <param-name>map-name</param-name>
    <param-value>SessionMap</param-value>
 </init-param>

In web.xml, my session-timeout is set to 120 (i.e. 2 hours). The Hazelcast map, named SessionMap, has a TTL of 24 hours (configured on the external cluster, not in web.xml). The thinking here is that we want to end sessions that are inactive for 2 hours but if someone is continuously using the application we want to let the session continue for a max of 24 hours.

The problem is that if I leave a session idle, Tomcat will terminate the session after 2 hours but the session will still remain in the Hazelcast map (SessionMap) until the TTL on that map.

When a session is destroyed by my application server (Tomcat), SessionListener calls WebFilter#destroyOriginalSession. This calls WebFilter#destroySession with the invalidated argument set to false. See below:

void destroyOriginalSession(HttpSession originalSession) {
    String hazelcastSessionId = (String)this.originalSessions.remove(originalSession.getId());
    if(hazelcastSessionId != null) {
        HazelcastHttpSession hazelSession = (HazelcastHttpSession)this.sessions.get(hazelcastSessionId);
        if(hazelSession != null) {
            this.destroySession(hazelSession, false);
        }
    }
}

This eventually creates a DeleteSessionEntryProcessor which is executed with executeOnKey(). The code from DeleteSessionEntryProcessor is below. “this.invalidate” is always false because of the above code, so it never actually removes the entry from the map.

public Object process(Entry<String, SessionState> entry) {
    SessionState sessionState = (SessionState)entry.getValue();
    if(sessionState == null) {
        return Boolean.FALSE;
    } else {
        if(this.invalidate) {
            entry.setValue((Object)null);
            this.removed = true;
        } else {
            entry.setValue(sessionState);
        }

        return Boolean.TRUE;
    }
}

I modified WebFilter#destroyOriginalSession and passed in true and it seems to behave correctly and remove the entries from the underlying map as I would expect.

As a side note, I opened a Stack Overflow question this morning before I dug into this further: http://stackoverflow.com/questions/43217697/hazelcast-remove-expired-session-from-map

Document or Ignore Configuration Collisions

Web Manager will throw an error if any of session-ttl-seconds, config-location, or client-config-location are configured in conjunction with instance-name. This specific behavior is undocumented in the README. The README also says session-ttl-seconds will be ignored in client/server mode.

I've submitted this as an issue, rather than as a PR changing the README, to see if these settings should be ignored if instance-name is configured or if we should update the README to indicate Web Manager will not start with these settings configured together.

Transient attribute doesn't work

I have attribute x specified as transient-attributes.

In com.hazelcast.web.HazelcastHttpSession#getAttribute we have some code which puts cache entry inside localCache, but it always pass false as value for transient flag.

It leads to update of transient field.

Verify and document programmatic configuration

Although it's not documented, WebFilter can be configured programmatically especially in Spring Boot applications (see the related guide). This provides an easier configuration but needs to be validated such that no functionality is missed when configured that way -- registration of SessionListener and SpringAwareWebFilter in particular.

Synchronization problems with hazelcast master branch

Synchronization problems with hazelcast master branch

Problem1

I want to use hazelcast.jar・hazelcast-client.jar・hazelcast-wm.jar build from master branch.
But, hazelcast-wm.jar build from master branch is not compatible with hazelcast.jar・hazelcast-client.jar build from master branch.

com.hazelcast.spi.impl.SerializationServiceSupport.getSerializationService()Lcom/hazelcast/internal/serialization/SerializationService;
java.lang.NoSuchMethodError: com.hazelcast.spi.impl.SerializationServiceSupport.getSerializationService()Lcom/hazelcast/internal/serialization/SerializationService;
at com.hazelcast.web.ClusteredSessionService.setAttribute(ClusteredSessionService.java:235) ~[hazelcast-wm-3.7-SNAPSHOT.jar:3.7-SNAPSHOT]
  • Cause

Because the interface of hazelcast.jar has been changed by the following commit.
hazelcast/hazelcast@be54c26

com.hazelcast.internal.serialization.SerializationService

com.hazelcast.spi.serialization.SerializationService

Problem2

I want to make pull request that fix Problem1, but hazelcast-wm master branch cannot refer hazelcast-3.7-SNAPSHOT.jar.
Because hazelcast-wm master branch pom.xml's default hazelcast.version is not 3.7-SNAPSHOT but 3.6.

Can I update default hazelcast.version to 3.7-SNAPSHOT?

Even now,master profile's hazelcast.version(hazelcast-wm master branch pom.xml) is 3.7-SNAPSHOT.
Therefore, compile error occurs when I build by 'mvn install -P master'.

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.5.1:compile (default-compile) on project hazelcast-wm: Compilation failure: Compilation failure:
[ERROR] /Users/yoshimoto/git/hazelcast-wm/src/main/java/com/hazelcast/web/ClusteredSessionService.java:[22,43] エラー: シンボルをつけられません
[ERROR] シンボル:   クラス SerializationService
[ERROR] 場所: パッケージ com.hazelcast.internal.serialization
[ERROR] /Users/yoshimoto/git/hazelcast-wm/src/main/java/com/hazelcast/web/ClusteredSessionService.java:[282,8] エラー: シンボルをつけられません
[ERROR] -> [Help 1]

Option to override WebFilter doFilter

I am using HazelcastSession with Spring for my web application. I have a health check url which I want to be STATELESS. Since the health check url is hit every 2 secs by load balancer, I see many Hazelcast sessions get opened in the process. That's why I want to make the health check service stateless. While spring security configuration provide me option to make a specific url STATELESS, but Hazelcast WebFilter is creating the session since it sits before the Spring Security Filter.

Would request to provide a solution. I can think of the following.

  1. Change in WebFilter to respect spring security STATELESS config
  2. remove final identifier letting us override WebFilter doFilter to ignore urls of our choice

Issue with Spring Security

Hi,

I'm trying to set up a sample application with sessions being shared among two instances of the application.

I'm using Spring Boot and Spring Security (default form login) and this is a peace o my config related to hazelcast-wm:

@Bean
public WebFilter webFilter(HazelcastInstance hazelcastInstance) {
	Properties properties = new Properties();
	properties.put("instance-name", hazelcastInstance.getName());
	properties.put("map-name", "sessions");
	properties.put("sticky-session", "false");
	return new SpringAwareWebFilter(properties);
}
@Bean
public SessionRegistry sessionRegistry() {
	return new SessionRegistryImpl();
}
@Bean
public ServletListenerRegistrationBean<SessionListener> hazelcastSessionListener() {
	return new ServletListenerRegistrationBean<>(new SessionListener());
}

After I login on 1st app and I can't access 2nd app using same cookies.
Without Spring Security everything works as expected (I can see session attributes being shared).

What am I doing wrong? Thanks in advance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.