Broadleaf Microservices

Privacy (since 1.6.0)


Regional regulations regarding customer privacy dictate rules for handling of customer data, including the right for a customer to be forgotten. Broadleaf provides support for achieving compliance with these regulations based on deployment configuration, framework tooling, or both. Your overall compliance objectives should be compared against support provided by the toolset to determine applicability and ascertain any gaps in functionality to achieve target requirements.

Broadleaf support currently focuses on the following three areas:

  1. Encryption of personal identifiable information (at rest)

  2. Transport encryption (TLS)

  3. Anonymization to achieve the right to be forgotten requirements

Data At Rest

Encrypting data at rest is generally not achieved directly through the framework tooling, but instead through infrastructure facilities - specifically the cloud provider. Cloud storage is configured for encryption and is often established by default (e.g. GCP storage is by default encrypted using AES256).

The two locations where personal identifiable information may be stored are:

  1. file store backing the database

  2. file store backing the search engine (e.g. solr search service from Broadleaf)


Encrypting data as it’s transported over the network (e.g. customer browser communication to the microservice) is important as well. All communications with Broadleaf services are setup to use https protocol leveraging TLS1.2.


Broadleaf also provides API and backing support for anonymization of customer data without disrupting overall data integrity. This is achieved by replacing customer identifiable information with nonsense information so that the customer may no longer be specifically identified. Note, the scope of support out-of-the-box covers known Broadleaf fields only. Customer extensions that introduce additional exposure will need to be accounted for (see extension later).


The anonymization endpoints provided by Broadleaf can be called safely multiple times for the same customer id. Care should be taken with modifications, or new handlers, to not violate this contract.


  • Authentication Services - base user information

  • Cart Services - customer name and address information

  • Customer Services - customer name and address information

  • Order Services - customer name and address information

See Services for more information on these individual services. Links to open api docs are also included as part of the information for each service. This includes the pii endpoints mentioned below.

Anonymization Endpoints

Service endpoints for customer anonymization

Service URI HTTP Method













The response from each endpoint is a serialized (json) representation of AnonymizationReport. The report details what fields were changed (before and after), as well as what fields were left untouched for any reason. Any errors are also reported here.

Anonymization Extension

The anonymization code leverages the AnonymizationHandler for the application of anonymization data to customer data fields. Existing handlers provided by Broadleaf can be replaced or customized. Also, entirely new handlers can be added.


Each of the out-of-the-box handlers is associated with a property that allows the individual handler to be disabled. See Configuration for more details on available properties.

Replace or Modify

You can declare your own bean definition providing your own instance of AnonymizationHandler using a bean id defined in any of these autoconfiguration classes to replace the out-of-the-box behavior with custom behavior.

  • AuthAnonymizationAutoConfiguration

  • OrderAnonymizationAutoConfiguration

  • CartAnonymizationAutoConfiguration

  • CustomerAnonymizationAutoConfiguration


Simply declare a bean of type AnonymizationHandler and it will automatically be used by the concrete instance of AnonymizationService. See below for the basic anatomy of a handler.

import static com.broadleafcommerce.common.privacy.anonymization.Constants.ANONYMOUS_ALPHA_STANDARD;
import static com.broadleafcommerce.common.privacy.anonymization.Constants.ANONYMOUS_EMAIL;
import static com.broadleafcommerce.customer.provider.RouteConstants.Persistence.CUSTOMER_ROUTE_PACKAGE;

public class CustomerAnonymizationHandler extends AbstractAnonymizationHandler {

    private final CustomerService<Customer> customerService;                                    (1)

    public String getDataRoutePartition() {
        return CUSTOMER_ROUTE_PACKAGE;                                                          (2)

    public int getOrder() {
        return -100;                                                                            (3)

    public List<AnonymizationRecord> anonymize(String boundedContextIdentifier,
            Object context,
            PrivacyUtility privacyUtility) {                                                    (4)
        ContextInfo contextInfo = (ContextInfo) context;
        if (contextInfo == null) {
            contextInfo = new ContextInfo(OperationType.READ);
        Customer customer = customerService.readByContextId(boundedContextIdentifier, contextInfo);
        return handleRecords(boundedContextIdentifier, customer, contextInfo, privacyUtility);

    protected List<AnonymizationRecord> handleRecords(String boundedContextIdentifier,
            Customer member,
            ContextInfo contextInfo,
            PrivacyUtility privacyUtility) {
        List<AnonymizationRecord> records = new ArrayList<>();
        records.add(process(boundedContextIdentifier, Customer.class.getSimpleName(), "email",
                member::getEmail, member::setEmail, ANONYMOUS_EMAIL));
        records.add(process(boundedContextIdentifier, Customer.class.getSimpleName(), "firstName",
                member::getFirstName, member::setFirstName, ANONYMOUS_ALPHA_STANDARD));
        records.add(process(boundedContextIdentifier, Customer.class.getSimpleName(), "lastName",
                member::getLastName, member::setLastName, ANONYMOUS_ALPHA_STANDARD));
        records.add(process(boundedContextIdentifier, Customer.class.getSimpleName(), "middleName",
                member::getMiddleName, member::setMiddleName, ANONYMOUS_ALPHA_STANDARD));
        records.add(process(boundedContextIdentifier, Customer.class.getSimpleName(), "fullName",
                member::getFullName, member::setFullName, ANONYMOUS_ALPHA_STANDARD));
        records.add(process(boundedContextIdentifier, Customer.class.getSimpleName(), "username",
                member::getUsername, member::setUsername, ANONYMOUS_EMAIL));
        records.addAll(process(boundedContextIdentifier, member.getPhone(),
                Customer.class.getSimpleName(), "phone"));
                member.getAdditionalPhones(), Customer.class.getSimpleName(), "additionalPhones"));
        try {
            customerService.replace(member.getId(), member,
                    contextInfo.withOperationType(contextInfo, OperationType.UPDATE));
        } catch (RuntimeException e) {
            records.add(fail(boundedContextIdentifier, Customer.class.getSimpleName(), e, false));
        return records;

  1. Inject the java service component to interact with the domain

  2. Establish the data route for which this handler should be honored. This is important when FlexPackage™ composition is employed. See Data Routing for more information.

  3. Handlers are also ordered. Setting a higher precedent order provides an opportunity to perform early operations, such as validation.

  4. Actually perform the anonymization of the sensitive entity data and persist. Also build up the AnonymizationRecord instances that will eventually be included in the overall AnonymizationReport.


Introducing new AnonymizationHandler instances is often interesting to include relevant validation, or account maintenance. For example, during the customer anonymization process, it may be important to first cancel the customer’s subscription (if applicable). A new custom handler could be used to achieve that step.