Class ClientSideSessionModule

  • All Implemented Interfaces:
    com.google.inject.Module

    public class ClientSideSessionModule
    extends ConfigurableModule<ClientSideSessionConfig>
    An extension module that provides a client side session store - cookie based.

    This module depends on SessionModule and MUST be added to the module list AFTER SessionModule.

    Example usage

    
     import ratpack.guice.Guice;
     import ratpack.core.http.client.ReceivedResponse;
     import ratpack.session.Session;
     import ratpack.session.SessionKey;
     import ratpack.session.SessionModule;
     import ratpack.session.clientside.ClientSideSessionModule;
     import ratpack.test.embed.EmbeddedApp;
    
     import static org.junit.jupiter.api.Assertions.*;
    
     public class ClientSideSessionModuleExample {
       public static void main(String... args) throws Exception {
         EmbeddedApp.of(s -> s
           .registry(Guice.registry(b -> b
             .module(SessionModule.class, config -> {
               //config.path("/").domain("www.example.com");
             })
             .module(ClientSideSessionModule.class, config -> {
               config.setSessionCookieName("session_name");
               config.setSecretToken("your token for signing");
               //config.setSecretKey("key for cipher");
               //config.setMacAlgorithm("MAC algorithm for signing");
               //config.setCipherAlgorithm("Cipher Algorithm");
               //config.setMaxSessionCookieSize(1024);
               //config.setMaxInactivityInterval(Duration.ofSeconds(60));
             })
           ))
           .handlers(chain -> chain
             .get(ctx -> {
               ctx.get(Session.class).getData()
                 .map(d -> d.get(SessionKey.ofType("value", "value")).orElse("not set"))
                 .then(ctx::render);
             })
             .get("set/:value", ctx -> {
               ctx.get(Session.class).getData().then(d -> {
                 d.set("value", ctx.getPathTokens().get("value"));
                 ctx.render(d.get(SessionKey.ofType("value", "value")).orElse("not set"));
               });
             })
           )
         )
         .test(client -> {
           ReceivedResponse response = client.get();
           assertEquals("not set", response.getBody().getText());
           assertFalse(response.getHeaders().getAll("Set-Cookie").contains("session_name"), "No cookies should be set");
    
           response = client.get("set/foo");
           assertEquals("foo", response.getBody().getText());
           assertTrue(response.getHeaders().getAll("Set-Cookie")
              .stream()
              .anyMatch(c -> c.contains("session_name_0=")), "We set a value and our session name");
           assertTrue(response.getHeaders().getAll("Set-Cookie")
              .stream()
              .anyMatch(c -> c.contains("session_name_lat_0=")), "We updated the last-access-time");
    
           response = client.get();
           assertEquals("foo", response.getBody().getText());
           assertFalse(response.getHeaders().getAll("Set-Cookie")
              .stream()
              .anyMatch(c -> c.contains("session_name_0=")), "We did not update session");
           assertTrue(response.getHeaders().getAll("Set-Cookie")
             .stream()
             .anyMatch(c -> c.contains("session_name_lat_0=")), "We updated the last-access-time");
         });
       }
     }
     

    Notes

    The max cookie size for a client is 4k so it's important to keep this in mind when using the ClientSideSessionModule

    By default your session will be signed but not encrypted. This is because the secretKey is not set by default. That is, your users will not be able to tamper with the cookie but they can still read the key value pairs that you have set. If you want to render the entire cookie unreadable make sure you set a secretKey

    When setting your own secretKey and cipherAlgorithm make sure that the key length is acceptable according to the algorithm you have chosen.

    When working in multi instances environment the secretToken has to be the same for every ratpack instance configuration.

    If your application does not require a unique SessionId for other reasons, consider replacing the default implementation with SessionId.empty() to avoid setting the session ID header.

    • Constructor Detail

      • ClientSideSessionModule

        public ClientSideSessionModule()
    • Method Detail

      • configure

        protected void configure()
        Overrides:
        configure in class com.google.inject.AbstractModule