log4j2 how to disable "date:" lookup - log4j throws exception - apache-camel

edit seems not to be possible at the moment filed an issue.
i am using log4j2 in my apache camel application. In camel file names can be configured this way "?fileName=${date:now:yyyyMMdd-HHmmss}ID.${id}.gz"
if i set log level to debug camel tries to log what it is doing but log4j seems to try to lookup/interpret the string with "date:" and throws an exception:
2014-11-24 11:29:19,218 ERROR Invalid date format: "now:yyyyMMdd-HHmmss", using default java.lang.IllegalArgumentExcepti
on: Illegal pattern character 'n'
at java.text.SimpleDateFormat.compile(Unknown Source)
at java.text.SimpleDateFormat.initialize(Unknown Source)
at java.text.SimpleDateFormat.<init>(Unknown Source)
at java.text.SimpleDateFormat.<init>(Unknown Source)
at org.apache.logging.log4j.core.lookup.DateLookup.formatDate(DateLookup.java:60)
at org.apache.logging.log4j.core.lookup.DateLookup.lookup(DateLookup.java:53)
at org.apache.logging.log4j.core.lookup.Interpolator.lookup(Interpolator.java:144)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.resolveVariable(StrSubstitutor.java:1008)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:926)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.substitute(StrSubstitutor.java:816)
at org.apache.logging.log4j.core.lookup.StrSubstitutor.replace(StrSubstitutor.java:385)
at org.apache.logging.log4j.core.pattern.MessagePatternConverter.format(MessagePatternConverter.java:71)
at org.apache.logging.log4j.core.pattern.PatternFormatter.format(PatternFormatter.java:36)
at org.apache.logging.log4j.core.layout.PatternLayout.toSerializable(PatternLayout.java:189)
at org.apache.logging.log4j.core.layout.PatternLayout.toSerializable(PatternLayout.java:53)
at org.apache.logging.log4j.core.layout.AbstractStringLayout.toByteArray(AbstractStringLayout.java:52)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:
104)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:97)
at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:428)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:407)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:365)
at org.apache.logging.log4j.core.Logger.logMessage(Logger.java:112)
at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:1347)
at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1312)
at org.apache.logging.slf4j.Log4jLogger.debug(Log4jLogger.java:132)
at org.apache.camel.util.IntrospectionSupport.setProperty(IntrospectionSupport.java:518)
at org.apache.camel.util.IntrospectionSupport.setProperty(IntrospectionSupport.java:570)
at org.apache.camel.util.IntrospectionSupport.setProperties(IntrospectionSupport.java:454)
at org.apache.camel.util.EndpointHelper.setProperties(EndpointHelper.java:249)
at org.apache.camel.impl.DefaultComponent.setProperties(DefaultComponent.java:272)
at org.apache.camel.component.file.GenericFileComponent.createEndpoint(GenericFileComponent.java:67)
at org.apache.camel.component.file.GenericFileComponent.createEndpoint(GenericFileComponent.java:37)
at org.apache.camel.impl.DefaultComponent.createEndpoint(DefaultComponent.java:123)
at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:514)
at org.apache.camel.impl.DefaultCamelContext.getEndpoint(DefaultCamelContext.java:547)
Is there a way to turn off this "date:" lookup? Why does it try to interpret stuff coming from log at all? I think it should not be touched in any way?!
Edit, very easy to reproduce in test:
public class LogTest {
private Logger log = LoggerFactory.getLogger(LogTest.class);
#Test
public void test() {
log.info("${date:now:buhu}");
}
}
It is crucial to us ${date:} - only "data:now" is working.
So this problem is completely independent from camel, but camel uses ${date:...} pattern for several things. Here is a simple route that reproduces the problem - the exception will be thrown on camel set up phase - no test code needed - logging level must be "debug"!:
public class LogTest extends CamelTestSupport{
private Logger log = LoggerFactory.getLogger(LogTest.class);
#Test
public void test() {
//log.info("${date:now:yyyyMMdd-HHmmss}");
}
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:a").to("file:./?fileName=${date:now:yyyyMMdd-HHmmss}ID.${id}.gz");
}
};
}
}

This issue was fixed in 2.7 version of Log4j2.
The solution is to upgrade to that version (or higher) and add in the pattern attribute the option "{nolookups}" to %msg .
%msg{nolookups}
For example
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{1} %L %M %t - %msg{nolookups}%n%xEx%n" />

