ExecuteWorkflowAction.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.plugins.workflow.modules.appointment.web;
import java.util.Calendar;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import fr.paris.lutece.plugins.appointment.web.AppointmentJspBean;
import fr.paris.lutece.plugins.workflow.modules.appointment.service.WorkflowAppointmentPlugin;
import fr.paris.lutece.portal.business.user.AdminUser;
import fr.paris.lutece.portal.business.user.AdminUserHome;
import fr.paris.lutece.portal.service.admin.AccessDeniedException;
import fr.paris.lutece.portal.service.admin.AdminAuthenticationService;
import fr.paris.lutece.portal.service.message.SiteMessage;
import fr.paris.lutece.portal.service.message.SiteMessageException;
import fr.paris.lutece.portal.service.message.SiteMessageService;
import fr.paris.lutece.portal.service.security.UserNotSignedException;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.portal.service.util.CryptoService;
import fr.paris.lutece.util.url.UrlItem;
/**
* Do execute a workflow action
*/
public class ExecuteWorkflowAction
{
// Parameters
private static final String PARAMETER_ID_ACTION = "id_action";
private static final String PARAMETER_ID_ADMIN_USER = "id_admin_user";
private static final String PARAMETER_ID_RESOURCE = "id_resource";
private static final String PARAMETER_TIMESTAMP = "timestamp";
private static final String PARAMETER_KEY = "key";
// Properties
private static final String PROPERTY_LINKS_LIMIT_VALIDITY = "workflow-appointment.executeWorkflowAction.links_limit_validity";
// JSP URL
private static final String JSP_URL_EXECUTE_WORKFLOW_ACTION = "jsp/site/plugins/workflow/modules/appointment/DoExecuteWorkflowAction.jsp";
// Error
private static final String ERROR_MESSAGE_ACCESS_DENIED = "portal.site.message.pageAccessDenied";
// Constants
private static final String DEFAULT_ENCRYPTION_ALGO = "SHA-256";
private static final int DEFAULT_LIMIT_TIME_VALIDITY = 30;
/**
* Do check if the given key is valid. If it is valid, then the user is redirected to a page to execute a workflow action.
*
* @param request
* The request
* @param response
* The response
* @return The next URL to redirect to
* @throws SiteMessageException
* If a site message needs to be displayed
*/
public String doExecuteWorkflowAction( HttpServletRequest request, HttpServletResponse response ) throws SiteMessageException
{
String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
String strIdAdminUser = request.getParameter( PARAMETER_ID_ADMIN_USER );
String strIdResource = request.getParameter( PARAMETER_ID_RESOURCE );
String strTimestamp = request.getParameter( PARAMETER_TIMESTAMP );
String strKey = request.getParameter( PARAMETER_KEY );
if ( StringUtils.isNotEmpty( strIdAction ) && StringUtils.isNumeric( strIdAction ) && StringUtils.isNotEmpty( strTimestamp )
&& StringUtils.isNumeric( strTimestamp ) && StringUtils.isNotEmpty( strIdResource ) && StringUtils.isNumeric( strIdResource )
&& StringUtils.isNotEmpty( strKey ) && StringUtils.isNotEmpty( strIdAdminUser ) && StringUtils.isNumeric( strIdAdminUser ) )
{
int nIdAction = Integer.parseInt( strIdAction );
long lTimestamp = Long.parseLong( strTimestamp );
int nIdResource = Integer.parseInt( strIdResource );
AdminUser user = null;
int nIdAdminUser = Integer.parseInt( strIdAdminUser );
if ( nIdAdminUser > 0 )
{
user = AdminUserHome.findByPrimaryKey( nIdAdminUser );
}
int nLinkLimitValidity = AppPropertiesService.getPropertyInt( PROPERTY_LINKS_LIMIT_VALIDITY, DEFAULT_LIMIT_TIME_VALIDITY );
if ( nLinkLimitValidity > 0 )
{
Calendar calendar = Calendar.getInstance( WorkflowAppointmentPlugin.getPluginLocale( Locale.getDefault( ) ) );
calendar.add( Calendar.DAY_OF_WEEK, -1 * nLinkLimitValidity );
if ( calendar.getTimeInMillis( ) > lTimestamp )
{
SiteMessageService.setMessage( request, ERROR_MESSAGE_ACCESS_DENIED, SiteMessage.TYPE_ERROR );
return null;
}
}
String strComputedKey = computeAuthenticationKey( nIdAction, nIdAdminUser, lTimestamp, nIdResource );
if ( ( user == null ) || !StringUtils.equals( strComputedKey, strKey ) )
{
SiteMessageService.setMessage( request, ERROR_MESSAGE_ACCESS_DENIED, SiteMessage.TYPE_ERROR );
return null;
}
try
{
AdminAuthenticationService.getInstance( ).registerUser( request, user );
}
catch( UserNotSignedException | AccessDeniedException e )
{
AppLogService.error( e.getMessage( ), e );
}
return AppointmentJspBean.getUrlExecuteWorkflowAction( request, strIdResource, strIdAction );
}
SiteMessageService.setMessage( request, ERROR_MESSAGE_ACCESS_DENIED, SiteMessage.TYPE_ERROR );
return null;
}
/**
* Get the URL to execute a workflow action on an appointment
*
* @param strBaseURL
* The base URL to use
* @param nIdWorkflowAction
* The id of the workflow action to execute
* @param nIdAdminUser
* The id of the action user that execute the action
* @param nIdResource
* The id of the appointment to execute the workflow action on
* @return The URL
*/
public static String getExecuteWorkflowActionUrl( String strBaseURL, int nIdWorkflowAction, int nIdAdminUser, int nIdResource )
{
long lTimestamp = System.currentTimeMillis( );
UrlItem urlItem = new UrlItem( strBaseURL + JSP_URL_EXECUTE_WORKFLOW_ACTION );
urlItem.addParameter( PARAMETER_ID_ACTION, nIdWorkflowAction );
urlItem.addParameter( PARAMETER_ID_RESOURCE, nIdResource );
urlItem.addParameter( PARAMETER_ID_ADMIN_USER, nIdAdminUser );
urlItem.addParameter( PARAMETER_TIMESTAMP, Long.toString( lTimestamp ) );
urlItem.addParameter( PARAMETER_KEY, computeAuthenticationKey( nIdWorkflowAction, nIdAdminUser, lTimestamp, nIdResource ) );
return urlItem.getUrl( );
}
/**
* Compute the authentication key to execute a workflow action
*
* @param nIdAction
* The id of the action to execute
* @param nIdAdminUser
* The id of the admin user that will execute the action
* @param nTimestamp
* The timestamp used when the link was created
* @param nIdResource
* The id of the workflow resource
* @return The authentication key
*/
private static String computeAuthenticationKey( int nIdAction, int nIdAdminUser, long nTimestamp, int nIdResource )
{
String strPrivateKey = CryptoService.getCryptoKey( );
return CryptoService.encrypt( nIdAction + nIdAdminUser + nTimestamp + nIdResource + strPrivateKey, DEFAULT_ENCRYPTION_ALGO );
}
}