Почему Jasypt пытается расшифровать заполнители свойств Camel независимо от префикса ENC(?

В моем приложении Blueprint, развернутом в JBoss Fuse 6.1.0-379, я хочу защитить пароль, который использую для создания подключения к базе данных. Я прочитал эту статью и добавил <enc:property-placeholder> в конфигурацию схемы. Однако в моей конфигурации схемы есть много заполнителей свойств, и кажется, что Jasypt Placeholder Resolver пытается расшифровать все заполнители, которые я определяю в своем Camel Context. Когда запускается Blueprint Context, я получаю следующее исключение:

11:59:51,233 | ERROR | t-379-dmz/deploy | BlueprintCamelContext            | 151 - org.apache.camel.camel-blueprint - 2.12.0.redhat-610379 | Error occurred during starting Camel: CamelContext(camel-5) due Failed to create route route7: Route(route7)[[From[{{uri}}]] -> [Log[logging]]] because of Failed to resolve endpoint: {{uri}} due to: org.jasypt.exceptions.EncryptionOperationNotPossibleException
org.apache.camel.FailedToCreateRouteException: Failed to create route route7: Route(route7)[[From[{{uri}}]] -> [Log[logging]]] because of Failed to resolve endpoint: {{uri}} due to: org.jasypt.exceptions.EncryptionOperationNotPossibleException
    at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:182)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultCamelContext.startRoute(DefaultCamelContext.java:778)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultCamelContext.startRouteDefinitions(DefaultCamelContext.java:1955)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultCamelContext.doStartCamel(DefaultCamelContext.java:1705)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultCamelContext.doStart(DefaultCamelContext.java:1579)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.support.ServiceSupport.start(ServiceSupport.java:61)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultCamelContext.start(DefaultCamelContext.java:1547)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.blueprint.BlueprintCamelContext.start(BlueprintCamelContext.java:177)[151:org.apache.camel.camel-blueprint:2.12.0.redhat-610379]
    at org.apache.camel.blueprint.BlueprintCamelContext.maybeStart(BlueprintCamelContext.java:209)[151:org.apache.camel.camel-blueprint:2.12.0.redhat-610379]
    at org.apache.camel.blueprint.BlueprintCamelContext.serviceChanged(BlueprintCamelContext.java:147)[151:org.apache.camel.camel-blueprint:2.12.0.redhat-610379]
    at org.apache.felix.framework.util.EventDispatcher.invokeServiceListenerCallback(EventDispatcher.java:934)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.util.EventDispatcher.fireEventImmediately(EventDispatcher.java:795)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.util.EventDispatcher.fireServiceEvent(EventDispatcher.java:544)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.Felix.fireServiceEvent(Felix.java:4666)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.Felix.registerService(Felix.java:3674)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.BundleContextImpl.registerService(BundleContextImpl.java:347)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.aries.blueprint.container.BlueprintContainerImpl.registerService(BlueprintContainerImpl.java:448)[9:org.apache.aries.blueprint.core:1.0.1.redhat-610379]
    at org.apache.aries.blueprint.container.BlueprintContainerImpl.doRun(BlueprintContainerImpl.java:383)[9:org.apache.aries.blueprint.core:1.0.1.redhat-610379]
    at org.apache.aries.blueprint.container.BlueprintContainerImpl.run(BlueprintContainerImpl.java:261)[9:org.apache.aries.blueprint.core:1.0.1.redhat-610379]
    at org.apache.aries.blueprint.container.BlueprintExtender.createContainer(BlueprintExtender.java:270)[9:org.apache.aries.blueprint.core:1.0.1.redhat-610379]
    at org.apache.aries.blueprint.container.BlueprintExtender.modifiedBundle(BlueprintExtender.java:233)[9:org.apache.aries.blueprint.core:1.0.1.redhat-610379]
    at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$Tracked.customizerModified(BundleHookBundleTracker.java:500)[11:org.apache.aries.util:1.0.1.redhat-610379]
    at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$Tracked.customizerModified(BundleHookBundleTracker.java:433)[11:org.apache.aries.util:1.0.1.redhat-610379]
    at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$AbstractTracked.track(BundleHookBundleTracker.java:725)[11:org.apache.aries.util:1.0.1.redhat-610379]
    at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$Tracked.bundleChanged(BundleHookBundleTracker.java:463)[11:org.apache.aries.util:1.0.1.redhat-610379]
    at org.apache.aries.util.tracker.hook.BundleHookBundleTracker$BundleEventHook.event(BundleHookBundleTracker.java:422)[11:org.apache.aries.util:1.0.1.redhat-610379]
    at org.apache.felix.framework.util.SecureAction.invokeBundleEventHook(SecureAction.java:1103)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.util.EventDispatcher.createWhitelistFromHooks(EventDispatcher.java:696)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.util.EventDispatcher.fireBundleEvent(EventDispatcher.java:484)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.Felix.fireBundleEvent(Felix.java:4650)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.Felix$4.run(Felix.java:2123)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.Felix.runInContext(Felix.java:2147)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.Felix.startBundle(Felix.java:2121)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:955)[org.apache.felix.framework-4.0.3.redhat-610379.jar:]
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1247)[7:org.apache.felix.fileinstall:3.3.11.redhat-610379]
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1219)[7:org.apache.felix.fileinstall:3.3.11.redhat-610379]
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.startAllBundles(DirectoryWatcher.java:1208)[7:org.apache.felix.fileinstall:3.3.11.redhat-610379]
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:503)[7:org.apache.felix.fileinstall:3.3.11.redhat-610379]
    at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:291)[7:org.apache.felix.fileinstall:3.3.11.redhat-610379]
Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: {{uri}} due to: org.jasypt.exceptions.EncryptionOperationNotPossibleException
    at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:480)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.util.CamelContextHelper.getMandatoryEndpoint(CamelContextHelper.java:71)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.model.RouteDefinition.resolveEndpoint(RouteDefinition.java:192)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:106)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultRouteContext.resolveEndpoint(DefaultRouteContext.java:112)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.model.FromDefinition.resolveEndpoint(FromDefinition.java:72)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultRouteContext.getEndpoint(DefaultRouteContext.java:88)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:890)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.model.RouteDefinition.addRoutes(RouteDefinition.java:177)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    ... 38 more
