Override Compilation Customizer for Groovy Updater Scripts

Info: Available in brXM 14.7.13 and 15.2.0+

Overview

You can override the default Groovy compilation customizers for updater scripts to enforce custom security requirements. This allows you to control how Groovy scripts are compiled and which classes or packages they can access.

When to Use

Override the default compilation customizers if you need to:

  • Enforce stricter security policies for Groovy updater scripts.
  • Allow or restrict specific imports beyond the default configuration.
  • Replace the default Bloomreach compilation customizers with project-specific logic.

Background

The Updater Editor in Bloomreach Content lets you create, manage, and execute Groovy updater scripts directly from the UI. Groovy supports compilation customizers, which modify the script compilation process.

Starting with versions 14.7.13 and 15.2.0, you can replace the default compilation customizers with your own implementation. Your customizers can access Bloomreach configuration through public static variables and methods in org.onehippo.repository.update.GroovyUpdaterClassLoader.

Important: Bloomreach supports the mechanism for customizing compilation, but does not support the customizers you implement. You are responsible for ensuring that your customizations do not introduce security vulnerabilities. When you provide your own CompilationCustomizerFactory, the default Bloomreach compilation customizers are no longer used.

Prerequisites

  • A standard implementation project structure based on the Maven archetype.
  • Familiarity with Java and Spring configuration.
  • Replace org.myproject with your actual package name.

Implementation Steps

To override the default Groovy compilation customizers:

  1. Create the spring.factories file

    In your cms module, add the following file:

    cms/src/main/resources/META-INF/spring.factories

    org.springframework.boot.autoconfigure.EnableAutoConfiguration = org.myproject.spring.MyAppConfiguration
    
  2. Implement the Spring configuration class

    Create the class org.myproject.spring.MyAppConfiguration:

    cms/src/main/java/org/myproject/spring/MyAppConfiguration.java

    package org.myproject.spring; import org.myproject.groovy.CompilationCustomizerFactoryImpl; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyAppConfiguration { @Bean(initMethod = "init", destroyMethod = "destroy") public CompilationCustomizerFactoryImpl getCompilationCustomizerFactory() { return new CompilationCustomizerFactoryImpl(); } }
  3. Implement the custom compilation customizer factory

    Create the class org.myproject.groovy.CompilationCustomizerFactoryImpl:

    cms/src/main/java/org/myproject/groovy/CompilationCustomizerFactoryImpl.java

    package org.myproject.groovy; import static java.util.Collections.unmodifiableList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import org.codehaus.groovy.control.customizers.CompilationCustomizer; import org.onehippo.cms7.services.HippoServiceRegistry; import org.onehippo.repository.update.CompilationCustomizerFactory; public class CompilationCustomizerFactoryImpl implements CompilationCustomizerFactory { public static final List<String> myAllowedImports = unmodifiableList( Stream.of("org.onehippo.repository.update.BaseNodeUpdateVisitor", "javax.jcr.Node", "javax.jcr.RepositoryException", "javax.jcr.Session").collect(Collectors.toList())); public void init() { HippoServiceRegistry.register(this, CompilationCustomizerFactory.class); } public void destroy() { HippoServiceRegistry.unregister(this, CompilationCustomizerFactory.class); } @Override public CompilationCustomizer[] createCompilationCustomizers() { // TODO return your custom compilation customizers } }
  4. Implement the createCompilationCustomizers method

    Provide your custom logic in the createCompilationCustomizers method. See the example below for a reference implementation.

  5. Build and deploy your project

    After implementing your customizer, build and deploy your project to apply the changes.

Example

The following example replaces the default implementation, which uses a list of disallowed imports, with a configuration that allows only specific imports.

package org.myproject.groovy; import static java.util.Collections.unmodifiableList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import org.codehaus.groovy.control.customizers.CompilationCustomizer; import org.codehaus.groovy.control.customizers.SecureASTCustomizer; import org.onehippo.cms7.services.HippoServiceRegistry; import org.onehippo.repository.update.CompilationCustomizerFactory; import org.onehippo.repository.update.GroovyUpdaterClassLoader; public class CompilationCustomizerFactoryImpl implements CompilationCustomizerFactory { public static final List<String> myAllowedImports = unmodifiableList( Stream.of("org.onehippo.repository.update.BaseNodeUpdateVisitor", "javax.jcr.Node", "javax.jcr.RepositoryException", "javax.jcr.Session").collect(Collectors.toList())); public void init() { HippoServiceRegistry.register(this, CompilationCustomizerFactory.class); } public void destroy() { HippoServiceRegistry.unregister(this, CompilationCustomizerFactory.class); } @Override public CompilationCustomizer[] createCompilationCustomizers() { final SecureASTCustomizer compilationCustomizer = new SecureASTCustomizer(); compilationCustomizer.setAllowedImports(myAllowedImports); compilationCustomizer.setIndirectImportCheckEnabled(true); compilationCustomizer.addExpressionCheckers(new GroovyUpdaterClassLoader.DefaultUpdaterExpressionChecker()); return new CompilationCustomizer[] { GroovyUpdaterClassLoader.createDefaultImportCustomizer(), compilationCustomizer }; } }

You can add additional classes to myAllowedImports as needed.

Verification

If a Groovy updater script imports a class that is not listed in myAllowedImports, the script will fail with an error similar to:

java.lang.SecurityException: Importing [my.package.MyClass] is not allowed
Share Feedback
Page: /build/content-updates/override-compilation-customizer-for-groovy-updater-scripts
Section: Build
Category *
Override Compilation Customizer for Groovy Updater Scripts | Bloomreach Content Documentation