The problem can be avoided, if the simple-Expression is written as $simple{..} instead of ${..}. Then log4j2 won't use his Date-Lookup.
So, if you change your Route from:
from("direct:a").to("file:./?fileName=${date:now:yyyyMMdd-HHmmss}ID.${id}.gz");
to:
from("direct:a").to("file:./?fileName=$simple{date:now:yyyyMMdd-HHmmss}ID.${id}.gz");
it should work, even if you debug Camel.

To disable the date lookup locally, you can add a "$" in front of the expression:
log.info("$${date:now:buhu}");
This will print ${date:now:buhu} instead of throwing an exception printing the stack trace.
As for how to avoid this using Camel, I'm not sure. The cleanest fix would probably be a log4j2 update to disable their DateLookup feature. A temporary fix is to disable DEBUG level logs from the org.apache.camel package:
<loggers>
<logger name="org.apache.camel" level="INFO" />
<root level="debug">
<appender-ref ref="Console" />
</root>
</loggers>
It's not ideal, but we can increase the log level if we ever need to debug Camel context creation since the log statements are not necessary for general everyday development.

The correct solution is now to upgrade the log4j-core library to 2.15.0 or above. At time of writing, the latest and current recommended version is 2.16.0.
The variable substitutions happening in logged messages here are symptoms of the same feature exploited in CVE-2021-44228, aka Log4Shell.
The feature is disabled by default in 2.15.0 and removed in 2.16.0.
It's not news to anyone by now, but it's really important to take steps to disable this feature, as a security measure, even if not using Apache Camel or encountering the issue as described.
As an aside, I found this question when searching for early warning signs of the Log4Shell vulnerability. I've quoted it in my write-up.

Related

camel snmp can't resive snmpversion=3 info

