Documentation Home

Multi-Customer Assisted Shopping

Broadleaf's CSR feature, allows for simultaneous multi-session customer assisted shopping.

How it works

This feature leverages and builds on top of Spring Session (http://projects.spring.io/spring-session/) to handle "multi-session" management.
Spring Session requires a "backing repository" in order to store all attributes across simultaneous sessions.
By default, Broadleaf provides a JDBC backing repository out-of-box that extends Spring Session's JDBC Repo
(http://docs.spring.io/spring-session/docs/1.2.1.RELEASE/reference/html5/#httpsession-jdbc). However, you are free
to switch out this backing repo with anything Spring Session supports, for example: Redis, Mongo, HazelCast, etc...

The mechanics behind this involve using a single session to maintain multiple "session aliases".
Internally Broadleaf uses Spring Session's CookieHttpSessionStrategy (http://docs.spring.io/spring-session/docs/1.2.1.RELEASE/api/org/springframework/session/web/http/CookieHttpSessionStrategy.html).
to maintain session aliases between requests. Since a single session may contain many sesssion aliases,
every request must have a session identifier in order to maintain context between requests.
Broadleaf provides a Javascript library that will intercept all anchor, form, and ajax requests and append the appropriate alias based on the
pages current context. In order to maintain internally initiated redirects and forwards, Broadleaf also
provides a BroadleafThymeleafViewResolver override to ammend the request with any session alias context.

Requirements

By default, this feature is disabled as there are a few requirements that your application must meet in order
for "multi-session" flows to function properly. It is also recommended that a thorough test be performed on the overall site
after being enabled to ensure that correct alias context is maintained throughout a shopping flow (i.e. no JavaScript/XHR calls outside
the context of normal DOM anchors or JQuery's Ajax calls drop the current session alias).

  • All URLs in your site application must be served under a single protocol, in most cases this would be HTTPS. This is due to the way cookies (auth and session fixation protection) are set and invalidated across multiple sessions. You can configure all your intercept-url's to use "HTTPS" by changing your configuration in applicationContext-security.xml

For example:

    ...
    <sec:intercept-url pattern="/" requires-channel="https"/>
    <sec:intercept-url pattern="/**" requires-channel="https"/>
    ...
  • By default, multi-session is only enabled for CSR Assisted Shopping "front-office" requests.
    Any "back-office" CSR site functions (such as Change Order) will not work in conjunction with any already provisioned csr shopping sessions.
    Any request initiated from a "back-office" request will invalidate any already initiated "front-office" request and vice-versa.

  • Broadleaf, by default, doesn't use Spring Security's built-in session fixation protection.
    Broadleaf has a custom security filter "blSessionFixationProtectionFilter" that manages an encrypted secure "http only" cookie
    between both secure and non-secure requests to preserve session ids. This filter must be adapted to handle multi-sessions as well.
    A new filter must be specified - which is outlined in the installation steps below.

Installation

  1. If you are using a JDBC backed repo to store the session attributes, you must include the following dependency in your root pom.xml
    <!-- Needed for Spring Session -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.1.9.RELEASE</version>
    </dependency>
  1. If you are using a JDBC/Database backed repo, you must make the following schema changes: Note: the following sample SQL below uses HSQLDB syntax, if you are using another DB, please use one of the Spring Session provided schema scripts located here as a starting point: https://github.com/spring-projects/spring-session/tree/master/spring-session/src/main/resources/org/springframework/session/jdbc Notice that to keep convention with the framework, we've prefixed the "oob spring" table names with BLC_ and you should do the same.
DROP TABLE BLC_SPRING_SESSION_ATTRIBUTES IF EXISTS;
DROP TABLE BLC_SPRING_SESSION IF EXISTS;

CREATE TABLE BLC_SPRING_SESSION (SESSION_ID CHAR(36),CREATION_TIME BIGINT NOT NULL,LAST_ACCESS_TIME BIGINT NOT NULL,MAX_INACTIVE_INTERVAL INT NOT NULL,PRINCIPAL_NAME VARCHAR(100),CONSTRAINT BLC_SPRING_SESSION_PK PRIMARY KEY (SESSION_ID));
CREATE INDEX BLC_SPRING_SESSION_IX1 ON BLC_SPRING_SESSION (LAST_ACCESS_TIME);

CREATE TABLE BLC_SPRING_SESSION_ATTRIBUTES (SESSION_ID CHAR(36),ATTRIBUTE_NAME VARCHAR(200),ATTRIBUTE_BYTES LONGVARBINARY,CONSTRAINT BLC_SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),CONSTRAINT BLC_SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES BLC_SPRING_SESSION(SESSION_ID) ON DELETE CASCADE);
CREATE INDEX BLC_SPRING_SESSION_ATTRIBUTES_IX1 ON BLC_SPRING_SESSION_ATTRIBUTES (SESSION_ID);
  1. To enable multi-session assisted shopping in your application, you must set the following system property:
csr.multi.customer.session.enabled=true

If for some reason, your application is all served under HTTP (e.g. just in dev), you must set the following
system property:

csr.multi.customer.session.https=false
  1. In site/src/main/webapp/WEB-INF/applicationContext-filter.xml:
  • add blCSRMultiSessionInitFilter as the very first filter in your blPreSecurityFilterChain
  • add blCSRMultiSessionCleanupFilter as the very last filter in your blPostSecurityFilterChain
  1. In site/src/main/webapp/WEB-INF/applicationContext-filter.xml declare the following beans at the bottom:
    <bean id="blMultiSessionHelperService" class="com.broadleafcommerce.enterprise.csr.web.filter.BroadleafMultiSessionHelperServiceImpl"/>
    <bean id="blCSRMultiSessionInitFilter" class="com.broadleafcommerce.enterprise.csr.web.filter.BroadleafCSRMultiSessionInitFilter"/>
    <bean id="blCSRMultiSessionCleanupFilter" class="com.broadleafcommerce.enterprise.csr.web.filter.BroadleafCSRMultiSessionCleanupFilter"/>

In addition, in order to validate multiple active CSR requests in the above filters, the CrossAppAuthCSRMultiSessionServiceImpl is configured
to generate a unique "token" for each active CSR session (i.e. this token is passed with each request via a cookie, "BLC_CSR_MULTI_AUTH_n").
This service looks at the system property csr.multi.customer.session.secretKey
to generate this token. This property should be set in PRODUCTION to an appropriate secret key. By default, it
is configured to use the value: "blc-default-key" if nothing is specified. This service uses "HmacSHA1" in conjunction with the secret key
to create the appropriate token, which is then verified in the above blCSRMultiSessionInitFilter.

  1. In site/src/main/webapp/WEB-INF/applicationContext-security.xml make sure all intercept-urls require either all HTTPS or all HTTP see requirements section above for details.

  2. In site/src/main/webapp/WEB-INF/applicationContext-security.xml change blSessionFixationProtectionFilter to be:

    <sec:custom-filter ref="blMultiSessionFixationProtectionFilter" before="SESSION_MANAGEMENT_FILTER"/>

and declare the bean:

    <bean id="blMultiSessionFixationProtectionFilter" class="com.broadleafcommerce.enterprise.csr.web.filter.BroadleafMultiSessionFixationProtectionFilter"/>
  1. In site/src/main/webapp/WEB-INF/applicationContext-servlet.xml add the following bean:
    <bean class="com.broadleafcommerce.enterprise.csr.web.extension.MultiSessionTemplateResolverExtensionHandler"/>
  1. Create a new file: site/src/main/webapp/WEB-INF/applicationContext-session.xml with the following contents:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

    <bean id="blCookieHttpSessionStrategy" class="com.broadleafcommerce.enterprise.csr.web.http.BroadleafCookieHttpSessionStrategy"/>

    <bean class="com.broadleafcommerce.enterprise.csr.web.http.BroadleafJdbcHttpSessionConfiguration">
        <property name="httpSessionStrategy" ref="blCookieHttpSessionStrategy"/>
        <property name="dataSource" ref="webDS"/>
        <property name="tableName" value="BLC_SPRING_SESSION"/>
    </bean>

</beans>
  1. Add the reference to this new app context in site/src/main/webapp/WEB-INF/web.xml (after applicationContext-filter.xml)
    /WEB-INF/applicationContext-session.xml
  1. Finally, in your site's footer.html add the following JS dependencies:
    <th:block th:if="${#brc.csrMode AND #props.get('csr.multi.customer.session.enabled')}">
        <blc:form>
            <input type="hidden" name="csrSessionAlias" th:value="${#httpServletRequest.getParameter('_s') != null ? #httpServletRequest.getParameter('_s') : 0}"/>
        </blc:form>
        <blc:bundle name="csrMultiSession.js"
                    mapping-prefix="/js/"
                    files="lib/URI.js,
                           csr-multi-client.js" />
    </th:block>
  1. If you are using a JDBC Backed Repo, you can initialize a spring-enabled scheduler to clean up any inactive sessions. JdbcOperationsSessionRepository contains an @Scheduled method to clear expired sessions. You can enable this by adding the following to your applicationContext-session.xml:
    <!-- configure scheduler to clean up expired csr sessions -->
    <task:annotation-driven scheduler="myMultiCsrSessionScheduler"/>
    <task:scheduler id="myMultiCsrSessionScheduler" pool-size="10"/>

Things to be aware of

If your application communicates with any external integrations (e.g. Payment Gateways) that rely on re-directs as a mechanism of transferring information.
You'll also need to make sure you extend and override those configurations to take into account the new multi-session request parameter.
For example, if your payment gateway relies on a transparent redirect to complete checkout, then you would need to make sure that the application constructs the appropriate "session aware" url:

    String url = BLCSystemProperty.resolveSystemProperty("gateway.mygateway.configuration.processUrl");
    url = multiSessionHelperService.encodeCurrentAliasToUrl(url);
    return url;