Caused by: org.apache.camel.RuntimeCamelException: org.jasypt.exceptions.EncryptionOperationNotPossibleException
    at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1363)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1005)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.blueprint.BlueprintPropertiesParser.parseProperty(BlueprintPropertiesParser.java:137)[151:org.apache.camel.camel-blueprint:2.12.0.redhat-610379]
    at org.apache.camel.component.properties.DefaultPropertiesParser.createPlaceholderPart(DefaultPropertiesParser.java:201)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.component.properties.DefaultPropertiesParser.doParseUri(DefaultPropertiesParser.java:105)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.component.properties.DefaultPropertiesParser.parseUri(DefaultPropertiesParser.java:51)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.component.properties.PropertiesComponent.parseUri(PropertiesComponent.java:160)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.component.properties.PropertiesComponent.parseUri(PropertiesComponent.java:119)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultCamelContext.resolvePropertyPlaceholders(DefaultCamelContext.java:1155)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:478)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    ... 46 more
Caused by: org.jasypt.exceptions.EncryptionOperationNotPossibleException
    at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.decrypt(StandardPBEByteEncryptor.java:918)
    at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.decrypt(StandardPBEStringEncryptor.java:725)
    at org.apache.karaf.jaas.jasypt.handler.EncryptablePropertyPlaceholder.getProperty(EncryptablePropertyPlaceholder.java:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[:1.7.0_25]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)[:1.7.0_25]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[:1.7.0_25]
    at java.lang.reflect.Method.invoke(Method.java:606)[:1.7.0_25]
    at org.apache.camel.util.ObjectHelper.invokeMethod(ObjectHelper.java:1001)[143:org.apache.camel.camel-core:2.12.0.redhat-610379]
    ... 54 more

Я создал тестовый пакет с контекстом Blueprint, который содержит только одно свойство-заполнитель, определенное в контексте Camel, без использования зашифрованного синтаксиса заполнителя ENC(). Я только что добавил <enc:property-placeholder>, и пакет не запустился с тем же исключением (org.jasypt.exceptions.EncryptionOperationNotPossibleException).

Это желаемое поведение?

Моя конфигурация Blueprint:

