SecurityHeaderService.java
package fr.paris.lutece.portal.service.securityheader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import fr.paris.lutece.portal.business.securityheader.SecurityHeader;
import fr.paris.lutece.portal.business.securityheader.SecurityHeaderHome;
import fr.paris.lutece.portal.business.securityheader.SecurityHeaderPageCategory;
import fr.paris.lutece.portal.business.securityheader.SecurityHeaderType;
import fr.paris.lutece.util.ReferenceList;
/**
* This class provides a service that offers methods to manage security headers.
*/
public class SecurityHeaderService
{
//This map contains the security headers loaded from the database. It prevents to make database calls when data are up to date.
//It must be refreshed each time that an action is performed. Currently, These actions are creating a new header, modifying an
//existing header, removing a header and enabling or disabling a header
private Map<String, SecurityHeader> _mapSecurityHeaders = new HashMap<String, SecurityHeader>( );
Map<String, Map<String, List<SecurityHeader>>> _mapActiveSecurityHeadersForFilters = new HashMap<String, Map<String, List<SecurityHeader>>>( );
//This boolean indicates if a refresh has been done on the security headers map. In other words, it tells if the map is up to date
//with data from database
private boolean _bMapRefreshDone = false;
private Logger _logger = LogManager.getLogger( "lutece.securityHeader" );
/**
* Returns all the security headers that match specified name, type and page category (if not null for the latter).
* If page category is null (REST api case), this criterion is ignored.
*
* @param strName
* The name of the security header
* @param strType
* The type of the security header
* @param pageCategory
* The page category of the security header
* @return list od security headers matching the criteria
*/
public List<SecurityHeader> find( String strName, String strType, String pageCategory )
{
ArrayList<SecurityHeader> securityHeadersResultList = new ArrayList<SecurityHeader>( );
for( SecurityHeader securityHeader : findAll( ) )
{
if( securityHeader.getName( ).equals( strName ) && securityHeader.getType( ).equals( strType ) )
{
if( pageCategory == null || securityHeader.getPageCategory( ).equals( pageCategory ) )
{
securityHeadersResultList.add( securityHeader );
}
}
}
return securityHeadersResultList;
}
/**
* Returns all security headers from the specified type and the specified category (if not null)
* that are active (attribute is_enable = true).
*
* @param strType
* @param strPageCategory
* @return collection on security headers
*/
public Collection<SecurityHeader> findActive( String strType, String strPageCategory )
{
if( !_bMapRefreshDone )
{
refreshSecurityHeadersMap( SecurityHeaderHome.findAll() );
}
if( _mapActiveSecurityHeadersForFilters.get(strType) != null )
{
return _mapActiveSecurityHeadersForFilters.get( strType ).get( strPageCategory );
}
return null;
}
/**
* Returns a collection of all security headers.
* Security headers are fetched from database (if data are stale) or from security headers map in memory (if the data in map are still up to date).
*
* @return collection of security headers
*/
public Collection<SecurityHeader> findAll( )
{
Collection<SecurityHeader> securityHeadersList = null;
if( _bMapRefreshDone )
{
securityHeadersList = _mapSecurityHeaders.values( );
}
else
{
securityHeadersList = SecurityHeaderHome.findAll( );
refreshSecurityHeadersMap( securityHeadersList );
}
return securityHeadersList;
}
/**
* Returns a list of all security headers used in manage security headers page. They are sorted by type, page category and name.
*
* @param locale
* The locale
* @return list of all security headers
*/
public List<SecurityHeader> findAllSorted( Locale locale )
{
List<SecurityHeader> securityHeadersList = findAll( ).stream().collect( Collectors.toList( ) );
Collections.sort( securityHeadersList, Comparator.comparing( SecurityHeader::getType )
.thenComparing( SecurityHeader::getPageCategory, Comparator.nullsLast( Comparator.naturalOrder( ) ) )
.thenComparing( SecurityHeader::getName ) );
return securityHeadersList;
}
/**
* Returns the reference list of security headers types
*
* @return ReferenceList object with security headers types
*/
public ReferenceList getTypeList( )
{
ReferenceList listTypes = new ReferenceList( );
for (SecurityHeaderType type : SecurityHeaderType.values()) {
listTypes.addItem( type.getCode(), type.getCode() );
}
return listTypes;
}
/**
* Returns the reference list of security headers page categories
*
* @return ReferenceList object with security headers page categories
*/
public ReferenceList getPageCategoryList( )
{
ReferenceList listPageCategory = new ReferenceList( );
for (SecurityHeaderPageCategory pageCategory : SecurityHeaderPageCategory.values()) {
listPageCategory.addItem( pageCategory.getCode(), pageCategory.getCode() );
}
return listPageCategory;
}
/**
* Create the security header given in parameter. Like all the actions, this one invalidates the map containing the security headers.
*
* @param securityHeader
* The security header to create
*/
public void create( SecurityHeader securityHeader )
{
_logger.debug( "Security header to create : name : {}, value : {}, type : {}, page category : {}", securityHeader.getName( ), securityHeader.getValue( ), securityHeader.getType( ), securityHeader.getPageCategory( ) );
SecurityHeaderHome.create( securityHeader );
clearMapSecurityHeaders( );
_logger.debug( "Security header created" );
}
/**
* Update the security header given in parameter. Like all the actions, this one invalidates the map containing the security headers.
*
* @param securityHeader
* The security header to update
*/
public void update( SecurityHeader securityHeader )
{
_logger.debug( "Security header to update : id : {}, name : {}, value : {}, type : {}, page category : {}", securityHeader.getId( ), securityHeader.getName( ), securityHeader.getValue( ), securityHeader.getType( ), securityHeader.getPageCategory( ) );
SecurityHeaderHome.update( securityHeader );
clearMapSecurityHeaders( );
_logger.debug( "Security header updated" );
}
/**
* Remove the security header given in parameter. Like all the actions, this one invalidates the map containing the security headers.
*
* @param securityHeader
* The security header to remove
*/
public void remove( int nSecurityHeaderId )
{
SecurityHeader securityHeader = _mapSecurityHeaders.get( String.valueOf( nSecurityHeaderId ) );
_logger.debug( "Security header to delete : id : {}, name : {}, value : {}, type : {}, page category : {}", securityHeader.getId( ), securityHeader.getName( ), securityHeader.getValue( ), securityHeader.getType( ), securityHeader.getPageCategory( ) );
SecurityHeaderHome.remove( nSecurityHeaderId );
clearMapSecurityHeaders( );
_logger.debug( "Security header deleted" );
}
/**
* Enable the security header with the id given in parameter. Like all the actions, this one invalidates the map containing the security headers.
*
* @param nSecurityHeaderId
* The id of the security header to enable
*/
public void enable( int nSecurityHeaderId )
{
SecurityHeader securityHeader = _mapSecurityHeaders.get( String.valueOf( nSecurityHeaderId ) );
_logger.debug( "Security header to enable : id : {}, name : {}, value : {}, type : {}, page category : {}", securityHeader.getId( ), securityHeader.getName( ), securityHeader.getValue( ), securityHeader.getType( ), securityHeader.getPageCategory( ) );
SecurityHeaderHome.updateIsActive( nSecurityHeaderId, true );
clearMapSecurityHeaders( );
_logger.debug( "Security header enabled" );
}
/**
* Disable the security header with the id given in parameter. Like all the actions, this one invalidates the map containing the security headers.
*
* @param nSecurityHeaderId
* The id of the security header to disable
*/
public void disable( int nSecurityHeaderId )
{
SecurityHeader securityHeader = _mapSecurityHeaders.get( String.valueOf( nSecurityHeaderId ) );
_logger.debug( "Security header to disable : id : {}, name : {}, value : {}, type : {}, page category : {}", securityHeader.getId( ), securityHeader.getName( ), securityHeader.getValue( ), securityHeader.getType( ), securityHeader.getPageCategory( ) );
SecurityHeaderHome.updateIsActive( nSecurityHeaderId, false );
clearMapSecurityHeaders( );
_logger.debug( "Security header disabled" );
}
/**
* Clears the map containing the security headers
*
*/
private void clearMapSecurityHeaders( )
{
_mapSecurityHeaders.clear( );
_mapActiveSecurityHeadersForFilters.clear( );
_bMapRefreshDone = false;
_logger.debug( "Security header maps cleared" );
}
/**
* Refreshes the map of security headers with the list given in parameter. After a call to this method, data of the map are up to date with database data.
*
* @param securityHeadersList
* The security headers collection
*/
private void refreshSecurityHeadersMap( Collection<SecurityHeader> securityHeadersList )
{
for( SecurityHeader securityHeader : securityHeadersList )
{
_mapSecurityHeaders.put( String.valueOf( securityHeader.getId( ) ), securityHeader );
if( securityHeader.isActive() )
{
_mapActiveSecurityHeadersForFilters.put( securityHeader.getType( ), addHeaderToTypeMap( securityHeader ) );
}
}
_bMapRefreshDone = true;
_logger.debug( "Security header map refreshed" );
}
/**
* Adds a security header in the map of active security headers of the same type as the security header passed in parameter
*
* @param securityHeader Security header to add to the map
* @return map of active security headers of the same type as the security header passed in parameter updated with this security header
*/
private Map<String, List<SecurityHeader>> addHeaderToTypeMap( SecurityHeader securityHeader )
{
//In _mapActiveSecurityHeadersForFilters, 2 keys are necessary to retrieve a list of security headers.
//For Page headers, those keys are respectively type and page category
//For Rest api headers, those keys are respectively type and null value.
//As page category is not irrelevant for rest api headers, they are grouped using the null key.
String firstKey = securityHeader.getType( );
Map<String, List<SecurityHeader>> mapHeadersForType = _mapActiveSecurityHeadersForFilters.get( firstKey );
List<SecurityHeader> headersListToUpdate = null;
String secondKey = null;
if( securityHeader.getType( ).equals( SecurityHeaderType.PAGE.getCode( ) ) )
{
secondKey = securityHeader.getPageCategory( );
}
if( mapHeadersForType == null )
{
mapHeadersForType = new HashMap<String, List<SecurityHeader>>( );
headersListToUpdate = new ArrayList<SecurityHeader>( );
}
else
{
headersListToUpdate = mapHeadersForType.get( secondKey );
if( headersListToUpdate == null )
{
headersListToUpdate = new ArrayList<SecurityHeader>( );
}
}
headersListToUpdate.add( securityHeader );
mapHeadersForType.put( secondKey, headersListToUpdate );
return mapHeadersForType;
}
}