SecurityService.java

  1. /*
  2.  * Copyright (c) 2002-2022, City of Paris
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  *  1. Redistributions of source code must retain the above copyright notice
  10.  *     and the following disclaimer.
  11.  *
  12.  *  2. Redistributions in binary form must reproduce the above copyright notice
  13.  *     and the following disclaimer in the documentation and/or other materials
  14.  *     provided with the distribution.
  15.  *
  16.  *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
  17.  *     contributors may be used to endorse or promote products derived from
  18.  *     this software without specific prior written permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
  24.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  25.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  26.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30.  * POSSIBILITY OF SUCH DAMAGE.
  31.  *
  32.  * License 1.0
  33.  */
  34. package fr.paris.lutece.portal.service.security;

  35. import fr.paris.lutece.portal.business.event.LuteceUserEvent;
  36. import fr.paris.lutece.portal.service.datastore.DatastoreService;
  37. import fr.paris.lutece.portal.service.event.LuteceUserEventManager;
  38. import fr.paris.lutece.portal.service.init.LuteceInitException;
  39. import fr.paris.lutece.portal.service.util.AppLogService;
  40. import fr.paris.lutece.portal.service.util.AppPropertiesService;
  41. import fr.paris.lutece.util.url.UrlItem;

  42. import java.security.Principal;

  43. import java.util.Collection;
  44. import java.util.Enumeration;
  45. import java.util.List;

  46. import javax.security.auth.login.LoginException;

  47. import javax.servlet.http.HttpServletRequest;
  48. import javax.servlet.http.HttpSession;

  49. /**
  50.  * This class provides a security service to register and check user authentication
  51.  */
  52. public final class SecurityService
  53. {
  54.     /**
  55.      * Session attribute that stores the LuteceUser object attached to the session
  56.      */
  57.     private static final String ATTRIBUTE_LUTECE_USER = "lutece_user";

  58.     private static final String PROPERTY_AUTHENTICATION_CLASS = "mylutece.authentication.class";
  59.     private static final String PROPERTY_AUTHENTICATION_ENABLE = "mylutece.authentication.enable";
  60.     private static final String PROPERTY_PORTAL_AUTHENTICATION_REQUIRED = "mylutece.portal.authentication.required";

  61.     private static final String URL_INTERROGATIVE = "?";
  62.     private static final String URL_AMPERSAND = "&";
  63.     private static final String URL_EQUAL = "=";

  64.     private static final String CONSTANT_ACTION_LOGIN_USER = "user.loginUser";
  65.     private static final String CONSTANT_ACTION_LOGOUT_USER = "user.logoutUser";
  66.     private static final String CONSTANT_FO = "FO";

  67.     private static SecurityService _singleton = new SecurityService( );
  68.     private static LuteceAuthentication _authenticationService;
  69.     private static boolean _bEnable;

  70.     /**
  71.      * Private constructor
  72.      */
  73.     private SecurityService( )
  74.     {
  75.     }

  76.     /**
  77.      * Initialize service
  78.      *
  79.      * @throws LuteceInitException
  80.      *             if an error occurs
  81.      */
  82.     public static synchronized void init( ) throws LuteceInitException
  83.     {
  84.         _bEnable = false;

  85.         String strEnable = AppPropertiesService.getProperty( PROPERTY_AUTHENTICATION_ENABLE, "false" );

  86.         if ( strEnable.equalsIgnoreCase( "true" ) )
  87.         {
  88.             _authenticationService = getPortalAuthentication( );

  89.             if ( _authenticationService != null )
  90.             {
  91.                 _bEnable = true;
  92.             }
  93.         }
  94.         else
  95.         {
  96.             // in case authentication is disabled after having been enabled
  97.             _authenticationService = null;
  98.         }
  99.     }

  100.     /**
  101.      * Get the unique instance of the Security Service
  102.      *
  103.      * @return The instance
  104.      */
  105.     public static SecurityService getInstance( )
  106.     {
  107.         return _singleton;
  108.     }

  109.     /**
  110.      * Returns the authentication's activation : enable or disable
  111.      *
  112.      * @return true if the authentication is active, false otherwise
  113.      */
  114.     public static boolean isAuthenticationEnable( )
  115.     {
  116.         return _bEnable;
  117.     }

  118.     /**
  119.      * Gets the LuteceUser attached to the current Http session
  120.      *
  121.      * @param request
  122.      *            The Http request
  123.      * @return A LuteceUser object if found
  124.      * @throws UserNotSignedException
  125.      *             If there is no current user
  126.      */
  127.     public LuteceUser getRemoteUser( HttpServletRequest request ) throws UserNotSignedException
  128.     {
  129.         LuteceUser user = getRegisteredUser( request );

  130.         if ( user == null )
  131.         {
  132.             // User is not registered by Lutece, but it may be authenticated by another
  133.             // system
  134.             if ( _authenticationService.isExternalAuthentication( ) || _authenticationService.isMultiAuthenticationSupported( ) )
  135.             {
  136.                 user = _authenticationService.getHttpAuthenticatedUser( request );

  137.                 if ( ( user == null ) && isPortalAuthenticationRequired( ) )
  138.                 {
  139.                     throw new UserNotSignedException( );
  140.                 }

  141.                 registerUser( request, user );
  142.             }
  143.             else
  144.             {
  145.                 throw new UserNotSignedException( );
  146.             }
  147.         }

  148.         return user;
  149.     }

  150.     /**
  151.      * Returns the user's principal
  152.      *
  153.      * @param request
  154.      *            The HTTP request
  155.      * @return The user's principal
  156.      * @throws UserNotSignedException
  157.      *             The UserNotSignedException
  158.      */
  159.     public Principal getUserPrincipal( HttpServletRequest request ) throws UserNotSignedException
  160.     {
  161.         return getRemoteUser( request );
  162.     }

  163.     /**
  164.      * Checks if the user is associated to a given role
  165.      *
  166.      * @param request
  167.      *            The Http request
  168.      * @param strRole
  169.      *            The Role name
  170.      * @return Returns true if the user is associated to the given role
  171.      */
  172.     public boolean isUserInRole( HttpServletRequest request, String strRole )
  173.     {
  174.         LuteceUser user;

  175.         if ( !isAuthenticationEnable( ) )
  176.         {
  177.             return true;
  178.         }

  179.         try
  180.         {
  181.             user = getRemoteUser( request );
  182.         }
  183.         catch( UserNotSignedException e )
  184.         {
  185.             return false;
  186.         }

  187.         return _authenticationService.isUserInRole( user, request, strRole );
  188.     }

  189.     /**
  190.      * Checks if the user is associated to a at least a role
  191.      *
  192.      * @param request
  193.      *            The Http request
  194.      * @param listRoles
  195.      *            The Role list
  196.      * @return Returns true if the user is associated to any role
  197.      */
  198.     public boolean isUserInAnyRole( HttpServletRequest request, List<String> listRoles )
  199.     {
  200.         boolean bAutorized = false;
  201.         for ( String strRole : listRoles )
  202.         {
  203.             if ( isUserInRole( request, strRole ) )
  204.             {
  205.                 bAutorized = true;
  206.                 break;
  207.             }
  208.         }
  209.         return bAutorized;
  210.     }

  211.     /**
  212.      * get all roles for this user : - user's roles - user's groups roles
  213.      *
  214.      * @param user
  215.      *            The user
  216.      * @return Array of roles
  217.      */
  218.     public String [ ] getRolesByUser( LuteceUser user )
  219.     {
  220.         return _authenticationService.getRolesByUser( user );
  221.     }

  222.     /**
  223.      * Checks user's login with the Authentication service.
  224.      *
  225.      * @param request
  226.      *            The Http request
  227.      * @param strUserName
  228.      *            The user's login
  229.      * @param strPassword
  230.      *            The user's password
  231.      * @throws LoginException
  232.      *             The LoginException
  233.      * @throws LoginRedirectException
  234.      *             if redirect exception
  235.      */
  236.     public void loginUser( HttpServletRequest request, final String strUserName, final String strPassword ) throws LoginException, LoginRedirectException
  237.     {
  238.         LuteceUser user = _authenticationService.login( strUserName, strPassword, request );

  239.         _authenticationService.updateDateLastLogin( user, request );

  240.         if ( _authenticationService.findResetPassword( request, strUserName ) )
  241.         {
  242.             String redirect = _authenticationService.getResetPasswordPageUrl( request );
  243.             registerUser( request, user );
  244.             AccessLogService.getInstance( ).info( AccessLoggerConstants.EVENT_TYPE_CONNECT, CONSTANT_ACTION_LOGIN_USER, user, null, CONSTANT_FO );

  245.             throw new LoginRedirectException( redirect );
  246.         }

  247.         registerUser( request, user );

  248.         AccessLogService.getInstance( ).info( AccessLoggerConstants.EVENT_TYPE_CONNECT, CONSTANT_ACTION_LOGIN_USER, user, null, CONSTANT_FO );

  249.     }

  250.     /**
  251.      * Logout the user
  252.      *
  253.      * @param request
  254.      *            The HTTP request
  255.      */
  256.     public void logoutUser( HttpServletRequest request )
  257.     {
  258.         LuteceUser user;

  259.         try
  260.         {
  261.             user = getRemoteUser( request );
  262.         }
  263.         catch( UserNotSignedException e )
  264.         {
  265.             return;
  266.         }

  267.         _authenticationService.logout( user );
  268.         HttpSession session = request.getSession( false );
  269.         if(session!=null)
  270.         {
  271.             session.invalidate();
  272.         }
  273.         LuteceUserEventManager.getInstance().notifyListeners( new LuteceUserEvent( user,LuteceUserEvent.EventType.LOGOUT ) );
  274.         AccessLogService.getInstance( ).info( AccessLoggerConstants.EVENT_TYPE_DISCONNECT, CONSTANT_ACTION_LOGOUT_USER, user, null, CONSTANT_FO );
  275.     }

  276.     /**
  277.      * Retrieves the portal authentication service configured in the config.properties
  278.      *
  279.      * @return A PortalAuthentication object
  280.      * @throws LuteceInitException
  281.      *             If an error occurred
  282.      */
  283.     private static LuteceAuthentication getPortalAuthentication( ) throws LuteceInitException
  284.     {
  285.         String strAuthenticationClass = AppPropertiesService.getProperty( PROPERTY_AUTHENTICATION_CLASS );
  286.         LuteceAuthentication authentication = null;

  287.         if ( ( strAuthenticationClass != null ) && !strAuthenticationClass.equals( "" ) )
  288.         {
  289.             try
  290.             {
  291.                 authentication = (LuteceAuthentication) Class.forName( strAuthenticationClass ).newInstance( );
  292.                 AppLogService.info( "Authentication service loaded : {}", authentication.getAuthServiceName( ) );
  293.             }
  294.             catch( InstantiationException | IllegalAccessException | ClassNotFoundException e )
  295.             {
  296.                 throw new LuteceInitException( "Error instantiating Authentication Class", e );
  297.             }
  298.         }

  299.         return authentication;
  300.     }

  301.     /**
  302.      * Register the user in the Http session
  303.      *
  304.      * @param request
  305.      *            The Http request
  306.      * @param user
  307.      *            The current user
  308.      */
  309.     public void registerUser( HttpServletRequest request, LuteceUser user )
  310.     {
  311.         HttpSession session = request.getSession( true );
  312.         session.setAttribute( ATTRIBUTE_LUTECE_USER, user );
  313.        
  314.         if ( user != null )
  315.         {
  316.             LuteceUserEventManager.getInstance().notifyListeners( new LuteceUserEvent( user, LuteceUserEvent.EventType.LOGIN_SUCCESSFUL ) );
  317.         }
  318.     }

  319.     /**
  320.      * Unregister the user in the Http session
  321.      *
  322.      * @param request
  323.      *            The Http request    
  324.      */
  325.     public void unregisterUser( HttpServletRequest request )
  326.     {
  327.         HttpSession session = request.getSession( true );
  328.         LuteceUser user = (LuteceUser)session.getAttribute( ATTRIBUTE_LUTECE_USER );
  329.        
  330.         if ( user != null )
  331.         {
  332.             session.removeAttribute( ATTRIBUTE_LUTECE_USER );
  333.         }
  334.     }

  335.     /**
  336.      * Gets the Lutece user registered in the Http session
  337.      *
  338.      * @param request
  339.      *            The HTTP request
  340.      * @return The User registered or null if the user has not been registered
  341.      */
  342.     public LuteceUser getRegisteredUser( HttpServletRequest request )
  343.     {
  344.         HttpSession session = ( request != null ) ? request.getSession( false ) : null;

  345.         if ( session != null )
  346.         {
  347.             return (LuteceUser) session.getAttribute( ATTRIBUTE_LUTECE_USER );
  348.         }

  349.         return null;
  350.     }

  351.     /**
  352.      * Returns the authentication type : External or Lutece portal based
  353.      *
  354.      * @return true if the user is already authenticated or false if it needs to login.
  355.      */
  356.     public boolean isExternalAuthentication( )
  357.     {
  358.         return _authenticationService.isExternalAuthentication( );
  359.     }

  360.     /**
  361.      * Returns the Login page URL of the Authentication Service
  362.      *
  363.      * @return The URL
  364.      */
  365.     public String getLoginPageUrl( )
  366.     {
  367.         return _authenticationService.getLoginPageUrl( );
  368.     }

  369.     /**
  370.      * Returns the DoLogin URL of the Authentication Service
  371.      *
  372.      * @return The URL
  373.      */
  374.     public String getDoLoginUrl( )
  375.     {
  376.         return _authenticationService.getDoLoginUrl( );
  377.     }

  378.     /**
  379.      * Returns the DoLogout URL of the Authentication Service
  380.      *
  381.      * @return The URL
  382.      */
  383.     public String getDoLogoutUrl( )
  384.     {
  385.         return _authenticationService.getDoLogoutUrl( );
  386.     }

  387.     /**
  388.      * Returns the new account page URL of the Authentication Service
  389.      *
  390.      * @return The URL
  391.      */
  392.     public String getNewAccountPageUrl( )
  393.     {
  394.         return _authenticationService.getNewAccountPageUrl( );
  395.     }

  396.     /**
  397.      * Returns the view account page URL of the Authentication Service
  398.      *
  399.      * @return The URL
  400.      */
  401.     public String getViewAccountPageUrl( )
  402.     {
  403.         return _authenticationService.getViewAccountPageUrl( );
  404.     }

  405.     /**
  406.      * Returns the lost password URL of the Authentication Service
  407.      *
  408.      * @return The URL
  409.      */
  410.     public String getLostPasswordPageUrl( )
  411.     {
  412.         return _authenticationService.getLostPasswordPageUrl( );
  413.     }

  414.     // Added in v1.3

  415.     /**
  416.      * Returns the access denied template
  417.      *
  418.      * @return The template
  419.      */
  420.     public String getAccessDeniedTemplate( )
  421.     {
  422.         return _authenticationService.getAccessDeniedTemplate( );
  423.     }

  424.     /**
  425.      * Returns the access controled template
  426.      *
  427.      * @return The template
  428.      */
  429.     public String getAccessControledTemplate( )
  430.     {
  431.         return _authenticationService.getAccessControledTemplate( );
  432.     }

  433.     /**
  434.      * Returns whether or not the portal needs authentication
  435.      *
  436.      * @return true if the access needs authentication, otherwise
  437.      * @since 1.3.1
  438.      */
  439.     public boolean isPortalAuthenticationRequired( )
  440.     {
  441.         String strAuthenticationRequired = DatastoreService.getDataValue( PROPERTY_PORTAL_AUTHENTICATION_REQUIRED, "false" );

  442.         return strAuthenticationRequired.equals( "true" );
  443.     }

  444.     /**
  445.      * Checks user's login with the Authentication service. Used during remote authentication validation We don't have to put user informations in session,
  446.      * since it is only used in external applications
  447.      *
  448.      * @param request
  449.      *            the request
  450.      * @param strUserName
  451.      *            The user's login
  452.      * @param strPassword
  453.      *            The user's password
  454.      * @return user's informations
  455.      * @throws LoginException
  456.      *             The LoginException
  457.      * @throws LoginRedirectException
  458.      *             The redirect exception
  459.      */
  460.     public LuteceUser remoteLoginUser( final HttpServletRequest request, final String strUserName, final String strPassword )
  461.             throws LoginException, LoginRedirectException
  462.     {
  463.         return _authenticationService.login( strUserName, strPassword, request );
  464.     }

  465.     /**
  466.      * Return true if the requested url is equal to LoginUrl
  467.      *
  468.      * @param request
  469.      *            The Http servlet request
  470.      * @return True if the requested url is equal to LoginUrl, false else.
  471.      */
  472.     public boolean isLoginUrl( HttpServletRequest request )
  473.     {
  474.         if ( ( getLoginPageUrl( ) == null ) || ( request == null ) )
  475.         {
  476.             return false;
  477.         }

  478.         String strRequestUrl = request.getRequestURI( );
  479.         UrlItem url = new UrlItem( strRequestUrl );

  480.         for ( String strParamValueLoginPageUrl : getLoginPageUrl( ).substring( getLoginPageUrl( ).indexOf( URL_INTERROGATIVE ) + 1 ).split( URL_AMPERSAND ) )
  481.         {
  482.             String [ ] arrayParamValueLoginPageUrl = strParamValueLoginPageUrl.split( URL_EQUAL );
  483.             Enumeration<String> enumParams = request.getParameterNames( );

  484.             while ( enumParams.hasMoreElements( ) )
  485.             {
  486.                 String strRequestParameter = enumParams.nextElement( );

  487.                 if ( arrayParamValueLoginPageUrl [0].equals( strRequestParameter )
  488.                         && arrayParamValueLoginPageUrl [1].equals( request.getParameter( strRequestParameter ) ) )
  489.                 {
  490.                     url.addParameter( strRequestParameter, request.getParameter( strRequestParameter ) );
  491.                 }
  492.             }
  493.         }

  494.         return url.getUrl( ).endsWith( getLoginPageUrl( ) ) && !getLoginPageUrl( ).equals( "" );
  495.     }

  496.     /**
  497.      * Tells whether or not the authentication service can provide a list of all its users
  498.      *
  499.      * @return true if the service can return a users list
  500.      */
  501.     boolean isUsersListAvailable( )
  502.     {
  503.         return _authenticationService.isUsersListAvailable( );
  504.     }

  505.     /**
  506.      * Returns all users managed by the authentication service if this feature is available.
  507.      *
  508.      * @return A collection of Lutece users or null if the service doesn't provide a users list
  509.      */
  510.     public Collection<LuteceUser> getUsers( )
  511.     {
  512.         return _authenticationService.getUsers( );
  513.     }

  514.     /**
  515.      * Returns user managed by the authentication service if this feature is available.
  516.      *
  517.      * @param strUserLogin
  518.      *            the user login
  519.      * @return A Lutece user or null if the service doesn't provide LuteceUser
  520.      */
  521.     public LuteceUser getUser( String strUserLogin )
  522.     {
  523.         return _authenticationService.getUser( strUserLogin );
  524.     }

  525.     /**
  526.      * <b>true</b> when the service provides multi authentication support
  527.      *
  528.      * @return <code>true</code> if multi authentication is supported, <code>false</code> otherwise.
  529.      */
  530.     public boolean isMultiAuthenticationSupported( )
  531.     {
  532.         return _authenticationService.isMultiAuthenticationSupported( );
  533.     }

  534.     /**
  535.      * Gets the actual authentication implementation
  536.      *
  537.      * @return {@link LuteceAuthentication} implementation
  538.      */
  539.     public LuteceAuthentication getAuthenticationService( )
  540.     {
  541.         return _authenticationService;
  542.     }
  543. }