<?xml version="1.0" encoding="UTF-8"?> 
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
           xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
           xmlns:enc="http://karaf.apache.org/xmlns/jasypt/v1.0.0"
           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0">


    <cm:property-placeholder persistent-id="encrypt.config" update-strategy="reload" >
        <cm:default-properties>
            <cm:property name="uri" value="timer://foo?fixedRate=true&amp;period=6000"/>
        </cm:default-properties>
    </cm:property-placeholder>

    <enc:property-placeholder>
        <enc:encryptor class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
            <property name="config">
                <bean class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
                    <property name="algorithm" value="PBEWithMD5AndDES" />
                    <property name="password" value="password" />
                </bean>
            </property>
        </enc:encryptor>
    </enc:property-placeholder>

     <camelContext xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns="http://camel.apache.org/schema/blueprint"
                  xsi:schemaLocation="http://camel.apache.org/schema/blueprint">
        <route>
            <from uri="{{uri}}"/>
            <log message="logging" loggingLevel="INFO" id="logBeforeService"></log>
        </route>
     </camelContext>

</blueprint>

person drAvalanche    schedule 29.05.2015    source источник
comment
Вы когда-нибудь находили решение этой проблемы? Я обнаружил, что просто наличие заполнителей свойств в моих верблюжьих маршрутах вызывает то же исключение, что и вы. Если я удалю верблюда, то он отлично расшифрует и расшифрует свойства. Точно так же, если я удалю jasypt enc:property-placeholder, он прекрасно разрешает свойства, но, очевидно, не расшифровывает их. Этот меня мучил весь день!   -  person ConMan    schedule 11.06.2015


Ответы (1)


EDIT: ответ службы поддержки RedHat

Итак, это известная проблема, и для нее есть несколько проблем Jira (здесь и здесь), и похоже, что проблема была решена в более новых версиях Верблюд. Я протестировал версию 2.12.0.redhat-611412, предоставленную патчем с именем jboss-fuse-6.1.0.redhat-379-r1p3, и исключение больше не выдается.

Независимо от того, что я сказал ранее, я вполне доволен этой реализацией. Я бы хотел, чтобы было выбрано исключение, если оно не может расшифровать значение, которое было фактически зашифровано, и это именно то, что происходит. Я изменил зашифрованное значение на ENC(invalid_and_should_throw_exception), и возникло исключение, как я и ожидал.

Caused by: org.jasypt.exceptions.EncryptionOperationNotPossibleException

EDIT: более краткий ответ

Camel-Blueprint ведет себя иначе, чем Camel-Core, в отношении того, как он разрешает значения заполнителей свойств. Camel-Core требует, чтобы разработчик определил преобразователь заполнителей свойств Camel, который разрешает свойства в контексте Camel для синтаксиса свойств camel [1]. Очевидно, причина этого заключается в том, чтобы избежать конфликтов между синтаксисом свойства spring [2] и синтаксисом языка простых выражений Camel [3]. У разработчика есть возможность связать Spring Property Placeholder Resolver с Camel, добавив дополнительную конфигурацию.

[1 - Синтаксис свойства Camel]

{{org.my.prop}}

[2 - Синтаксис свойства Spring]

${org.my.prop}

[3 - Синтаксис языка простых выражений]

${exchange.body}

В Camel-Blueprint соединение между преобразователями заполнителей свойств Blueprint и контекстом Camel происходит автоматически. Когда создается контекст Blueprint Camel, в него вводится контекст Blueprint Bundle. С помощью Blueprint Bundle Context Camel извлекает из него все bean-компоненты и определяет, могут ли они быть назначены реализации Apache Aries AbstractPropertyPlaceholder. Для каждого экземпляра определенных вами преобразователей заполнителей свойств Camel может вызывать для них метод resolveProperty без необходимости анализировать синтаксис свойства, определенный каждым из преобразователей.

Поскольку преобразователь заполнителей свойств Jasypt ожидает синтаксис заполнителя [4], он просто игнорирует все, что не соответствует этому синтаксису. Поскольку Camel-Blueprint обходит эту проверку, которая обеспечивает синтаксис свойства, мы оказываемся в ситуации, когда Camel говорит Jasypt Placeholder Resolver расшифровывать каждое свойство, которое мы пытаемся использовать в нашем Camel Context. Это, конечно, вызовет исключение, потому что вы пытаетесь расшифровать свойство, которое не было зашифровано.

[4 - Синтаксис свойств Jasypt Blueprint]

ENC(encrypted.value)

