2

Spring is using the default validator factory provided by hibernate factory. However, I do not want to include an Expression Language dependency.

This answer recommends avoiding using the default factory by using this code:

import javax.validation.Validation;
import javax.validation.Validator;
import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;

private static final Validator VALIDATOR =
  Validation.byDefaultProvider()
    .configure()
    .messageInterpolator(new ParameterMessageInterpolator())
    .buildValidatorFactory()
    .getValidator();

That works well when I have a reference to VALIDATOR, but I'm not sure how to tell spring to use the above instead of the OptionalValidatorFactoryBean which extends LocalValidatorFactoryBean that I think is filled in with the validator from Validation.buildDefaultValidatorFactory() based on the javadoc from LocalValidatorFactoryBean

In summary, how do I replace spring's default Validation.buildDefaultValidatorFactory() with Validation.byDefaultProvider().configure().messageInterpolator(new ParameterMessageInterpolator()).buildValidatorFactory().getValidator() so that I can avoid the dependency on Expression Language.

joseph
  • 2,429
  • 1
  • 22
  • 43

2 Answers2

2

Thanks to @dbreaux 's answer I went through the docs and came up with this solution:

@Bean
public LocalValidatorFactoryBean validator() {
    LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
    localValidatorFactoryBean.setMessageInterpolator(new ParameterMessageInterpolator());
    return localValidatorFactoryBean;
}

I no longer need the Expression Language dependency and my validation is working with Hibernate Validator 5.2.5.Final.

However, due to a security issue, I had to upgrade to 6.0.22.Final and switched to the below which is really close to @dbreaux 's. I also had to add @Validated to the @Controller.

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    MethodValidationPostProcessor bean = new MethodValidationPostProcessor();
    bean.setValidator(Validation.byDefaultProvider()
            .configure()
            // We must use ParameterMessageInterpolator so that we do not need to add a dependency
            // on Java Expression Language which is a potential security vulnerability.
            // See https://securitylab.github.com/research/bean-validation-RCE/ for more info.
            .messageInterpolator(new ParameterMessageInterpolator())
            .buildValidatorFactory()
            .getValidator());
    return bean;
}
joseph
  • 2,429
  • 1
  • 22
  • 43
1

Try looking at Configuring a Bean Validation Provider for some discussion of the Validation Provider mechanism, and, for example, Spring-driven Method Validation, to then inject that as a default method-validation bean.

    <bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">  
        <property name="validatorFactory" ref="myValidatorFactory"/>  
    </bean>

(I did this kind of thing with Spring 4.x, on WebSphere Application Server, here.)

dbreaux
  • 4,982
  • 1
  • 25
  • 64
  • Thank you. I will look through this and try it out tomorrow. I will report back with the results here. – joseph Dec 02 '21 at 01:11