Skip to content

Commit

Permalink
Add environment lookup and regex replacement for pattern layout
Browse files Browse the repository at this point in the history
  • Loading branch information
rgoers committed Oct 19, 2011
1 parent c0e509d commit a538903
Show file tree
Hide file tree
Showing 15 changed files with 408 additions and 46 deletions.
Expand Up @@ -182,7 +182,7 @@ private RolloverFrequency calculateFrequency(String pattern) {

private PatternParser createPatternParser() {

return new PatternParser(KEY, null);
return new PatternParser(null, KEY, null);
}

private boolean patternContains(String pattern, char[] chars) {
Expand Down
Expand Up @@ -31,6 +31,8 @@
import org.apache.logging.log4j.core.filter.Filterable;
import org.apache.logging.log4j.core.filter.Filters;
import org.apache.logging.log4j.core.helpers.NameUtil;
import org.apache.logging.log4j.core.lookup.Interpolator;
import org.apache.logging.log4j.core.lookup.StrLookup;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;
import org.apache.logging.log4j.status.StatusLogger;

Expand Down Expand Up @@ -74,6 +76,8 @@ public class BaseConfiguration extends Filterable implements Configuration {

private boolean started = false;

private ConcurrentMap<String, Object> componentMap = new ConcurrentHashMap<String, Object>();

/**
* Constructor.
*/
Expand Down Expand Up @@ -112,6 +116,14 @@ public void stop() {
protected void setup() {
}

public Object getComponent(String name) {
return componentMap.get(name);
}

public void addComponent(String name, Object obj) {
componentMap.putIfAbsent(name, obj);
}

protected void doConfigure() {
boolean setRoot = false;
boolean setLoggers = false;
Expand All @@ -121,8 +133,17 @@ protected void doConfigure() {
continue;
}
if (child.getName().equalsIgnoreCase("properties")) {
subst = (StrSubstitutor) child.getObject();
} else if (child.getName().equalsIgnoreCase("appenders")) {
if (subst.getVariableResolver() == null) {
subst.setVariableResolver((StrLookup) child.getObject());
} else {
logger.error("Properties declaration must be the first element in the configuration");
}
continue;
}
else if (subst.getVariableResolver() == null) {
subst.setVariableResolver(new Interpolator(null));
}
if (child.getName().equalsIgnoreCase("appenders")) {
appenders = (ConcurrentMap<String, Appender>) child.getObject();
} else if (child.getName().equalsIgnoreCase("filters")) {
setFilters((Filters) child.getObject());
Expand Down
Expand Up @@ -55,4 +55,8 @@ public interface Configuration extends Filtering {
StrSubstitutor getSubst();

void createConfiguration(Node node, LogEvent event);

Object getComponent(String name);

void addComponent(String name, Object object);
}
Expand Up @@ -19,6 +19,7 @@
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.lookup.Interpolator;
import org.apache.logging.log4j.core.lookup.MapLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;
import org.apache.logging.log4j.core.lookup.StrSubstitutor;

import java.util.HashMap;
Expand All @@ -31,16 +32,16 @@
public class PropertiesPlugin {

@PluginFactory
public static StrSubstitutor configureSubstitutor(@PluginElement("properties") Property[] properties) {
public static StrLookup configureSubstitutor(@PluginElement("properties") Property[] properties) {
if (properties == null) {
return new StrSubstitutor(new Interpolator(null));
return new Interpolator(null);
}
Map<String, String> map = new HashMap<String, String>();

for (Property prop : properties) {
map.put(prop.getName(), prop.getValue());
}

return new StrSubstitutor(new Interpolator(new MapLookup(map)));
return new Interpolator(new MapLookup(map));
}
}
Expand Up @@ -18,13 +18,17 @@
package org.apache.logging.log4j.core.layout;

import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttr;
import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.helpers.OptionConverter;
import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;
import org.apache.logging.log4j.core.pattern.PatternConverter;
import org.apache.logging.log4j.core.pattern.PatternParser;
import org.apache.logging.log4j.core.pattern.RegexReplacement;

import java.nio.charset.Charset;
import java.util.List;
Expand Down Expand Up @@ -415,7 +419,7 @@ public class PatternLayout extends AbstractStringLayout {
*/
private List<PatternConverter> converters;

private static final String KEY = "Converter";
public static final String KEY = "Converter";

/**
* Conversion pattern.
Expand All @@ -427,13 +431,20 @@ public class PatternLayout extends AbstractStringLayout {
*/
private boolean handlesExceptions;

/**
* The current Configuration.
*/
private final Configuration config;

private final RegexReplacement replace;

/**
* Constructs a EnhancedPatternLayout using the DEFAULT_LAYOUT_PATTERN.
* <p/>
* The default pattern just produces the application supplied message.
*/
public PatternLayout() {
this(DEFAULT_CONVERSION_PATTERN, Charset.defaultCharset());
this(null, null, DEFAULT_CONVERSION_PATTERN, Charset.defaultCharset());
}

/**
Expand All @@ -442,18 +453,30 @@ public PatternLayout() {
* The default pattern just produces the application supplied message.
*/
public PatternLayout(final String pattern) {
this(pattern, Charset.defaultCharset());
this(null, null, pattern, Charset.defaultCharset());
}

/**
* Constructs a EnhancedPatternLayout using the DEFAULT_LAYOUT_PATTERN.
* <p/>
* The default pattern just produces the application supplied message.
*/
public PatternLayout(Configuration config, final String pattern) {
this(config, null, pattern, Charset.defaultCharset());
}

/**
* Constructs a EnhancedPatternLayout using the supplied conversion pattern.
*
* @param pattern conversion pattern.
*/
public PatternLayout(final String pattern, final Charset charset) {
public PatternLayout(Configuration config, final RegexReplacement replace, final String pattern,
final Charset charset) {
super(charset);
this.replace = replace;
this.conversionPattern = pattern;
PatternParser parser = createPatternParser();
this.config = config;
PatternParser parser = createPatternParser(config);
converters = parser.parse((pattern == null) ? DEFAULT_CONVERSION_PATTERN : pattern);
handlesExceptions = parser.handlesExceptions();

Expand All @@ -471,7 +494,7 @@ public void setConversionPattern(final String conversionPattern) {
if (pattern == null) {
return;
}
PatternParser parser = createPatternParser();
PatternParser parser = createPatternParser(this.config);
converters = parser.parse(pattern);
handlesExceptions = parser.handlesExceptions();
}
Expand All @@ -486,12 +509,24 @@ public String formatAs(final LogEvent event) {
for (PatternConverter c : converters) {
c.format(event, buf);
}
return buf.toString();
String str = buf.toString();
if (replace != null) {
str = replace.format(str);
}
return config == null ? str : config.getSubst().replace(event, str);

This comment has been minimized.

Copy link
@mirabilos

mirabilos Dec 12, 2021

From what I can gather, this is where the root cause behind CVE-2021-44228 was introduced.

This comment has been minimized.

Copy link
@mirabilos

mirabilos Dec 13, 2021

2797204 #623 is going to remove this functionality of questionable worth entirely; thanks!

}

private PatternParser createPatternParser() {

return new PatternParser(KEY, LogEventPatternConverter.class);
private PatternParser createPatternParser(Configuration config) {
if (config == null) {
return new PatternParser(config, KEY, LogEventPatternConverter.class);
}
PatternParser parser = (PatternParser) config.getComponent(KEY);
if (parser == null) {
parser = new PatternParser(config, KEY, LogEventPatternConverter.class);
config.addComponent(KEY, parser);
parser = (PatternParser) config.getComponent(KEY);
}
return parser;
}

public String toString() {
Expand All @@ -500,6 +535,8 @@ public String toString() {

@PluginFactory
public static PatternLayout createLayout(@PluginAttr("pattern") String pattern,
@PluginConfiguration Configuration config,
@PluginElement("replace") RegexReplacement replace,
@PluginAttr("charset") String charset) {
Charset c = Charset.isSupported("UTF-8") ? Charset.forName("UTF-8") : Charset.defaultCharset();
if (charset != null) {
Expand All @@ -510,7 +547,7 @@ public static PatternLayout createLayout(@PluginAttr("pattern") String pattern,
}
}
if (pattern != null) {
return new PatternLayout(pattern, c);
return new PatternLayout(config, replace, pattern, c);
}
logger.error("No pattern specified for PatternLayout");
return null;
Expand Down
@@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache license, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the license for the specific language governing permissions and
* limitations under the license.
*/
package org.apache.logging.log4j.core.lookup;

import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;

/**
* Looks up keys from environment variables.
*/
@Plugin(name="env",type="Lookup")
public class EnvironmentLookup implements StrLookup {

/**
* Get the value of the environment variable.
* @param key the key to be looked up, may be null
* @return The value of the environment variable.
*/
public String lookup(String key) {
return System.getenv(key);
}

/**
* Get the value of the environment variable.
* @param event The current LogEvent (is ignored by this StrLookup).
* @param key the key to be looked up, may be null
* @return The value of the environment variable.
*/
public String lookup(LogEvent event, String key) {
return System.getenv(key);
}
}
Expand Up @@ -40,7 +40,7 @@ public class Interpolator implements StrLookup {
private final StrLookup defaultLookup;

public Interpolator(StrLookup defaultLookup) {
this.defaultLookup = defaultLookup;
this.defaultLookup = defaultLookup == null ? new MapLookup(new HashMap<String, String>()) : defaultLookup;
PluginManager manager = new PluginManager("Lookup");
manager.collectPlugins();
Map<String, PluginType> plugins = manager.getPlugins();
Expand Down
Expand Up @@ -27,7 +27,7 @@
* Return the event's rendered message in a StringBuffer.
*/
@Plugin(name="MessagePatternConverter", type="Converter")
@ConverterKeys({"m", "message"})
@ConverterKeys({"m", "msg", "message"})
public final class MessagePatternConverter extends LogEventPatternConverter {

private final String format;
Expand Down

0 comments on commit a538903

Please sign in to comment.