/* * Password Management Servlets (PWM) * http://www.pwm-project.org * * Copyright (c) 2006-2009 Novell, Inc. * Copyright (c) 2009-2017 The PWM Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package password.pwm.util.logging; import org.apache.log4j.RollingFileAppender; import password.pwm.PwmApplication; import password.pwm.PwmConstants; import password.pwm.bean.LoginInfoBean; import password.pwm.bean.SessionLabel; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmUnrecoverableException; import password.pwm.http.PwmRequest; import password.pwm.http.PwmSession; import password.pwm.svc.event.AuditEvent; import password.pwm.svc.event.AuditRecord; import password.pwm.svc.event.AuditRecordFactory; import password.pwm.util.java.JavaHelper; import password.pwm.util.java.JsonUtil; import java.io.IOException; import java.time.Instant; import java.util.HashMap; import java.util.Map; /** * @author Jason D. Rivard */ public class PwmLogger { // ------------------------------ FIELDS ------------------------------ private static LocalDBLogger localDBLogger; private static PwmLogLevel minimumDbLogLevel; private static PwmApplication pwmApplication; private static RollingFileAppender fileAppender; private static boolean initialized; private final String name; private final org.apache.log4j.Logger log4jLogger; private final boolean localDBDisabled; public static void markInitialized() { initialized = true; } static void setPwmApplication(final PwmApplication pwmApplication) { PwmLogger.pwmApplication = pwmApplication; if (pwmApplication != null) { initialized = true; } } static void setLocalDBLogger(final PwmLogLevel minimumDbLogLevel, final LocalDBLogger localDBLogger) { PwmLogger.minimumDbLogLevel = minimumDbLogLevel; PwmLogger.localDBLogger = localDBLogger; } static void setFileAppender(final RollingFileAppender rollingFileAppender) { PwmLogger.fileAppender = rollingFileAppender; } public static PwmLogger forClass(final Class className) { return new PwmLogger(className.getName(), false); } public static PwmLogger getLogger(final String name) { return new PwmLogger(name, false); } public static PwmLogger forClass( final Class className, final boolean localDBDisabled ) { return new PwmLogger(className.getName(), localDBDisabled); } public static PwmLogger getLogger(final String name, final boolean localDBDisabled) { return new PwmLogger(name, localDBDisabled); } // --------------------------- CONSTRUCTORS --------------------------- PwmLogger(final String name, final boolean localDBDisabled) { this.name = name; this.localDBDisabled = localDBDisabled; log4jLogger = org.apache.log4j.Logger.getLogger(name); } // --------------------- GETTER / SETTER METHODS --------------------- public String getName() { return name; } // -------------------------- OTHER METHODS -------------------------- private void doPwmRequestLogEvent(final PwmLogLevel level, final PwmRequest pwmRequest, final Object message, final Throwable e) { final PwmSession pwmSession = pwmRequest != null ? pwmRequest.getPwmSession() : null; doPwmSessionLogEvent(level, pwmSession, message, e); } private void doPwmSessionLogEvent(final PwmLogLevel level, final PwmSession pwmSession, final Object message, final Throwable e) { final SessionLabel sessionLabel = pwmSession != null ? pwmSession.getLabel() : null; Object cleanedMessage = message; if (pwmSession != null && message != null) { try { cleanedMessage = PwmLogger.removeUserDataFromString(pwmSession.getLoginInfoBean(), message.toString()); } catch (PwmUnrecoverableException e1) { /* can't be logged */ } } doLogEvent(level, sessionLabel, cleanedMessage, e); } private void doLogEvent(final PwmLogLevel level, final SessionLabel sessionLabel, final Object message, final Throwable e) { final String topic = log4jLogger.getName(); final PwmLogEvent logEvent = PwmLogEvent.createPwmLogEvent(Instant.now(), topic, message.toString(), sessionLabel, e, level); doLogEvent(logEvent); } private void doLogEvent(final PwmLogEvent logEvent) { pushMessageToLog4j(logEvent); try { if (!localDBDisabled && localDBLogger != null && minimumDbLogLevel != null) { if (logEvent.getLevel().compareTo(minimumDbLogLevel) >= 0) { localDBLogger.writeEvent(logEvent); } } if (logEvent.getLevel() == PwmLogLevel.FATAL) { if (!logEvent.getMessage().contains("5039")) { final Map<String,String> messageInfo = new HashMap<>(); messageInfo.put("level",logEvent.getLevel().toString()); messageInfo.put("actor",logEvent.getActor()); messageInfo.put("source",logEvent.getSource()); messageInfo.put("topic",logEvent.getTopic()); messageInfo.put("errorMessage",logEvent.getMessage()); final String messageInfoStr = JsonUtil.serializeMap(messageInfo); final AuditRecord auditRecord = new AuditRecordFactory(pwmApplication).createSystemAuditRecord( AuditEvent.FATAL_EVENT, messageInfoStr ); pwmApplication.getAuditManager().submit(auditRecord); } } } catch (Exception e2) { //nothing can be done about it now; } } private void pushMessageToLog4j(final PwmLogEvent logEvent) { final String wrappedMessage = logEvent.getEnhancedMessage(); final Throwable throwable = logEvent.getThrowable(); final PwmLogLevel level = logEvent.getLevel(); if (initialized) { switch (level) { case DEBUG: log4jLogger.debug(wrappedMessage, throwable); break; case ERROR: log4jLogger.error(wrappedMessage, throwable); break; case INFO: log4jLogger.info(wrappedMessage, throwable); break; case TRACE: log4jLogger.trace(wrappedMessage, throwable); break; case WARN: log4jLogger.warn(wrappedMessage, throwable); break; case FATAL: log4jLogger.fatal(wrappedMessage, throwable); break; default: JavaHelper.unhandledSwitchStatement(level); } } else { System.err.println(logEvent.toLogString()); } } private static String convertErrorInformation(final ErrorInformation info) { return info.toDebugStr(); } public void log(final PwmLogLevel level, final SessionLabel sessionLabel, final CharSequence message) { doLogEvent(level, sessionLabel, message, null); } public void trace(final CharSequence message) { doLogEvent(PwmLogLevel.TRACE, null, message, null); } public void trace(final PwmSession pwmSession, final CharSequence message) { doPwmSessionLogEvent(PwmLogLevel.TRACE, pwmSession, message, null); } public void trace(final PwmRequest pwmRequest, final CharSequence message) { doPwmRequestLogEvent(PwmLogLevel.TRACE, pwmRequest, message, null); } public void trace(final SessionLabel sessionLabel, final CharSequence message) { doLogEvent(PwmLogLevel.TRACE, sessionLabel, message, null); } public void trace(final CharSequence message, final Throwable exception) { doLogEvent(PwmLogLevel.TRACE, null, message, exception); } public void debug(final CharSequence message) { doLogEvent(PwmLogLevel.DEBUG, null, message, null); } public void debug(final PwmSession pwmSession, final CharSequence message) { doPwmSessionLogEvent(PwmLogLevel.DEBUG, pwmSession, message, null); } public void debug(final PwmSession pwmSession, final ErrorInformation errorInformation) { doPwmSessionLogEvent(PwmLogLevel.DEBUG, pwmSession, convertErrorInformation(errorInformation), null); } public void debug(final PwmRequest pwmRequest, final CharSequence message) { doPwmRequestLogEvent(PwmLogLevel.DEBUG, pwmRequest, message, null); } public void debug(final PwmRequest pwmRequest, final ErrorInformation errorInformation) { doPwmRequestLogEvent(PwmLogLevel.DEBUG, pwmRequest, convertErrorInformation(errorInformation), null); } public void debug(final SessionLabel sessionLabel, final CharSequence message) { doLogEvent(PwmLogLevel.DEBUG, sessionLabel, message, null); } public void debug(final SessionLabel sessionLabel, final ErrorInformation errorInformation) { doLogEvent(PwmLogLevel.DEBUG, sessionLabel, convertErrorInformation(errorInformation), null); } public void debug(final CharSequence message, final Throwable exception) { doPwmSessionLogEvent(PwmLogLevel.DEBUG, null, message, exception); } public void debug(final PwmSession pwmSession, final CharSequence message, final Throwable e) { doPwmSessionLogEvent(PwmLogLevel.DEBUG, pwmSession, message, e); } public void info(final CharSequence message) { doLogEvent(PwmLogLevel.INFO, null, message, null); } public void info(final PwmSession pwmSession, final CharSequence message) { doPwmSessionLogEvent(PwmLogLevel.INFO, pwmSession, message, null); } public void info(final PwmRequest pwmRequest, final CharSequence message) { doPwmRequestLogEvent(PwmLogLevel.INFO, pwmRequest, message, null); } public void info(final PwmRequest pwmRequest, final ErrorInformation errorInformation) { doPwmRequestLogEvent(PwmLogLevel.INFO, pwmRequest, convertErrorInformation(errorInformation), null); } public void info(final SessionLabel sessionLabel, final CharSequence message) { doLogEvent(PwmLogLevel.INFO, sessionLabel, message, null); } public void info(final CharSequence message, final Throwable exception) { doLogEvent(PwmLogLevel.INFO, null, message, exception); } public void error(final CharSequence message) { doLogEvent(PwmLogLevel.ERROR, null, message, null); } public void error(final PwmSession pwmSession, final CharSequence message) { doPwmSessionLogEvent(PwmLogLevel.ERROR, pwmSession, message, null); } public void error(final PwmSession pwmSession, final ErrorInformation errorInformation) { doPwmSessionLogEvent(PwmLogLevel.ERROR, pwmSession, convertErrorInformation(errorInformation), null); } public void error(final PwmRequest pwmRequest, final CharSequence message, final Throwable exception) { doPwmRequestLogEvent(PwmLogLevel.ERROR, pwmRequest, message, exception); } public void error(final PwmRequest pwmRequest, final CharSequence message) { doPwmRequestLogEvent(PwmLogLevel.ERROR, pwmRequest, message, null); } public void error(final PwmRequest pwmRequest, final ErrorInformation errorInformation) { doPwmRequestLogEvent(PwmLogLevel.ERROR, pwmRequest, convertErrorInformation(errorInformation), null); } public void error(final ErrorInformation errorInformation) { doPwmRequestLogEvent(PwmLogLevel.ERROR, null, convertErrorInformation(errorInformation), null); } public void error(final SessionLabel sessionLabel, final CharSequence message) { doLogEvent(PwmLogLevel.ERROR, sessionLabel, message, null); } public void error(final SessionLabel sessionLabel, final ErrorInformation errorInformation) { doLogEvent(PwmLogLevel.ERROR, sessionLabel, convertErrorInformation(errorInformation), null); } public void error(final CharSequence message, final Throwable exception) { doLogEvent(PwmLogLevel.ERROR, null, message, exception); } public void error(final SessionLabel sessionLabel, final CharSequence message, final Throwable exception) { doLogEvent(PwmLogLevel.ERROR, sessionLabel, message, exception); } public void error(final PwmSession pwmSession, final CharSequence message, final Throwable exception) { doPwmSessionLogEvent(PwmLogLevel.ERROR, pwmSession, message, exception); } public void warn(final CharSequence message) { doLogEvent(PwmLogLevel.WARN, null, message, null); } public void warn(final PwmSession pwmSession, final CharSequence message) { doPwmSessionLogEvent(PwmLogLevel.WARN, pwmSession, message, null); } public void warn(final PwmRequest pwmRequest, final CharSequence message) { doPwmRequestLogEvent(PwmLogLevel.WARN, pwmRequest, message, null); } public void warn(final SessionLabel sessionLabel, final CharSequence message) { doLogEvent(PwmLogLevel.WARN, sessionLabel, message, null); } public void warn(final PwmSession pwmSession, final ErrorInformation message) { doPwmSessionLogEvent(PwmLogLevel.WARN, pwmSession, convertErrorInformation(message), null); } public void warn(final CharSequence message, final Throwable exception) { doLogEvent(PwmLogLevel.WARN, null, message, exception); } public void warn(final PwmSession pwmSession, final CharSequence message, final Throwable exception) { doPwmSessionLogEvent(PwmLogLevel.WARN, pwmSession, message, exception); } public void warn(final PwmSession pwmSession, final ErrorInformation errorInformation, final Throwable exception) { doPwmSessionLogEvent(PwmLogLevel.WARN, pwmSession, convertErrorInformation(errorInformation), exception); } public void fatal(final CharSequence message) { doLogEvent(PwmLogLevel.FATAL, null, message, null); } public void fatal(final PwmSession pwmSession, final CharSequence message) { doPwmSessionLogEvent(PwmLogLevel.FATAL, pwmSession, message, null); } public void fatal(final SessionLabel sessionLabel, final CharSequence message) { doLogEvent(PwmLogLevel.FATAL, sessionLabel, message, null); } public void fatal(final Object message, final Throwable exception) { doLogEvent(PwmLogLevel.FATAL, null, message, exception); } public Appendable asAppendable(final PwmLogLevel pwmLogLevel, final SessionLabel sessionLabel) { return new PwmLoggerAppendable(pwmLogLevel, sessionLabel); } private class PwmLoggerAppendable implements Appendable { private final PwmLogLevel logLevel; private final SessionLabel sessionLabel; private StringBuilder buffer = new StringBuilder(); private PwmLoggerAppendable( final PwmLogLevel logLevel, final SessionLabel sessionLabel ) { this.logLevel = logLevel; this.sessionLabel = sessionLabel; } @Override public Appendable append(final CharSequence csq) throws IOException { doAppend(csq); return this; } @Override public Appendable append( final CharSequence csq, final int start, final int end ) throws IOException { doAppend(csq.subSequence(start,end)); return this; } @Override public Appendable append(final char c) throws IOException { doAppend(String.valueOf(c)); return this; } private synchronized void doAppend(final CharSequence charSequence) { buffer.append(charSequence); int length = buffer.indexOf("\n"); while (length > 0) { final String line = buffer.substring(0,length); buffer.delete(0, + length + 1); doLogEvent(logLevel, sessionLabel, line, null); length = buffer.indexOf("\n"); } } } public static String removeUserDataFromString(final LoginInfoBean loginInfoBean, final String input) throws PwmUnrecoverableException { if (input == null || loginInfoBean == null) { return input; } String returnString = input; if (loginInfoBean.getUserCurrentPassword() != null) { final String pwdStringValue = loginInfoBean.getUserCurrentPassword().getStringValue(); if (pwdStringValue != null && !pwdStringValue.isEmpty() && returnString.contains(pwdStringValue)) { returnString = returnString.replace(pwdStringValue, PwmConstants.LOG_REMOVED_VALUE_REPLACEMENT); } } return returnString; } }