Broadleaf Microservices
  • v1.0.0-latest-prod

Privacy (since 1.6.0)

Overview

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

Refer to Best Practices for more information.

Anonymization

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).

Note

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.

Inventory

  • 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

  • Payment Transaction 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

Authentication

/pii/users/{customerId}

DELETE

Cart

/pii/carts/{customerId}

DELETE

Customer

/pii/customers/{customerId}

DELETE

Order

/pii/orders/{customerId}

DELETE

Payment Transaction

/pii/payments/{customerId}

DELETE

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.

Note
Before anonymizing data, make sure to first consider the implications on your business’s ability to complete any processes that are not yet finalized. For example, will anonymizing a Payment have negative impacts on your business’s ability to fulfill an order?

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.

Disable

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

  • PaymentAnonymizationAutoConfiguration

New

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;

@RequiredArgsConstructor
public class CustomerAnonymizationHandler extends AbstractAnonymizationHandler {

    private final CustomerService<Customer> customerService;                                    # (1)

    @Override
    public String getDataRoutePartition() {
        return CUSTOMER_ROUTE_PACKAGE;                                                          # (2)
    }

    @Override
    public int getOrder() {
        return -100;                                                                            # (3)
    }

    @Override
    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"));
        records.addAll(processAdditionalPhones(boundedContextIdentifier,
                member.getAdditionalPhones(), Customer.class.getSimpleName(), "additionalPhones"));
        try {
            customerService.replace(member.getId(), member,
                    contextInfo.withOperationType(contextInfo, OperationType.UPDATE));
        } catch (RuntimeException e) {
            records.clear();
            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.

Note

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.