Решения:

  1. Создайте класс, который реализует Jasypt StringEncryptor и содержит StandardPBEStringEncryptor в качестве атрибута. Реализованные методы шифрования и расшифровки вызывают методы шифрования и расшифровки StandardPBEStringEncryptor, но перехватывают любые возникающие исключения.

    • This is the solution I gave in my original answer.
    • Это опасно, если зашифрованное значение нельзя расшифровать, что нельзя игнорировать. Пакет не должен запускаться, чтобы предотвратить, например. ваша учетная запись базы данных от блокировки.
  2. Расшифруйте значения вручную, прежде чем передавать их в распознаватель заполнителей.

    • You could create a configuration service, where you compaile all your configuration from your various sources, decrypt all the encrypted values manually, then expose the properties as an OSGi service to be shared accross bundles.
    • Я отказался от этого дизайна, это в основном повторная реализация службы ConfigurationAdmin, которая изначально предоставляется Karaf (с добавлением расшифровки, которую Karaf не предоставляет), она просто не так хороша, как та, которую предоставляет Karaf, поскольку она не способный обнаруживать, когда конфигурация приложения изменилась.
  3. Decrypt values at runtime.
    • Not a fan of this either, requires your application to be aware of which application properties are expected to be encrypted.

Я отправил запрос в службу поддержки Redhat через наш контракт на поддержку, я буду держать вас в курсе, если что-то из этого выйдет.

Исходный ответ:

Думаю, я понял это. Согласно документации верблюда, верблюд в чертеже способен обнаруживать наличие преобразователя заполнителя чертежа и пытается использовать его для разрешения своих свойств.

Проблема с этим в том, что ему все равно, что такое префикс и суффикс-заполнитель, он просто идет вперед и использует его независимо. Сопоставитель заполнителей Jasypt спроектирован так, что он даже вызывается, только если префикс заполнителя равен "ENC(" и суффикс ")", помните, что Camel не заботится об этом. Camel передает свои неразрешенные свойства распознавателю свойств Jasypt, который, конечно же, пытается их расшифровать. Поскольку они не зашифрованы, создается исключение.

Чтобы обойти это, я создал собственный шифратор, который реализует Jasypt StringEncryptor. Пользовательский шифратор содержит экземпляр StandardPBEStingEncryptor и использует его для фактического шифрования/дешифрования. Ключевое отличие состоит в том, что исключения перехватываются и игнорируются, поэтому, если возникает исключение, пытающееся расшифровать свойство верблюда, которое не зашифровано, оно игнорируется, и приложение продолжает работать в обычном режиме.

Класс Java:

package uk.co.test;

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CustomEncryptor implements StringEncryptor {

    private StandardPBEStringEncryptor encryptor;
    private static final Logger LOG = LoggerFactory.getLogger(CustomEncryptor.class);

    public CustomEncryptor(String password) {
        encryptor = new StandardPBEStringEncryptor();
        encryptor.setPassword(password);
    }

    @Override
    public String decrypt(String value) {

        String ret = null;

        try {
            ret = encryptor.decrypt(value);
        } catch (Exception e) {
            LOG.error("Failed to decrypt value.");
        }

        return ret;
    }

    @Override
    public String encrypt(String value) {

        String ret = null;

        try {
            ret = encryptor.encrypt(value);
        } catch (Exception e) {
            LOG.error("Failed to encrypt value.");
        }

        return ret;
    }

    public StandardPBEStringEncryptor getEncryptor() {
        return encryptor;
    }

    public void setEncryptor(StandardPBEStringEncryptor encryptor) {
        this.encryptor = encryptor;
    }

}

Конфигурация чертежа:

<enc:property-placeholder>
    <enc:encryptor class="uk.co.test.CustomEncryptor">
        <argument value="myPass" />
    </enc:encryptor>
</enc:property-placeholder>
person ConMan    schedule 11.06.2015
comment
Да, кажется, проблема в классе BlueprintPropertiesParser, он просто перебирает все PropertyPlaceholders, несмотря на шаблон в заполнителе. Я думаю, что он должен проверять каждую клавишу с помощью шаблона и разрешать только при совпадении шаблона. - person drAvalanche; 17.06.2015
comment
Я декомпилировал версию camel-core 2.12.0.redhat-611412, класс BlueprintPropertiesParser точно такой же, как и в версии 610379, и проблема осталась. Думаю попробовать применить этот патч fisheye6.atlassian.com/changelog/ в класс и пересобрать верблюда из исходников. - person drAvalanche; 23.06.2015
comment
Хм это интересно. Верблюд — сложный зверь, возможно, реализация сложнее, чем мы думаем! Тем не менее, я могу подтвердить, что версия верблюда 2.12.0.redhat-611412 работает так, как я ожидал, в этом отношении, возможно, вы столкнулись с другой проблемой? Кроме того, я бы не стал перекомпилировать его сам, придерживаясь того, который предоставляется maven / redhat для поддержки, а что нет. - person ConMan; 23.06.2015