EvaluationContextConfigurers.java

package pro.verron.officestamper.preset;


import org.springframework.expression.EvaluationContext;
import org.springframework.expression.TypeLocator;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.*;
import pro.verron.officestamper.api.EvaluationContextConfigurer;
import pro.verron.officestamper.api.OfficeStamperException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Utility class for configuring the EvaluationContext used by officestamper.
 */
public class EvaluationContextConfigurers {

    private EvaluationContextConfigurers() {
        throw new OfficeStamperException("EvaluationContextConfigurers cannot be instantiated");
    }

    /**
     * Returns a {@link EvaluationContextConfigurer} instance that does no customization.
     * <p>
     * This configurer does nothing to the StandardEvaluationContext class, and therefore all the
     * unfiltered features are accessible.
     * It should be used when there is a need to use the
     * powerful features of the aforementioned class, and there is a trust that the template won't
     * contain any dangerous injections.
     *
     * @return a {@link EvaluationContextConfigurer} instance
     */
    public static EvaluationContextConfigurer noopConfigurer() {
        return new NoOpEvaluationContextConfigurer();
    }

    /**
     * Returns a default {@link EvaluationContextConfigurer} instance.
     * <p>
     * The default configurer provides better default security for the
     * {@link EvaluationContext} used by OfficeStamper.
     * It sets up the context with enhanced security measures, such as
     * limited property accessors, constructor resolvers, and method resolvers.
     * It also sets a type locator, type converter, type comparator, and operator overloader.
     * This configurer is recommended to be used when there is a need for improved security
     * and protection against potential dangerous injections in the template.
     *
     * @return a {@link EvaluationContextConfigurer} instance with enhanced security features
     */
    public static EvaluationContextConfigurer defaultConfigurer() {
        return new DefaultEvaluationContextConfigurer();
    }

    /**
     * {@link EvaluationContextConfigurer} that does no customization.
     * <p>
     * The NoOpEvaluationContextConfigurer is a configuration placeholder used to indicate the
     * intention to keep the standard powerful features provided by the
     * Spring framework's StandardEvaluationContext class.
     * <p>
     * StandardEvaluationContext is a powerful class by default, which can lead to potential security risks
     * if not properly managed. This might include potential dangerous injections in the template.
     * <p>
     * This configurer does nothing to the StandardEvaluationContext class, and therefore all the
     * unfiltered features are accessible. It should be used when there is a need to use the
     * powerful features of the aforementioned class, and there is a trust that the template won't
     * contain any dangerous injections.
     *
     * @author Joseph Verron
     * @author Mario Siegenthaler
     * @version ${version}
     * @since 1.0.13
     */
    private static class NoOpEvaluationContextConfigurer
            implements EvaluationContextConfigurer {
        /**
         * Configures the provided StandardEvaluationContext.
         *
         * @param context the StandardEvaluationContext to be configured, not null
         */
        @Override
        public void configureEvaluationContext(StandardEvaluationContext context) {
            // DO NOTHING
        }
    }

    /**
     * {@link EvaluationContextConfigurer} that has better default security,
     * especially doesn't allow especially known injections.
     *
     * @author Joseph Verron
     * @version ${version}
     * @since 1.6.5
     */
    private static class DefaultEvaluationContextConfigurer
            implements EvaluationContextConfigurer {
        /**
         * {@inheritDoc}
         */
        @Override
        public void configureEvaluationContext(StandardEvaluationContext context) {
            TypeLocator typeLocator = typeName -> {
                throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
            };
            context.setPropertyAccessors(List.of(DataBindingPropertyAccessor.forReadWriteAccess()));
            context.setConstructorResolvers(Collections.emptyList());
            context.setMethodResolvers(new ArrayList<>(List.of(DataBindingMethodResolver.forInstanceMethodInvocation())));
            //noinspection DataFlowIssue, ignore the warning since it is a workaround fixing potential security issues
            context.setBeanResolver(null);
            context.setTypeLocator(typeLocator);
            context.setTypeConverter(new StandardTypeConverter());
            context.setTypeComparator(new StandardTypeComparator());
            context.setOperatorOverloader(new StandardOperatorOverloader());
        }
    }
}