When I use came-snmp resive snmp info which version is 3, it can't go to the process method.
#Component
public class SnmpCollect extends RouteBuilder {
#Override
public void configure() throws Exception {
from("snmp:0.0.0.0:162?protocol=udp&type=TRAP&snmpVersion=3&securityName=test").process(new Processor() {
#Override
public void process(Exchange arg0) throws Exception {
}
}
}
Camel xml config:
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
<routeBuilder ref="snmpCollect"/>
</camelContext>
But when the snmp info which version is 1 or 2 is coming, it can go to the process method.
What's wrong with it, and how to make it work for "snmpVersion=3" info?
Camel Version is 2.20.1
Let me try to answer your question by providing some info based in what I've found.
Seems that he requirements and interfaces from v1 and v2 version differ from v3, so it doesn't like to work just updating the version. The mainly difference, from what I've seen, is that you need to provide a security model to v3. I saw that you are passing it via parameters, but have you got the chance to check the security requirements?
When I use the TrapTest where is on the camel-snmp github “github.com/apache/camel/blob/master/components/camel-snmp/s‌​rc/…”,it‘s ok.But when I change the snmpVersion to SnmpConstants.version3,it's also error
That's because the interface changed and the test should rely on ScopedPDU model instead of the base class PDU. Also the security model isn't set up in this test:
org.snmp4j.MessageException: Message processing model 3 returned error: Unsupported security model
Unfortunately there isn't any example using camel-snmp with v3, but you could take a look into this example using the inner component snmp4j.

Why does Jasypt try to decrypt Camel Property Placeholders, regardless of the ENC( prefix?

In my Blueprint application deployed in JBoss Fuse 6.1.0-379, I want to secure the password I use for creating a database connection. I read this article and added <enc:property-placeholder> to the blueprint configuration. However my blueprint configuration has many property placeholders, and it seems that the Jasypt Placeholder Resolver is trying to decrypt all the placeholders I define in my Camel Context. When the Blueprint Context starts up, I get the following exception:
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
I created a test bundle with a Blueprint Context which contains only one placeholder property defined in the Camel Context, without using the encrypted ENC() placeholder syntax. I just added <enc:property-placeholder> and the bundle failed to start with same exception (org.jasypt.exceptions.EncryptionOperationNotPossibleException).
Is this desired behavior?
My Blueprint configuration:
<?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&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>
EDIT: Response from RedHat Support
So this is a known issue, and theres a couple of Jira issues for it (here and here), and it appears as if the issue has been resolved in newer versions of Camel. I have tested with version 2.12.0.redhat-611412, provided by the patch named jboss-fuse-6.1.0.redhat-379-r1p3, and the exception is no longer being thrown.
Regardless of what I have said previously, im quite happy with this implementation. I would want an exception to be thrown if it couldnt decrypt a value which was actaully encrypted, and that is exactly what happens. I modified the encrypted value to ENC(invalid_and_should_throw_exception), and an exception was thrown exactly like I would expect it to.
Caused by: org.jasypt.exceptions.EncryptionOperationNotPossibleException
EDIT: A more concise Answer
Camel-Blueprint behaves differently to Camel-Core, in regards to the way that it resolves property placeholder values. Camel-Core requires the developer to define a Camel Property Placeholder Resolver, which resolves properties in the Camel Context, for the camel property syntax [1]. Obviously the reasoning behind this is to avoid conflicts between the spring property syntax [2] and the Camel Simple Expression Language syntax [3]. The developer has the choice to optionally bridge the Spring Property Placeholder Resolver with Camel by adding extra configuration.
[1 - Camel Property Syntax]
{{org.my.prop}}
[2 - Spring Property Syntax]
${org.my.prop}
[3 - Simple Expression Language Syntax]
${exchange.body}
In Camel-Blueprint, the bridging between the Blueprint Property Placeholder Resolvers and the Camel Context happens automatically. When a Blueprint Camel Context is created, the Blueprint Bundle Context is injected into it. With the Blueprint Bundle Context, Camel pulls all of the beans out of it and determines if they are assignable to the Apache Aries implementation AbstractPropertyPlaceholder. With each instance of the Property Placeholder Resolvers you have defined, Camel is then capable of calling the resolveProperty method on them, without having to parse the property syntax defined by each of the resolvers.
Because the Jasypt Property Placeholder Resolver expects the placeholder syntax [4], it just ignores everything which dosent match this syntax. Because Camel-Blueprint by-passes that validation which ensures the property syntax, we end up in a scenario where Camel is telling the Jasypt Placeholder Resolver to decrypt every property that we attempt to use in our Camel Context. This of course will throw an exception, because you’re trying to decrypt a property which hasn’t been encrypted.
[4 - Jasypt Blueprint Property Syntax]
ENC(encrypted.value)
Solutions:
Create a class which implements the Jasypt StringEncryptor and holds the StandardPBEStringEncryptor as an attribute. The implemented encrypt and decrypt methods call the encrypt and decrypt methods of the StandardPBEStringEncryptor, but catch any exceptions that are thrown.
This is the solution I gave in my original answer.
This is dangerous, if an encrypted value can’t be decrypted that shouldn’t be ignored. The bundle should not start up, to prevent e.g. your database account from getting locked.
Decrypt values manually before passing them to the Placeholder Resolver.
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.
I’ve gone off this design, it’s basically re-implementing the ConfigurationAdmin service which is provided natively by Karaf (with the addition of decryption which Karaf doesn’t provide), it’s just not as good as the one Karaf provides as it is not capable of detecting when application configuration has changed.
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.
I have raised a support ticket with Redhat through our support contract, I'll keep you updated if anything comes of it.
Original Answer:
I think I figured this one out. According to the camel documentation, in blueprint camel is capable of detecting that a blueprint placeholder resolver is present, and attempts to use that to resolve its properties.
The problem with this is that it does not care what the placeholder prefix and suffix is, it just goes ahead and uses it regarless. The Jasypt placeholder resolver has been desgined so that it is only even invoked if the placeholder prefix is "ENC(" and the suffix is ")", remember Camel dosent care about this. Camel passes its unresolved properties to the Jasypt property resolver, which of course attempts to decrypt them. Because they are not encrypted, an exception is thrown.
To get around this, I have created a custom encryptor which implements the Jasypt StringEncryptor. The custom encryptor contains an instance of the StandardPBEStingEncryptor, and uses that to do the actual encryption/ decryption. The key difference is that Exceptions are caught and ignored, so if an Exception is thrown trying to decrypt a camel property which isnt encrypted, then it is ignored and the application continues as normal.
The Java Class:
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;
}
}
The Blueprint configuration:
<enc:property-placeholder>
<enc:encryptor class="uk.co.test.CustomEncryptor">
<argument value="myPass" />
</enc:encryptor>
</enc:property-placeholder>

How to resolve "You have not started an Objectify context" in JUnit?

I've got some Objectify test code running in JUnit and I'm getting this error:
java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.
at com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44)
at com.googlecode.objectify.impl.ref.LiveRef.<init>(LiveRef.java:31)
at com.googlecode.objectify.Ref.create(Ref.java:26)
at com.googlecode.objectify.Ref.create(Ref.java:32)
at com.netbase.followerdownloader.repository.DownloadTaskRepositoryImpl.create(DownloadTaskRepositoryImpl.java:35)
at com.netbase.followerdownloader.repository.DownloadTaskRepositoryImplTest.setUp(DownloadTaskRepositoryImplTest.java:45)
How do I resolve this for test code?
Jeff Schnitzer answered this here: https://groups.google.com/forum/#!topic/objectify-appengine/8HinahG7irg. That link points to https://groups.google.com/forum/#!topic/objectify-appengine/O4FHC_i7EGk where Jeff suggests the following quick and dirty workaround:
My #BeforeMethod starts an objectify context (ObjectifyService.begin())
My #AfterMethod closes the objectify context
Jeff suggests we use ObjectifyService.run() instead but admits it's more work.
Here's how my implementation looks:
public class DownloadTaskRepositoryImplTest {
// maximum eventual consistency (see https://cloud.google.com/appengine/docs/java/tools/localunittesting)
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setDefaultHighRepJobPolicyUnappliedJobPercentage(100));
private Closeable closeable;
#Before
public void setUp() {
helper.setUp();
ObjectifyRegistrar.registerDataModel();
closeable = ObjectifyService.begin();
}
#After
public void tearDown() {
closeable.close();
helper.tearDown();
}
I also had this issue and noticed that I had not added the ObjectifyFilter to my web.xml
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I also had to include Objectify and guava jars in my WEB-INF>lib directory and include them in my build path.
I was facing the same error and this solusion worked for me
I have an app based on Endpoints that uses Objectify. When I leave it with the default/automatic scaling, everything works great. Once I enable basic scaling, though, I get the following exception when executing the endpoint method:
[INFO] java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.
[INFO] at com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44)
[INFO] at com.myco.myapp.dao.datastore.OfyService.ofy(OfyService.java:62)
The good news is that this goes away when you enable RequestDispatcher
support in the web.xml file like so. I think this is a documentation
issue, then, but I didn't know if everyone would agree if I edited the
Wiki page directly. Here is the proposed web.xml entry, which worked
for me:
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Improving michael-osofsky answer, I add this to my ofy helper class
public static void registerDataModel() {
try {
factory().register(Profile.class);
} catch (Exception e){
e.printStackTrace();
}
}
and remplace
ObjectifyRegistrar.registerDataModel();
for this
OfyService.registerDataModel();
OfyService.java
public static void registerDataModel() {
try {
factory().register(Profile.class);
} catch (Exception e){
e.printStackTrace();
}
}
As Jeff Schnitzer says in the link provided by Michael Osofsky:
In your tests you should have some notion of a 'request' even if it is just conceptual. If "each test is a request by itself", then you can use #Before/#After in conjunction with ObjectifyService.begin() to demarcate the requests. However, this is probably not actually how your tests work - it isn't how my tests work.
He then goes on to say:
This would be prettier with JDK8 closures but the idea is straightforward - you're wrapping some unit of work in a context which represents a request. It would probably be smart to add even more context like authentication in that wrapper too.
I came up with the following implementation of his idea. With the solution below, you can ensure each call to a servlet handler gets a fresh Objectify session while still making your servlet handler calls in a single line of code. It also decouples your tests from explicitly worrying about Objectify, and allows you to add additional non-Objectify context around your servlet handlers.
My solution below works with Objectify 5.1.22. I tried using Objectify 6+, but I had problems that seem to be related to this.
First, define a custom Supplier that is able to capture the exceptions thrown by a servlet handler.
#FunctionalInterface
public interface ServletSupplier<T> {
T get()
throws ServletException, IOException;
}
Next, define a wrapper method that accepts your new custom Supplier as an input, and wrap the call to ServletSupplier.get() in a try-with-resources block that calls ObjectifyService.begin(). You must also register your entity classes before calling ServletSupplier.get().
public <T> T runInServletContext(ServletSupplier<T> servletMethod)
throws ServletException, IOException {
try (Closeable session = ObjectifyService.begin()) {
ObjectifyService.register(MyObj.class);
return servletMethod.get();
}
}
Finally, anywhere in your tests that you call the servlet handler you should do so using the wrapper method.
MyObj myObjPost = runInServletContext(() -> getServlet().doPost(request, response));
// Assert results of doPost call.
MyObj myObjGet = runInServletContext(() -> getServlet().doGet(request, response));
// Assert results of doGet call.
Just in case someone ends up here (as I originally did) looking up the same problem but for the ktor "main.kt" server instead of unit tests...
After looking at the ObjectifyFilter source code, I added
val closer = ObjectifyService.begin()
... real service here ...
closer.close()
around my actual servlet code and that fixed the problem.

