mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Merged 5.2.N (5.2.2) to HEAD (5.2)
135255 arebegea: MNT-17427 : api/invite/cancel deletes records in the database with a GET: CSRF/XSS attack - delete the script/org/alfresco/repository/invite/invite.get - use the alternatives: script/org/alfresco/repository/site/invitation/invitation.post and script/org/alfresco/repository/site/invitation/invitation.delete - updating the tests - updating the controller for the invitation.delete to a java controller - fix test fallout (SiteServiceTest testInviteDisabledUser - expected error status code) - improve security by allowing only invitationIDs that belong the the site passed as parameter to be canceled - be consistent and return 404 when an invitationID can not be found git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@137384 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.web.scripts.invitation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.service.cmr.invitation.Invitation;
|
||||
import org.alfresco.service.cmr.invitation.InvitationExceptionForbidden;
|
||||
import org.alfresco.service.cmr.invitation.InvitationService;
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.springframework.extensions.webscripts.Cache;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* Cancel invitation for a web site; This is the controller for the
|
||||
* org/alfresco/repository/site/invitation/invitation.delete.desc.xml webscript
|
||||
*/
|
||||
public class InvitationDelete extends DeclarativeWebScript
|
||||
{
|
||||
// services
|
||||
private InvitationService invitationService;
|
||||
private SiteService siteService;
|
||||
|
||||
public void setInvitationService(InvitationService invitationService)
|
||||
{
|
||||
this.invitationService = invitationService;
|
||||
}
|
||||
|
||||
public void setSiteService(SiteService siteService)
|
||||
{
|
||||
this.siteService = siteService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
|
||||
{
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
|
||||
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
|
||||
final String siteShortName = templateVars.get("shortname");
|
||||
final String invitationId = templateVars.get("invitationId");
|
||||
validateParameters(siteShortName, invitationId);
|
||||
|
||||
try
|
||||
{
|
||||
// MNT-9905 Pending Invites created by one site manager aren't visible to other site managers
|
||||
String currentUser = AuthenticationUtil.getRunAsUser();
|
||||
|
||||
if (siteShortName != null && (SiteModel.SITE_MANAGER).equals(siteService.getMembersRole(siteShortName, currentUser)))
|
||||
{
|
||||
|
||||
RunAsWork<Void> runAsSystem = new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
checkAndCancelTheInvitation(invitationId, siteShortName);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
AuthenticationUtil.runAs(runAsSystem, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
else
|
||||
{
|
||||
checkAndCancelTheInvitation(invitationId, siteShortName);
|
||||
}
|
||||
}
|
||||
catch (InvitationExceptionForbidden fe)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_FORBIDDEN, "Unable to cancel workflow", fe);
|
||||
}
|
||||
catch (AccessDeniedException ade)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_FORBIDDEN, "Unable to cancel workflow", ade);
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private void validateParameters(String siteShortName, String invitationId)
|
||||
{
|
||||
if ((invitationId == null) || (invitationId.length() == 0))
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid invitation id provided");
|
||||
}
|
||||
|
||||
SiteInfo site = siteService.getSite(siteShortName);
|
||||
if (site == null)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_NOT_FOUND, "Invalid site id provided");
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkAndCancelTheInvitation(final String invId, String siteShortName)
|
||||
{
|
||||
Invitation invitation = null;
|
||||
try
|
||||
{
|
||||
invitation = invitationService.getInvitation(invId);
|
||||
}
|
||||
catch (org.alfresco.service.cmr.invitation.InvitationExceptionNotFound ienf)
|
||||
{
|
||||
throwInvitationNotFoundException(invId, siteShortName);
|
||||
}
|
||||
if (invitation == null)
|
||||
{
|
||||
throwInvitationNotFoundException(invId, siteShortName);
|
||||
}
|
||||
|
||||
// check that this invitation really belongs to the specified siteShortName
|
||||
if (invitation != null && invitation.getResourceName() != null && !siteShortName.equals(invitation.getResourceName()))
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_FORBIDDEN, "Unable to cancel workflow");
|
||||
}
|
||||
|
||||
invitationService.cancel(invId);
|
||||
}
|
||||
|
||||
protected void throwInvitationNotFoundException(final String invId, String siteShortName)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_NOT_FOUND,
|
||||
"The invitation :" + invId + " for web site :" + siteShortName + ", does not exist.");
|
||||
}
|
||||
|
||||
}
|
@@ -1,324 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Alfresco 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.web.scripts.invite;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.service.cmr.invitation.Invitation;
|
||||
import org.alfresco.service.cmr.invitation.InvitationExceptionForbidden;
|
||||
import org.alfresco.service.cmr.invitation.InvitationExceptionUserError;
|
||||
import org.alfresco.service.cmr.invitation.InvitationService;
|
||||
import org.alfresco.service.cmr.invitation.NominatedInvitation;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.springframework.extensions.webscripts.Cache;
|
||||
import org.springframework.extensions.webscripts.DeclarativeWebScript;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* Web Script invoked by a Site Manager (Inviter) to either send
|
||||
* (action='start') an invitation to a another person (Invitee) to join a Site
|
||||
* as a Site Collaborator, or to cancel (action='cancel') a pending invitation
|
||||
* that has already been sent out
|
||||
*
|
||||
* @author glen dot johnson at alfresco dot com
|
||||
*/
|
||||
public class Invite extends DeclarativeWebScript
|
||||
{
|
||||
private static final String ACTION_START = "start";
|
||||
private static final String ACTION_CANCEL = "cancel";
|
||||
|
||||
private static final String MODEL_PROP_KEY_ACTION = "action";
|
||||
private static final String MODEL_PROP_KEY_INVITE_ID = "inviteId";
|
||||
private static final String MODEL_PROP_KEY_INVITE_TICKET = "inviteTicket";
|
||||
private static final String MODEL_PROP_KEY_INVITEE_USER_NAME = "inviteeUserName";
|
||||
private static final String MODEL_PROP_KEY_INVITEE_FIRSTNAME = "inviteeFirstName";
|
||||
private static final String MODEL_PROP_KEY_INVITEE_LASTNAME = "inviteeLastName";
|
||||
private static final String MODEL_PROP_KEY_INVITEE_EMAIL = "inviteeEmail";
|
||||
private static final String MODEL_PROP_KEY_SITE_SHORT_NAME = "siteShortName";
|
||||
private static final String MODEL_PROP_KEY_INVITEE_USERNAME = "inviteeUserName";
|
||||
|
||||
// URL request parameter names
|
||||
private static final String PARAM_INVITEE_FIRSTNAME = "inviteeFirstName";
|
||||
private static final String PARAM_INVITEE_LASTNAME = "inviteeLastName";
|
||||
private static final String PARAM_INVITEE_EMAIL = "inviteeEmail";
|
||||
private static final String PARAM_SITE_SHORT_NAME = "siteShortName";
|
||||
private static final String PARAM_INVITE_ID = "inviteId";
|
||||
private static final String PARAM_INVITEE_SITE_ROLE = "inviteeSiteRole";
|
||||
private static final String PARAM_SERVER_PATH = "serverPath";
|
||||
private static final String PARAM_ACCEPT_URL = "acceptUrl";
|
||||
private static final String PARAM_REJECT_URL = "rejectUrl";
|
||||
|
||||
// services
|
||||
private InvitationService invitationService;
|
||||
private SiteService siteService;
|
||||
|
||||
public void setInvitationService(InvitationService invitationService)
|
||||
{
|
||||
this.invitationService = invitationService;
|
||||
}
|
||||
|
||||
public void setSiteService(SiteService siteService)
|
||||
{
|
||||
this.siteService = siteService;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.alfresco.web.scripts.DeclarativeWebScript#executeImpl(org.alfresco
|
||||
* .web.scripts.WebScriptRequest,
|
||||
* org.alfresco.web.scripts.WebScriptResponse)
|
||||
*/
|
||||
@Override
|
||||
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
|
||||
{
|
||||
// initialise model to pass on for template to render
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
|
||||
// extract action string from URL
|
||||
String servicePath = req.getServicePath();
|
||||
String action = null;
|
||||
int actionStartIndex = servicePath.lastIndexOf("/") + 1;
|
||||
if (actionStartIndex <= servicePath.length() - 1)
|
||||
{
|
||||
action = servicePath.substring(actionStartIndex, servicePath
|
||||
.length());
|
||||
}
|
||||
|
||||
// check that the action has been provided on the URL
|
||||
// and that URL parameters have been provided
|
||||
if ((action == null) || (action.length() == 0))
|
||||
{
|
||||
// handle action not provided on URL
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"Action has not been provided in URL");
|
||||
}
|
||||
|
||||
// handle no parameters given on URL
|
||||
if ((req.getParameterNames() == null) || (req.getParameterNames().length == 0))
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"No parameters have been provided on URL");
|
||||
}
|
||||
|
||||
// handle action 'start'
|
||||
if (action.equals(ACTION_START))
|
||||
{
|
||||
// check for 'inviteeFirstName' parameter not provided
|
||||
String inviteeFirstName = req.getParameter(PARAM_INVITEE_FIRSTNAME);
|
||||
if ((inviteeFirstName == null) || (inviteeFirstName.trim().length() == 0))
|
||||
{
|
||||
// handle inviteeFirstName URL parameter not provided
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"'inviteeFirstName' parameter "
|
||||
+ "has not been provided in URL for action '"
|
||||
+ ACTION_START + "'");
|
||||
}
|
||||
|
||||
// check for 'inviteeLastName' parameter not provided
|
||||
String inviteeLastName = req.getParameter(PARAM_INVITEE_LASTNAME);
|
||||
if ((inviteeLastName == null) || (inviteeLastName.trim().length() == 0))
|
||||
{
|
||||
// handle inviteeLastName URL parameter not provided
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"'inviteeLastName' parameter "
|
||||
+ "has not been provided in URL for action '"
|
||||
+ ACTION_START + "'");
|
||||
}
|
||||
|
||||
// check for 'inviteeEmail' parameter not provided
|
||||
String inviteeEmail = req.getParameter(PARAM_INVITEE_EMAIL);
|
||||
if ((inviteeEmail == null) || (inviteeEmail.trim().length() == 0))
|
||||
{
|
||||
// handle inviteeEmail URL parameter not provided
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"'inviteeEmail' parameter "
|
||||
+ "has not been provided in URL for action '"
|
||||
+ ACTION_START + "'");
|
||||
}
|
||||
|
||||
// check for 'siteShortName' parameter not provided
|
||||
String siteShortName = req.getParameter(PARAM_SITE_SHORT_NAME);
|
||||
if ((siteShortName == null) || (siteShortName.trim().length() == 0))
|
||||
{
|
||||
// handle siteShortName URL parameter not provided
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"'siteShortName' parameter "
|
||||
+ "has not been provided in URL for action '"
|
||||
+ ACTION_START + "'");
|
||||
}
|
||||
|
||||
// check for 'inviteeSiteRole' parameter not provided
|
||||
String inviteeSiteRole = req.getParameter(PARAM_INVITEE_SITE_ROLE);
|
||||
if ((inviteeSiteRole == null) || (inviteeSiteRole.trim().length() == 0))
|
||||
{
|
||||
// handle inviteeSiteRole URL parameter not provided
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"'inviteeSiteRole' parameter has not been provided in URL for action '"
|
||||
+ ACTION_START + "'");
|
||||
}
|
||||
|
||||
// check for 'serverPath' parameter not provided
|
||||
String serverPath = req.getParameter(PARAM_SERVER_PATH);
|
||||
if ((serverPath == null) || (serverPath.trim().length() == 0))
|
||||
{
|
||||
// handle serverPath URL parameter not provided
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"'serverPath' parameter has not been provided in URL for action '"
|
||||
+ ACTION_START + "'");
|
||||
}
|
||||
|
||||
// check for 'acceptUrl' parameter not provided
|
||||
String acceptUrl = req.getParameter(PARAM_ACCEPT_URL);
|
||||
if ((acceptUrl == null) || (acceptUrl.trim().length() == 0))
|
||||
{
|
||||
// handle acceptUrl URL parameter not provided
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"'acceptUrl' parameter has not been provided in URL for action '"
|
||||
+ ACTION_START + "'");
|
||||
}
|
||||
|
||||
// check for 'rejectUrl' parameter not provided
|
||||
String rejectUrl = req.getParameter(PARAM_REJECT_URL);
|
||||
if ((rejectUrl == null) || (rejectUrl.trim().length() == 0))
|
||||
{
|
||||
// handle rejectUrl URL parameter not provided
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"'rejectUrl' parameter has not been provided in URL for action '"
|
||||
+ ACTION_START + "'");
|
||||
}
|
||||
|
||||
// check for the invitee user name (if present)
|
||||
String inviteeUserName = req.getParameter(MODEL_PROP_KEY_INVITEE_USERNAME);
|
||||
|
||||
NominatedInvitation newInvite = null;
|
||||
try
|
||||
{
|
||||
if (inviteeUserName != null)
|
||||
{
|
||||
newInvite = invitationService.inviteNominated(inviteeUserName, Invitation.ResourceType.WEB_SITE, siteShortName, inviteeSiteRole, acceptUrl, rejectUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
newInvite = invitationService.inviteNominated(inviteeFirstName, inviteeLastName, inviteeEmail, Invitation.ResourceType.WEB_SITE, siteShortName, inviteeSiteRole, acceptUrl, rejectUrl);
|
||||
}
|
||||
// add model properties for template to render
|
||||
model.put(MODEL_PROP_KEY_ACTION, ACTION_START);
|
||||
model.put(MODEL_PROP_KEY_INVITE_ID, newInvite.getInviteId());
|
||||
model.put(MODEL_PROP_KEY_INVITE_TICKET, newInvite.getTicket());
|
||||
model.put(MODEL_PROP_KEY_INVITEE_USER_NAME, newInvite.getInviteeUserName());
|
||||
model.put(MODEL_PROP_KEY_INVITEE_FIRSTNAME, inviteeFirstName);
|
||||
model.put(MODEL_PROP_KEY_INVITEE_LASTNAME, inviteeLastName);
|
||||
model.put(MODEL_PROP_KEY_INVITEE_EMAIL, inviteeEmail);
|
||||
model.put(MODEL_PROP_KEY_SITE_SHORT_NAME, siteShortName);
|
||||
}
|
||||
catch (InvitationExceptionUserError ie)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_CONFLICT, ie.getMessage());
|
||||
}
|
||||
catch (InvitationExceptionForbidden fe)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_FORBIDDEN, fe.toString());
|
||||
}
|
||||
|
||||
// process action 'start' with provided parameters
|
||||
//startInvite(model, inviteeFirstName, inviteeLastName, inviteeEmail, inviteeUserName, siteShortName, inviteeSiteRole, serverPath, acceptUrl, rejectUrl);
|
||||
}
|
||||
// else handle if provided 'action' is 'cancel'
|
||||
else if (action.equals(ACTION_CANCEL))
|
||||
{
|
||||
// check for 'inviteId' parameter not provided
|
||||
String inviteId = req.getParameter(PARAM_INVITE_ID);
|
||||
if ((inviteId == null) || (inviteId.length() == 0))
|
||||
{
|
||||
// handle inviteId URL parameter not provided
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST,
|
||||
"'inviteId' parameter has "
|
||||
+ "not been provided in URL for action '"
|
||||
+ ACTION_CANCEL + "'");
|
||||
}
|
||||
|
||||
// process action 'cancel' with provided parameters
|
||||
try
|
||||
{
|
||||
//MNT-9905 Pending Invites created by one site manager aren't visible to other site managers
|
||||
String currentUser = AuthenticationUtil.getRunAsUser();
|
||||
String siteShortName = req.getParameter(PARAM_SITE_SHORT_NAME);
|
||||
|
||||
if (siteShortName != null && (SiteModel.SITE_MANAGER).equals(siteService.getMembersRole(siteShortName, currentUser)))
|
||||
{
|
||||
final String invId = inviteId;
|
||||
|
||||
RunAsWork<Void> runAsSystem = new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
invitationService.cancel(invId);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
AuthenticationUtil.runAs(runAsSystem, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
else
|
||||
{
|
||||
invitationService.cancel(inviteId);
|
||||
}
|
||||
|
||||
// add model properties for template to render
|
||||
model.put(MODEL_PROP_KEY_ACTION, ACTION_CANCEL);
|
||||
model.put(MODEL_PROP_KEY_INVITE_ID, inviteId);
|
||||
}
|
||||
catch(InvitationExceptionForbidden fe)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_FORBIDDEN, "Unable to cancel workflow" , fe);
|
||||
}
|
||||
catch(AccessDeniedException ade)
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_FORBIDDEN, "Unable to cancel workflow" , ade);
|
||||
}
|
||||
}
|
||||
// handle action not recognised
|
||||
else
|
||||
{
|
||||
throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Action, '"
|
||||
+ action + "', "
|
||||
+ "provided in URL has not been recognised.");
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user