DefaultAccessLogger.java
- /*
- * Copyright (c) 2002-2022, City of Paris
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice
- * and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice
- * and the following disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * License 1.0
- */
- package fr.paris.lutece.portal.service.security.impl;
- import java.io.UnsupportedEncodingException;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import com.fasterxml.jackson.core.JsonProcessingException;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import fr.paris.lutece.api.user.User;
- import fr.paris.lutece.portal.service.security.AccessLoggerConstants;
- import fr.paris.lutece.portal.service.util.AppPropertiesService;
- import fr.paris.lutece.portal.service.security.IAccessLogger;
- import java.text.MessageFormat;
- import org.apache.logging.log4j.Level;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- /**
- * This class provides a default implementation for AccessLogger Service
- *
- * A specific log format can be set in the properties file
- *
- * - portal.defaultAccessLogger.messageFormat - portal.defaultAccessLogger.messageFormatSeparator
- *
- * Log lines could be certified with a hash, that could be verified, whith this property set to true :
- *
- * - portal.defaultAccessLogger.addHashToLogs
- *
- */
- public final class DefaultAccessLogger implements IAccessLogger
- {
- private static final String CONSTANT_HASH_ENCODING = "UTF-8";
- private static final String CONSTANT_HASH_DIGEST = "MD5";
- private static final String PROPERTY_ADD_HASH_TO_LOGS = "accessLogger.defaultAccessLogger.addHashToLogs";
- private static final String PROPERTY_ACCESSLOG_MESSAGE_FORMAT = "accessLogger.defaultAccessLogger.messageFormat";
- private static final String PROPERTY_ACCESSLOG_MESSAGE_FORMAT_SEPARATOR = "accessLogger.defaultAccessLogger.messageFormatSeparator";
- private static final String DEFAULT_ACCESSLOG_MESSAGE_FORMAT = "|{0}|{1}|{2}|{3}|{4}|{5}|";
- private static final String DEFAULT_ACCESSLOG_MESSAGE_FORMAT_SEPARATOR = "|";
- private static final String ERROR_MSG = "ERROR : unable to create json from data";
- private final boolean _bAddHashToLogs = AppPropertiesService.getPropertyBoolean( PROPERTY_ADD_HASH_TO_LOGS, false );
- private final String _messageFormat = AppPropertiesService.getProperty( PROPERTY_ACCESSLOG_MESSAGE_FORMAT, DEFAULT_ACCESSLOG_MESSAGE_FORMAT );
- private final String _messageFormatSeparator = AppPropertiesService.getProperty( PROPERTY_ACCESSLOG_MESSAGE_FORMAT_SEPARATOR,
- DEFAULT_ACCESSLOG_MESSAGE_FORMAT_SEPARATOR );
- public static final String DEFAULT_LOGGER_ACCESS_LOG = "lutece.accessLogger";
- private static Logger _defaultLogger = LogManager.getLogger( DEFAULT_LOGGER_ACCESS_LOG );
- /**
- * {@inheritDoc}
- */
- @Override
- public void info( String strEventType, String strAppEventCode, User connectedUser, Object data, String specificOrigin )
- {
- Logger logger = getLogger( specificOrigin );
- if ( logger.isInfoEnabled( ) )
- {
- String strAppId = AppPropertiesService.getProperty( AccessLoggerConstants.PROPERTY_SITE_CODE, "?" );
- String logMessage = getLogMessage( strAppId, strEventType, strAppEventCode, ( connectedUser != null ? connectedUser.getAccessCode( ) : "null" ),
- data );
- logger.info( logMessage );
- }
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void debug( String strEventType, String strAppEventCode, User connectedUser, Object data, String specificOrigin )
- {
- Logger logger = getLogger( specificOrigin );
- if ( logger.isDebugEnabled( ) )
- {
- String strAppId = AppPropertiesService.getProperty( AccessLoggerConstants.PROPERTY_SITE_CODE, "?" );
- String logMessage = getLogMessage( strAppId, strEventType, strAppEventCode, ( connectedUser != null ? connectedUser.getAccessCode( ) : "null" ),
- data );
- logger.debug( logMessage );
- }
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void trace( String strEventType, String strAppEventCode, User connectedUser, Object data, String specificOrigin )
- {
- Logger logger = getLogger( specificOrigin );
- if ( logger.isTraceEnabled( ) )
- {
- String strAppId = AppPropertiesService.getProperty( AccessLoggerConstants.PROPERTY_SITE_CODE, "?" );
- String logMessage = getLogMessage( strAppId, strEventType, strAppEventCode, ( connectedUser != null ? connectedUser.getAccessCode( ) : "null" ),
- data );
- logger.trace( logMessage );
- }
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void warn( String strEventType, String strAppEventCode, User connectedUser, Object data, String specificOrigin )
- {
- Logger logger = getLogger( specificOrigin );
- if ( logger.isEnabled( Level.WARN ) )
- {
- String strAppId = AppPropertiesService.getProperty( AccessLoggerConstants.PROPERTY_SITE_CODE, "?" );
- String logMessage = getLogMessage( strAppId, strEventType, strAppEventCode, ( connectedUser != null ? connectedUser.getAccessCode( ) : "null" ),
- data );
- logger.warn( logMessage );
- }
- }
- /**
- * build log message
- *
- * @param eventType
- * @param description
- * @param connectedUserLogin
- * @param data
- * @return the log message
- */
- private String getLogMessage( String strAppId, String strEventType, String strAppEventCode, String strConnectedUserLogin, Object data )
- {
- String jsonData = "";
- if ( data != null )
- {
- ObjectMapper obj = new ObjectMapper( );
- try
- {
- jsonData = obj.writeValueAsString( data );
- }
- catch( JsonProcessingException e )
- {
- jsonData = ERROR_MSG;
- }
- }
- return getLogMessage( strAppId, strEventType, strAppEventCode, strConnectedUserLogin, jsonData, isAddHashToLogs( ) );
- }
- /**
- * build log message
- *
- * @param eventType
- * @param description
- * @param connectedUserLogin
- * @param data
- * @return the log message
- */
- private String getLogMessage( String strAppId, String strEventType, String strAppEventCode, String strConnectedUserLogin, String strData,
- boolean isAddHashToLogs )
- {
- String strHash = "";
- if ( isAddHashToLogs )
- {
- strHash = getHash( MessageFormat.format( _messageFormat, "", strAppId, strEventType, strAppEventCode, strConnectedUserLogin, strData ) );
- }
- return MessageFormat.format( _messageFormat, strHash, strAppId, strEventType, strAppEventCode, strConnectedUserLogin, strData );
- }
- /**
- * get hash
- *
- * @param message
- * @param last
- * hash
- *
- * @return the hash in String
- */
- private static String getHash( String message )
- {
- byte [ ] byteChaine;
- try
- {
- byteChaine = message.getBytes( CONSTANT_HASH_ENCODING );
- MessageDigest md = MessageDigest.getInstance( CONSTANT_HASH_DIGEST );
- byte [ ] hash = md.digest( byteChaine );
- // convert byte array to Hexadecimal String
- StringBuilder sb = new StringBuilder( 2 * hash.length );
- for ( byte b : hash )
- {
- sb.append( String.format( "%02x", b & 0xff ) );
- }
- return sb.toString( );
- }
- catch( UnsupportedEncodingException | NoSuchAlgorithmException e )
- {
- return "Hash ERROR : " + e.getLocalizedMessage( );
- }
- }
- /**
- * verify hash
- *
- * @param message
- *
- * @return true if the hash contained in the message is valid
- */
- public boolean verifyMessageHash( String message )
- {
- try
- {
- int idx = message.indexOf( _messageFormatSeparator, message.indexOf( DEFAULT_LOGGER_ACCESS_LOG ) );
- String hash = message.substring( idx + 1, idx + 33 );
- String data = "||" + message.substring( idx + 34 );
- return ( hash != null && ( hash.equals( "" ) || hash.equals( getHash( data ) ) ) );
- }
- catch( StringIndexOutOfBoundsException e )
- {
- return false;
- }
- }
- /**
- * is addHashToLogs enabled
- *
- * @return true if addHashToLogs enabled
- */
- public boolean isAddHashToLogs( )
- {
- return _bAddHashToLogs;
- }
- /**
- * get logger
- *
- * @param strSpecificLogger
- * @return the logger
- */
- private Logger getLogger( String specificOrigin )
- {
- if ( specificOrigin != null && !"".equals( specificOrigin ) )
- {
- return LogManager.getLogger( DEFAULT_LOGGER_ACCESS_LOG + "." + specificOrigin );
- }
- return _defaultLogger;
- }
- }