Camel CXF throwing AssertionBuilderRegistryImpl exception

cannot figure out what is going on with this - trying to set up a route to just see cxf connect to a soap web service (I don't care about the actual data and don't expect the data to actually 'work', but it keeps throwing an exception I don't understand:
I wonder if I'm configuring it correctly.
I was thinking it might be a missing jar, but strated causing dependency conflicts when I tried to bring in other Jars
I'm using a maven dependency "camel-cxf" to load in all my jar configuration
"Reason: org.apache.cxf.bus.extension.ExtensionException: Could not load extension class org.apache.cxf.ws.policy.AssertionBuilderRegistryImpl."
The exact error is
"Failed to create Producer for endpoint: Endpoint[cxf://http://wsf.cdyne.com/WeatherWS/Weather.asmx?dataFormat=MESSAGE&portName=WeatherSoap&serviceClass=prototypes.CxfExample%24GetWeatherInformationSoapIn&serviceName=Weather&wsdlURL=http%3A%2F%2Fwsf.cdyne.com%2FWeatherWS%2FWeather.asmx%3FWSDL]. Reason: org.apache.cxf.bus.extension.ExtensionException: Could not load extension class org.apache.cxf.ws.policy.AssertionBuilderRegistryImpl."
The code I'm using to cause this is
camel.addComponent( "cxf", new CxfComponent() );
camel.addRoutes( new RouteBuilder() {
#Override
public void configure() throws Exception {
from( "timer://sometimer?delay=1s")
.to( "cxf://http://wsf.cdyne.com/WeatherWS/Weather.asmx"
+"?wsdlURL=http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL"
+"&dataFormat=MESSAGE"
+"&serviceClass=prototypes.CxfExample$GetWeatherInformationSoapIn"
+"&serviceName=Weather"
+"&portName=WeatherSoap"
);
}
});
camel.start();
Thread.sleep( 10000 );
camel.stop();
I think I have 'solved' it -
mvn:camel-cfx dependency is not enough
you need mvn:neethi dependency too
the AssertationBuildImpl class extends from a class that is not included in the jar-set for mvn:camel-cfx, which makes AssertationBuildImpl appear listed as a known class in the ide, but doesn't get class-loaded at runtime
this was a horrendous problem to track down, by analysing source-code of third-parties

Log to a database using log4j

Since in log4j javadoc is
WARNING: This version of JDBCAppender is very likely to be completely replaced in the future. Moreoever, it does not log exceptions.
What should I do to log to a database?
If you are looking for a database appender which not only works, but also supports connection pooling, is maintained and properly documented, than consider logback's DBAppender.
Ironically enough, the warning in the javadocs about removing JDBCAppender in future versions of log4j was written by me.
You can use an alternative appender, but really Log4j 1.2 is going to be around and standard for a long time. They developed DBAppender as part of their receivers companions, which isn't officially released, but you can download the source code and get your own going as well.
Unless the issue of not logging exceptions bothers you, JDBCAppender is just fine. Any further upgrade to 2.0 is going to be more radical than just changing JDBCAppender (if 2.0 happens), so I wouldn't worry about using it, despite the warning. They clearly don't have a solid roadmap or timeline to introducing a new version, and 1.2.15 was released in 2007.
**log4j.properties file**
# Define the root logger with appender file
log4j.rootLogger = DEBUG, DB
# Define the DB appender
log4j.appender.DB=org.apache.log4j.jdbc.JDBCAppender
# Set JDBC URL
log4j.appender.DB.URL=jdbc:mysql://localhost/log
# Set Database Driver
log4j.appender.DB.driver=com.mysql.jdbc.Driver
# Set database user name and password
log4j.appender.DB.user=root
log4j.appender.DB.password=root
# Set the SQL statement to be executed.
log4j.appender.DB.sql=INSERT INTO actionlg(user_id, dated, logger, level, message) values('%X{userId}',' %d{yyyy-MM-dd-HH-mm}','%C','%p','%m')
# Define the layout for file appender
log4j.appender.DB.layout=org.apache.log4j.PatternLayout
**Java Class**
Log4jExamples.java
import java.sql.*;
import java.io.*;
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
public class Log4jExample {
/* Get actual class name to be printed on */
static Logger log = Logger.getLogger(Log4jExample.class.getName());
public static void main(String[] args)throws IOException,SQLException{
log.error("Error");
MDC.put("userId", "1234");
}
}
**libs required**
- mysql-connector-java-3.1.8-bin.jar
- log4j-1.2.17.jar

Resources