Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-1869

InMemorySessionManager Session Creation Not Thread Safe

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 2.0.40.Final, 2.2.11.Final
    • 2.2.5.Final
    • Core
    • None
    • Hide

      package reproducer;

      import io.undertow.Undertow;
      import io.undertow.server.HttpHandler;
      import io.undertow.server.HttpServerExchange;
      import io.undertow.server.session.InMemorySessionManager;
      import io.undertow.server.session.Session;
      import io.undertow.server.session.SessionAttachmentHandler;
      import io.undertow.server.session.SessionConfig;
      import io.undertow.server.session.SessionCookieConfig;
      import io.undertow.server.session.SessionManager;
      import io.undertow.util.Headers;

      public class Reproducer {
      public static void main(final String[] args) {

      SessionManager sessionManager = new InMemorySessionManager(
      "SESSION_MANAGER");
      SessionCookieConfig sessionConfig = new SessionCookieConfig();
      /*

      • Use the sessionAttachmentHandler to add the sessionManager and
      • sessionCofing to the exchange of every request
        */
        SessionAttachmentHandler sessionAttachmentHandler = new SessionAttachmentHandler(
        sessionManager, sessionConfig);
        // set as next handler your root handler
        sessionAttachmentHandler.setNext(new HttpHandler()
        Unknown macro: { @Override public void handleRequest(final HttpServerExchange exchange) throws Exception
        Unknown macro: { SessionManager sm = exchange .getAttachment(SessionManager.ATTACHMENT_KEY); SessionConfig sessionConfig = exchange .getAttachment(SessionConfig.ATTACHMENT_KEY); Session session = sm.getSession(exchange, sessionConfig); if (session == null) session = sm.createSession(exchange, sessionConfig); exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); exchange.getResponseSender().send("Hello World"); }
        }

        );
        Undertow server = Undertow.builder()
        .addHttpListener(8080, "localhost")
        .setHandler(sessionAttachmentHandler).build();
        server.start();
        }
        }

      Create urls.txt with as many lines you like:
      cat urls.txt
      url = "http://localhost:8080"
      url = "http://localhost:8080"
      url = "http://localhost:8080"
      url = "http://localhost:8080"
      url = "http://localhost:8080"
      url = "http://localhost:8080"
      url = "http://localhost:8080"

      3. INvoke( change ID on every call)
      curl -X GET -b 'JSESSIONID=xxxxxx3' --verbose --parallel --parallel-immediate --parallel-max 5 --config urls.txt

      possibly bump up max. Though its hard to reproduce.

      possibly:

      #!/bin/bash
      set -x
      
       for i in {0..200..1}
                  do 
                      salt="$RANDOM"
                      curl -b \'JSESSIONID=xx"$salt"xx\' --verbose --parallel --parallel-immediate --parallel-max 15 --config urls.txt
          done
      
      Show
      package reproducer; import io.undertow.Undertow; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.server.session.InMemorySessionManager; import io.undertow.server.session.Session; import io.undertow.server.session.SessionAttachmentHandler; import io.undertow.server.session.SessionConfig; import io.undertow.server.session.SessionCookieConfig; import io.undertow.server.session.SessionManager; import io.undertow.util.Headers; public class Reproducer { public static void main(final String[] args) { SessionManager sessionManager = new InMemorySessionManager( "SESSION_MANAGER"); SessionCookieConfig sessionConfig = new SessionCookieConfig(); /* Use the sessionAttachmentHandler to add the sessionManager and sessionCofing to the exchange of every request */ SessionAttachmentHandler sessionAttachmentHandler = new SessionAttachmentHandler( sessionManager, sessionConfig); // set as next handler your root handler sessionAttachmentHandler.setNext(new HttpHandler() Unknown macro: { @Override public void handleRequest(final HttpServerExchange exchange) throws Exception Unknown macro: { SessionManager sm = exchange .getAttachment(SessionManager.ATTACHMENT_KEY); SessionConfig sessionConfig = exchange .getAttachment(SessionConfig.ATTACHMENT_KEY); Session session = sm.getSession(exchange, sessionConfig); if (session == null) session = sm.createSession(exchange, sessionConfig); exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); exchange.getResponseSender().send("Hello World"); } } ); Undertow server = Undertow.builder() .addHttpListener(8080, "localhost") .setHandler(sessionAttachmentHandler).build(); server.start(); } } Create urls.txt with as many lines you like: cat urls.txt url = "http://localhost:8080" url = "http://localhost:8080" url = "http://localhost:8080" url = "http://localhost:8080" url = "http://localhost:8080" url = "http://localhost:8080" url = "http://localhost:8080" 3. INvoke( change ID on every call) curl -X GET -b 'JSESSIONID=xxxxxx3' --verbose --parallel --parallel-immediate --parallel-max 5 --config urls.txt possibly bump up max. Though its hard to reproduce. possibly: #!/bin/bash set -x for i in {0..200..1} do salt="$RANDOM" curl -b \'JSESSIONID=xx"$salt"xx\' --verbose --parallel --parallel-immediate --parallel-max 15 --config urls.txt done
    • Undefined

      UNDERTOW-175 made it possible for a session ID being passed in to be used for session creation, however if multiple requests come in at once with the same "new" session ID the following error can be reported:

      2021-03-23 15:02:03,309 ERROR [io.undertow.request] (default task-2) UT005023: Exception handling request to /hello-world-jsf-3/session: java.lang.IllegalStateException: UT000196: Session with id dLA4P9OPnFMMe3Q2uIJqtr74o2J2jY0rkISdMJ7l already exists2021-03-23 15:02:03,309 ERROR [io.undertow.request] (default task-2) UT005023: Exception handling request to /hello-world-jsf-3/session: java.lang.IllegalStateException: UT000196: Session with id dLA4P9OPnFMMe3Q2uIJqtr74o2J2jY0rkISdMJ7l already exists at io.undertow.core@2.2.5.Final//io.undertow.server.session.InMemorySessionManager.createSession(InMemorySessionManager.java:180) at io.undertow.servlet@2.2.5.Final//io.undertow.servlet.spec.ServletContextImpl.getSession(ServletContextImpl.java:948) at io.undertow.servlet@2.2.5.Final//io.undertow.servlet.spec.HttpServletRequestImpl.getSession(HttpServletRequestImpl.java:421) at org.wildfly.security.elytron-web.undertow-server-servlet@1.9.0.Final//org.wildfly.elytron.web.undertow.server.servlet.ElytronHttpServletExchange$3.create(ElytronHttpServletExchange.java:259) at org.wildfly.security.elytron-private@1.15.1.Final//org.wildfly.security.http.util.sso.DefaultSingleSignOnSession.put(DefaultSingleSignOnSession.java:98) 

      This is just a call to getSession(true) but if this is called by two threads at the same time it is possible both threads will call InMemorySessionManager.createSession with one getting the above error.

      This can be easily triggered by a single web page concurrently requesting multiple resources concurrently.

       

            rhn-cservice-bbaranow Bartosz Baranowski
            darran.lofthouse@redhat.com Darran Lofthouse
            Votes:
            0 Vote for this issue
            Watchers:
            7 Start watching this issue

              Created:
              Updated:
              Resolved: