Skip to content

Support separate logger for sensitive information (take 2) #168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions src/main/java/net/authorize/util/HttpCallTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
*
*/
public class HttpCallTask implements Callable<ANetApiResponse> {
private static Log logger = LogFactory.getLog(HttpCallTask.class);
private static Log loggerSensitive = LogFactory.getLog(SensitiveLogger.class);
private static Log filteredLogger = new SensitiveFilterLogWrapper(LogFactory.getLog(HttpUtility.class));

Environment env = null;
ANetApiRequest request = null;
Expand Down Expand Up @@ -82,7 +83,11 @@ public ANetApiResponse call() throws Exception {
}
}
}
LogHelper.debug(logger, "Raw Response: '%s'", buffer.toString());
if (loggerSensitive.isDebugEnabled()) {
LogHelper.debug(loggerSensitive, "Raw Response: '%s'", buffer.toString());
} else if (filteredLogger.isDebugEnabled()) {
LogHelper.debug(filteredLogger, "Raw Response: '%s'", buffer.toString());
}
// handle HTTP errors
if (0 == buffer.length()) {
response = createErrorResponse(httpResponse, null);
Expand Down Expand Up @@ -117,7 +122,7 @@ public ANetApiResponse call() throws Exception {
{
response = (ANetApiResponse) localResponse;
} else {
LogHelper.warn( logger, "Unknown ResponseType: '%s'", localResponse);
LogHelper.warn( filteredLogger, "Unknown ResponseType: '%s'", localResponse);
}
}
}
Expand Down Expand Up @@ -158,7 +163,7 @@ private void setErrorResponse(List<Message> messages, HttpResponse httpResponse)
String text = "Unknown Error";
if (null != httpResponse.getStatusLine())
{
LogHelper.warn( logger, "Error deserializing response to '%s'", this.classType);
LogHelper.warn( filteredLogger, "Error deserializing response to '%s'", this.classType);

code = String.format("%d", httpResponse.getStatusLine().getStatusCode());
if (null != httpResponse.getStatusLine().getReasonPhrase()) { text = httpResponse.getStatusLine().getReasonPhrase();}
Expand All @@ -172,7 +177,7 @@ private void setErrorResponse(List<Message> messages, Exception exception) {
messages.add(errorMessage);
String code = "Error";
String text = "Unknown Error";
LogHelper.error( logger, "Http request execute failed: '%s'", exception.getMessage());
LogHelper.error( filteredLogger, "Http request execute failed: '%s'", exception.getMessage());
code = exception.getClass().getCanonicalName();
//code = exception.getClass().getTypeName();// requires java1.8
text = exception.getMessage();
Expand All @@ -184,6 +189,6 @@ private void setErrorResponse(List<Message> messages, Exception exception) {
private void setErrorMessageValues(String code, String text) {
errorMessage.setCode(code);
errorMessage.setText(text);
LogHelper.warn(logger, "Adding ErrorMessage: Code: '%s', Text: '%s'", code, text);
LogHelper.warn(filteredLogger, "Adding ErrorMessage: Code: '%s', Text: '%s'", code, text);
}
}
31 changes: 20 additions & 11 deletions src/main/java/net/authorize/util/HttpUtility.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
*/
public final class HttpUtility {

private static Log logger = LogFactory.getLog(HttpUtility.class);
private static Log loggerSensitive = LogFactory.getLog(SensitiveLogger.class);
private static Log filteredLogger = new SensitiveFilterLogWrapper(LogFactory.getLog(HttpUtility.class));

static int httpConnectionTimeout = Environment.getIntProperty(Constants.HTTP_CONNECTION_TIME_OUT);
static int httpReadTimeout = Environment.getIntProperty(Constants.HTTP_READ_TIME_OUT);
Expand Down Expand Up @@ -68,7 +69,7 @@ static HttpPost createPostRequest(Environment env, ANetApiRequest request) throw

if(null != request) {
postUrl = new URI(env.getXmlBaseUrl() + "/xml/v1/request.api");
logger.debug(String.format("Posting request to Url: '%s'", postUrl));
filteredLogger.debug(String.format("Posting request to Url: '%s'", postUrl));
httpPost = new HttpPost(postUrl);
httpPost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false);

Expand All @@ -80,7 +81,11 @@ static HttpPost createPostRequest(Environment env, ANetApiRequest request) throw
httpPost.setHeader("Content-Type", "text/xml; charset=utf-8");

String xmlRequest = XmlUtility.getXml(request);
logger.debug(String.format("Request: '%s%s%s'", LogHelper.LineSeparator, xmlRequest, LogHelper.LineSeparator));
if (loggerSensitive.isDebugEnabled()) {
loggerSensitive.debug(String.format("Request: '%s%s%s'", LogHelper.LineSeparator, xmlRequest, LogHelper.LineSeparator));
} else if (filteredLogger.isDebugEnabled()) {
filteredLogger.debug(String.format("Request: '%s%s%s'", LogHelper.LineSeparator, xmlRequest, LogHelper.LineSeparator));
}
httpPost.setEntity(new StringEntity(xmlRequest, HTTP.UTF_8));
}

Expand All @@ -103,11 +108,15 @@ public static <T> ANetApiResponse postData(Environment env, ANetApiRequest reque

try {
response = future.get();
logger.debug(String.format("Response: '%s'", response));
if (loggerSensitive.isDebugEnabled()) {
loggerSensitive.debug(String.format("Response: '%s'", response));
} else if (filteredLogger.isDebugEnabled()) {
filteredLogger.debug(String.format("Response: '%s'", response));
}
} catch (InterruptedException ie) {
logger.error(String.format("Http call interrupted Message: '%s'", ie.getMessage()));
filteredLogger.error(String.format("Http call interrupted Message: '%s'", ie.getMessage()));
} catch (ExecutionException ee) {
logger.error(String.format("Execution error for http post Message: '%s'", ee.getMessage()));
filteredLogger.error(String.format("Execution error for http post Message: '%s'", ee.getMessage()));
}

return response;
Expand All @@ -125,9 +134,9 @@ public static String convertStreamToString(InputStream is) {
try {
bomStripperStream = new BOMStripperInputStream(is) ;
} catch (NullPointerException e) {
logger.warn(String.format("Exception creating BOMStripperInputStream: '%s'", e.getMessage()));
filteredLogger.warn(String.format("Exception creating BOMStripperInputStream: '%s'", e.getMessage()));
} catch (IOException e) {
logger.warn(String.format("Exception creating BOMStripperInputStream: '%s'", e.getMessage()));
filteredLogger.warn(String.format("Exception creating BOMStripperInputStream: '%s'", e.getMessage()));
}
if ( null == bomStripperStream) {
throw new NullPointerException("Unable to create BomStriper from the input stream");
Expand All @@ -137,7 +146,7 @@ public static String convertStreamToString(InputStream is) {
try {
bomStripperStream.skipBOM();
} catch (IOException e) {
logger.warn(String.format("Exception setting skip for BOMStripperInputStream: '%s'", e.getMessage()));
filteredLogger.warn(String.format("Exception setting skip for BOMStripperInputStream: '%s'", e.getMessage()));
}

String line = null;
Expand All @@ -153,7 +162,7 @@ public static String convertStreamToString(InputStream is) {
sb.append(line).append(LogHelper.LineSeparator);
}
} catch (IOException e) {
logger.warn(String.format("Exception reading data from Stream: '%s'", e.getMessage()));
filteredLogger.warn(String.format("Exception reading data from Stream: '%s'", e.getMessage()));
} finally {

tryClose( reader);
Expand All @@ -171,7 +180,7 @@ private static <T extends Closeable> void tryClose( T closableObject) {
try {
closableObject.close();
} catch (Exception e) {
logger.warn(String.format("Exception closing '%s': '%s'", closableObject.getClass(), e.getMessage()));
filteredLogger.warn(String.format("Exception closing '%s': '%s'", closableObject.getClass(), e.getMessage()));
}
}
}
Expand Down
178 changes: 178 additions & 0 deletions src/main/java/net/authorize/util/SensitiveFilterLogWrapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package net.authorize.util;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class SensitiveFilterLogWrapper implements Log {

private static final String SENSITIVE_CONFIG_FILE_NAME = "/AuthorizedNetSensitiveTagsConfig.json";

private static Pattern[] cardPatterns;

private static Pattern[] tagPatterns;
private static String[] tagReplacements;
private static Gson gson;
private Log delegate;

public SensitiveFilterLogWrapper(Log delegate) {
this.delegate = delegate;

parseConfiguration(delegate);
}

private void parseConfiguration(Log delegate) {
try {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(SensitiveDataConfigType.class, new SensitiveTagsDeserializer());
gson = gsonBuilder.create();

InputStream in = getClass().getResourceAsStream(SENSITIVE_CONFIG_FILE_NAME);
Closeable closeableResource = in;
if (null != in) {
try {
InputStreamReader inputStreamReader = new InputStreamReader(in);
closeableResource = inputStreamReader;
BufferedReader reader = new BufferedReader(inputStreamReader);
closeableResource = reader;
SensitiveDataConfigType configType = gson.fromJson(reader, SensitiveDataConfigType.class);
cardPatterns = new Pattern[configType.sensitiveStringRegexes.length];

for (int i = 0; i < configType.sensitiveStringRegexes.length; i++) {
cardPatterns[i] = Pattern.compile(configType.sensitiveStringRegexes[i]);
}

int noOfSensitiveTags = configType.sensitiveTags.length;
tagPatterns = new Pattern[noOfSensitiveTags];
tagReplacements = new String[noOfSensitiveTags];

for (int j = 0; j < noOfSensitiveTags; j++) {
String tagName = configType.sensitiveTags[j].tagName;
String pattern = configType.sensitiveTags[j].pattern;
String replacement = configType.sensitiveTags[j].replacement;

if (pattern != null && !pattern.isEmpty())
tagPatterns[j] = Pattern.compile("<" + tagName + ">" + pattern + "</" + tagName + ">");
else
tagPatterns[j] = Pattern.compile("<" + tagName + ">" + ".+" + "</" + tagName + ">");
tagReplacements[j] = "<" + tagName + ">" + replacement + "</" + tagName + ">";
}
} finally {
closeableResource.close();
}
} else {
delegate.error("Resource " + SENSITIVE_CONFIG_FILE_NAME + " not found when configuring SensitiveFilterLogWrapper");
}
} catch (Exception e) {
delegate.error("Something went wrong configuring the SensitiveFilterLogWrapper", e);
}
}

public static String maskCreditCards(String str) {
for (int i = 0; i < cardPatterns.length; i++) {
str = cardPatterns[i].matcher(str).replaceAll("XXXX");
}
return str;
}

public static String maskSensitiveXmlString(String str) {
for (int i = 0; i < tagPatterns.length; i++) {
str = tagPatterns[i].matcher(str).replaceAll(tagReplacements[i]);
}
return str;
}

public String filterSensitiveInformation(Object messageObject) {
if (null == messageObject) {
return null;
}

String message = messageObject.toString();
try {
String messageWithMaskedXml = SensitiveFilterLogWrapper.maskSensitiveXmlString(message);
String messageWithMaskedCardNumber = SensitiveFilterLogWrapper.maskCreditCards(messageWithMaskedXml);
return messageWithMaskedCardNumber;
} catch (Exception e) {
return "Error masking message: " + e.getMessage();
}
}

public void debug(Object arg0, Throwable arg1) {
delegate.debug(filterSensitiveInformation(arg0), arg1);
}

public void debug(Object arg0) {
delegate.debug(filterSensitiveInformation(arg0));
}

public void error(Object arg0, Throwable arg1) {
delegate.error(filterSensitiveInformation(arg0), arg1);
}

public void error(Object arg0) {
delegate.error(filterSensitiveInformation(arg0));
}

public void fatal(Object arg0, Throwable arg1) {
delegate.fatal(filterSensitiveInformation(arg0), arg1);
}

public void fatal(Object arg0) {
delegate.fatal(filterSensitiveInformation(arg0));
}

public void info(Object arg0, Throwable arg1) {
delegate.info(filterSensitiveInformation(arg0), arg1);
}

public void info(Object arg0) {
delegate.info(filterSensitiveInformation(arg0));
}

public boolean isDebugEnabled() {
return delegate.isDebugEnabled();
}

public boolean isErrorEnabled() {
return delegate.isErrorEnabled();
}

public boolean isFatalEnabled() {
return delegate.isFatalEnabled();
}

public boolean isInfoEnabled() {
return delegate.isInfoEnabled();
}

public boolean isTraceEnabled() {
return delegate.isTraceEnabled();
}

public boolean isWarnEnabled() {
return delegate.isWarnEnabled();
}

public void trace(Object arg0, Throwable arg1) {
delegate.trace(filterSensitiveInformation(arg0), arg1);
}

public void trace(Object arg0) {
delegate.trace(filterSensitiveInformation(arg0));
}

public void warn(Object arg0, Throwable arg1) {
delegate.warn(filterSensitiveInformation(arg0), arg1);
}

public void warn(Object arg0) {
delegate.warn(filterSensitiveInformation(arg0));
}
}
5 changes: 5 additions & 0 deletions src/main/java/net/authorize/util/SensitiveLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package net.authorize.util;

public class SensitiveLogger {

}