/*
 * Licensed 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.owasp.security.logging.log4j.mask;

import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.rewrite.RewritePolicy;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.slf4j.Log4jMarker;
import org.owasp.security.logging.SecurityMarkers;

/**
 *
 * @author adetlefsen
 */
@Plugin(name = "MaskingRewritePolicy", category = "Core", elementType = "rewritePolicy", printObject = true)
public class MaskingRewritePolicy implements RewritePolicy {

	public static final Object MASKED_PASSWORD = "********";
        
    @PluginFactory
    public static MaskingRewritePolicy createPolicy() {
        return new MaskingRewritePolicy();
    }

	/**
	 * Rewrite the event.
	 * 
	 * @param source
	 *            a logging event that may be returned or used to create a new
	 *            logging event.
	 * @return The LogEvent after rewriting.
	 */
        @Override
	public LogEvent rewrite(LogEvent source) {
		// get the markers for the log event. If no markers, nothing can be
		// tagged confidential and we can return
		Marker sourceMarker = source.getMarker();
		if (sourceMarker == null)
			return source;

		// get the message. If no message we can return
		final Message msg = source.getMessage();
		if (msg == null || !(msg instanceof ParameterizedMessage))
			return source;

		// get the parameters. If no params we can return
		Object[] params = msg.getParameters();
		if (params == null || params.length == 0)
			return source;

		// check if this event is actually marked as confidential. If not,
		// return
		Log4jMarker eventMarker = new Log4jMarker(sourceMarker);
		if (!eventMarker.contains(SecurityMarkers.CONFIDENTIAL))
			return source;

		// we have a message, parameters, a marker, and it is confidential.
		// Process
		for (int i = 0; i < params.length; i++) {
			params[i] = MASKED_PASSWORD;
		}
		Message outMessage = new ParameterizedMessage(msg.getFormat(), params,
				msg.getThrowable());
		LogEvent output = new Log4jLogEvent(source.getLoggerName(),
				source.getMarker(), source.getLoggerFqcn(), source.getLevel(),
				outMessage, source.getThrown(), source.getContextMap(),
				source.getContextStack(), source.getThreadName(),
				source.getSource(), source.getTimeMillis());

		return output;
	}

}

@@ -2728,16 +2728,43 @@
 RD;%0A%09%09%7D%0A
+%09%09%0A%09%09// create new message%0A
 %09%09Messag
@@ -2857,151 +2857,114 @@
 ));%0A
-%09%09LogEvent output = new Log4jLogEvent(source.getLoggerName(),%0A%09%09%09%09source.getMarker(), source.getLoggerFqcn(), source.getLevel(),
+%0A%09%09// build new log event for output%0A%09%09LogEvent output = new Log4jLogEvent.Builder(source)
 %0A%09%09%09%09
-ou
+.se
 tMessage
 , so
@@ -2963,157 +2963,32 @@
 sage
-, source.getThrown(), source.getContextMap(),%0A%09%09%09%09source.getContextStack(), source.getThreadName(),%0A%09%09%09%09source.getSource(), source.getTimeMillis()
+(outMessage).build(
 );%0A
+%09%09
 %0A%09%09r

Add converter for SLF4J to Log4J Markers