简体   繁体   中英

Spring Boot trusted packages for rabbitmq

We're building a Spring Boot application (2.0.4-RELEASE) that receives messages via RabbitMQ. Hence the application.properties contains the rabbit related config:

spring.rabbitmq.addresses=****
spring.rabbitmq.username=****
spring.rabbitmq.password=****
spring.rabbitmq.listener.simple.concurrency=2
spring.rabbitmq.listener.simple.prefetch=5
spring.rabbitmq.listener.simple.retry.enabled=true
spring.rabbitmq.listener.simple.retry.max-attempts=5

Configuration:

@Bean
public TopicExchange fileUpdate() {
    return new TopicExchange("my.fancy.exchange", true, false);
}

@Bean
public Queue fileUpload() {
    return new Queue("myFancyQueue", true);
}

@Bean
public Binding bindingUpload(Queue queue, TopicExchange eventExchange) {
    return BindingBuilder.bind(queue).to(eventExchange).with("");
}

Message Consumer:

@RabbitListener(queues = "myFancyQueue")
public void receive(Object message) {
    ...
}

When receiving a message of a specific type (eg __TypeId__: my.fancy.package.Clazz ) the following error is thrown:

Caused by: java.lang.IllegalArgumentException: The class 'my.fancy.package.Clazz' is not in the trusted packages: [java.util, java.lang]. If you believe this class is safe to deserialize, please provide its name. If the serialization is only done by a trusted source, you can also enable trust all (*).

From what I've discovered so far activeMQ provides a configuration option for that through the application.properties as

spring.activemq.packages.trust-all=

or

spring.activemq.packages.trusted=

but I can't find any similar option that would work for rabbitMQ. So far I've been using a workaround that solves my problem but of course it would be great to have an option like that in the configuration file.

My solution so far:

Adding to the configuration class:

@Bean
public MessageConverter jsonMessageConverter() {
    Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter(new ObjectMapper());
    jsonMessageConverter.setClassMapper(new ImporterClassMapper(FileUploadMessage.class));        
    return jsonMessageConverter;
}

@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
    RabbitTemplate template = new RabbitTemplate(connectionFactory);
    template.setMessageConverter(jsonMessageConverter());
    return template;
}

And changing the message consumer to

@Resource(name = "jsonMessageConverter")
private MessageConverter messageConverter;

@RabbitListener(queues = "${uploaded.files.queue}")
public void receive(Message message) {
    FileUploadMessage uploadMessage = (FileUploadMessage) messageConverter.fromMessage(message);
    ...
}

Plus adding a class mapper that allows unkown types to be imported and sets a default type to which messages should be cast to on import:

public class ImporterClassMapper implements ClassMapper, InitializingBean {

    private volatile Class<?> defaultType;

    public ImporterClassMapper(Class<?> defaultType) {
        this.defaultType = defaultType;
    }    

    @Override
    public void afterPropertiesSet() throws Exception {
        // nothing to do
    }

    @Override
    public void fromClass(Class<?> clazz, MessageProperties properties) {
        // avoid setting __TypeId__ header so consumers from other modules can implement their own DTOs
    }

    @Override
    public Class<?> toClass(MessageProperties properties) {
        return this.defaultType;
    }

    public void setClass(Class<?> type) {
        this.defaultType = type;
    }
}

Any advise on how to improve this solution?

I fixed the same error by setting trusted packages on the Spring AMQP ClassMapper being used.

@Configuration
public class RabbitConfig {

    @Bean
    @Scope("prototype")
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(SimpleRabbitListenerContainerFactory factory, ObjectMapper objectMapper) {
        factory.setMessageConverter(jsonToMapMessageConverter(objectMapper));
        return factory;
    }

    @Bean
    public MessageConverter jsonToMapMessageConverter(ObjectMapper objectMapper) {
        Jackson2JsonMessageConverter messageConverter = new ImplicitJsonMessageConverter(objectMapper);
        DefaultClassMapper classMapper = new DefaultClassMapper();
        classMapper.setTrustedPackages("*");
        classMapper.setDefaultType(Map.class);
        messageConverter.setClassMapper(classMapper);
        return messageConverter;
    }

    public static class ImplicitJsonMessageConverter extends Jackson2JsonMessageConverter {    
        public ImplicitJsonMessageConverter(ObjectMapper jsonObjectMapper) {
            super(jsonObjectMapper, "*");
        }    
        @Override
        public Object fromMessage(Message message) throws MessageConversionException {
            message.getMessageProperties().setContentType("application/json");
            return super.fromMessage(message);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM