Merge pull request #103 from rhauch/dbz-122
DBZ-122 Prevent logging of password configuration property values
This commit is contained in:
commit
3e2d953b1a
@ -58,6 +58,8 @@
|
|||||||
@Immutable
|
@Immutable
|
||||||
public interface Configuration {
|
public interface Configuration {
|
||||||
|
|
||||||
|
public static final Pattern PASSWORD_PATTERN = Pattern.compile(".*password$", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The basic interface for configuration builders.
|
* The basic interface for configuration builders.
|
||||||
*
|
*
|
||||||
@ -734,7 +736,7 @@ public Set<String> keys() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return props.toString();
|
return withMaskedPasswords().asProperties().toString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -781,7 +783,7 @@ public Set<String> keys() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return props.toString();
|
return withMaskedPasswords().asProperties().toString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1442,7 +1444,7 @@ public String getString(String key) {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return asProperties().toString();
|
return withMaskedPasswords().asProperties().toString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1471,7 +1473,83 @@ public String getString(String key) {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return asProperties().toString();
|
return withMaskedPasswords().asProperties().toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new {@link Configuration} that contains the mapped values.
|
||||||
|
*
|
||||||
|
* @param mapper the function that takes a key and value and returns the new mapped value
|
||||||
|
* @return the Configuration with mapped values; never null
|
||||||
|
*/
|
||||||
|
default Configuration mapped(BiFunction<? super String, ? super String, String> mapper) {
|
||||||
|
if (mapper == null) return this;
|
||||||
|
return new Configuration() {
|
||||||
|
@Override
|
||||||
|
public Set<String> keys() {
|
||||||
|
return Configuration.this.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getString(String key) {
|
||||||
|
return mapper.apply(key, Configuration.this.getString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return withMaskedPasswords().asProperties().toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new {@link Configuration} that contains all of the same fields as this configuration, except with masked values
|
||||||
|
* for all keys that end in "password".
|
||||||
|
*
|
||||||
|
* @return the Configuration with masked values for matching keys; never null
|
||||||
|
*/
|
||||||
|
default Configuration withMaskedPasswords() {
|
||||||
|
return withMasked(PASSWORD_PATTERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new {@link Configuration} that contains all of the same fields as this configuration, except with masked values
|
||||||
|
* for all keys that match the specified pattern.
|
||||||
|
*
|
||||||
|
* @param keyRegex the regular expression to match against the keys
|
||||||
|
* @return the Configuration with masked values for matching keys; never null
|
||||||
|
*/
|
||||||
|
default Configuration withMasked(String keyRegex) {
|
||||||
|
if (keyRegex == null) return this;
|
||||||
|
return withMasked(Pattern.compile(keyRegex));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new {@link Configuration} that contains all of the same fields as this configuration, except with masked values
|
||||||
|
* for all keys that match the specified pattern.
|
||||||
|
*
|
||||||
|
* @param keyRegex the regular expression to match against the keys
|
||||||
|
* @return the Configuration with masked values for matching keys; never null
|
||||||
|
*/
|
||||||
|
default Configuration withMasked(Pattern keyRegex) {
|
||||||
|
if (keyRegex == null) return this;
|
||||||
|
return new Configuration() {
|
||||||
|
@Override
|
||||||
|
public Set<String> keys() {
|
||||||
|
return Configuration.this.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getString(String key) {
|
||||||
|
boolean matches = keyRegex.matcher(key).matches();
|
||||||
|
return matches ? "********" : Configuration.this.getString(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return withMaskedPasswords().asProperties().toString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1623,7 +1701,13 @@ default boolean validateAndRecord(Iterable<Field> fields, Consumer<String> probl
|
|||||||
problems.accept("The '" + f.name() + "' value is invalid: " + problem);
|
problems.accept("The '" + f.name() + "' value is invalid: " + problem);
|
||||||
} else {
|
} else {
|
||||||
String valueStr = v.toString();
|
String valueStr = v.toString();
|
||||||
if (v instanceof CharSequence) valueStr = "'" + valueStr + "'";
|
if (v instanceof CharSequence) {
|
||||||
|
if (PASSWORD_PATTERN.matcher((CharSequence) v).matches()) {
|
||||||
|
valueStr = "********"; // mask any fields that we know are passwords
|
||||||
|
} else {
|
||||||
|
valueStr = "'" + valueStr + "'";
|
||||||
|
}
|
||||||
|
}
|
||||||
problems.accept("The '" + f.name() + "' value " + valueStr + " is invalid: " + problem);
|
problems.accept("The '" + f.name() + "' value " + valueStr + " is invalid: " + problem);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -137,8 +137,8 @@ public void configure(Configuration config, HistoryRecordComparator comparator)
|
|||||||
.withDefault(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class)
|
.withDefault(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class)
|
||||||
.withDefault(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class)
|
.withDefault(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class)
|
||||||
.build();
|
.build();
|
||||||
logger.info("KafkaDatabaseHistory Consumer config: " + consumerConfig);
|
logger.info("KafkaDatabaseHistory Consumer config: " + consumerConfig.withMaskedPasswords());
|
||||||
logger.info("KafkaDatabaseHistory Producer config: " + producerConfig);
|
logger.info("KafkaDatabaseHistory Producer config: " + producerConfig.withMaskedPasswords());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -91,4 +92,24 @@ public void shouldCallFunctionOnEachMatchingFieldUsingRegex() {
|
|||||||
assertThat(counter.get()).isEqualTo(6);
|
assertThat(counter.get()).isEqualTo(6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMaskPasswords() {
|
||||||
|
Pattern p = Pattern.compile(".*password$",Pattern.CASE_INSENSITIVE);
|
||||||
|
assertThat(p.matcher("password").matches()).isTrue();
|
||||||
|
assertThat(p.matcher("otherpassword").matches()).isTrue();
|
||||||
|
|
||||||
|
config = Configuration.create()
|
||||||
|
.with("column.password", "warning")
|
||||||
|
.with("column.Password.this.is.not","value")
|
||||||
|
.with("column.truncate.to.20.chars", "20-chars")
|
||||||
|
.with("column.mask.with.20.chars", "20-mask")
|
||||||
|
.with("column.mask.with.0.chars", "0-mask")
|
||||||
|
.with("column.mask.with.chars", "should-not-be-matched")
|
||||||
|
.build();
|
||||||
|
assertThat(config.withMaskedPasswords().toString().contains("warning")).isFalse();
|
||||||
|
assertThat(config.toString().contains("warning")).isFalse();
|
||||||
|
assertThat(config.withMaskedPasswords().getString("column.password")).isEqualTo("********");
|
||||||
|
assertThat(config.getString("column.password")).isEqualTo("warning");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user