mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Merged HEAD-BUG-FIX (5.0/Cloud) to HEAD (5.0/Cloud)
84047: Merged V4.2-BUG-FIX (4.2.4) to HEAD-BUG-FIX (5.0/Cloud) 83804: Merged V4.1-BUG-FIX (4.1.10) to V4.2-BUG-FIX (4.2.4) 83716: MNT-11355: Merged DEV to V4.1-BUG-FIX (4.1.10) 83675: MNT-11355: PostSubParamInjection and HeaderParamManipulation attacks identified by HP Web Inspect - Hide SQLException from stacktrace that is sent in error response to client. Add unit test. ----------------------------------------------- M /alfresco/BRANCHES/DEV/V4.1-BUG-FIX M /alfresco/BRANCHES/DEV/V4.1-BUG-FIX/root/projects/core/source/java/org/alfresco/error/AlfrescoRuntimeException.java M /alfresco/BRANCHES/DEV/V4.1-BUG-FIX/root/projects/remote-api/source/java/org/alfresco/repo/web/scripts/RepositoryContainer.java M /alfresco/BRANCHES/DEV/V4.1-BUG-FIX/root/projects/remote-api/source/test-java/org/alfresco/repo/web/scripts/RepositoryContainerTest.java git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@84623 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2013 Alfresco Software Limited.
|
* Copyright (C) 2005-2014 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -21,6 +21,7 @@ package org.alfresco.repo.web.scripts;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import javax.transaction.Status;
|
import javax.transaction.Status;
|
||||||
import javax.transaction.UserTransaction;
|
import javax.transaction.UserTransaction;
|
||||||
|
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.error.ExceptionStackUtil;
|
import org.alfresco.error.ExceptionStackUtil;
|
||||||
import org.alfresco.repo.model.Repository;
|
import org.alfresco.repo.model.Repository;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
@@ -88,6 +90,8 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
private long maxContentSize = (long) 4 * 1024 * 1024 * 1024; // 4gb
|
private long maxContentSize = (long) 4 * 1024 * 1024 * 1024; // 4gb
|
||||||
private ThresholdOutputStreamFactory streamFactory = null;
|
private ThresholdOutputStreamFactory streamFactory = null;
|
||||||
|
|
||||||
|
private final static Class<?>[] HIDE_EXCEPTIONS = new Class[] { SQLException.class };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shame init is already used (by TenantRepositoryContainer).
|
* Shame init is already used (by TenantRepositoryContainer).
|
||||||
*/
|
*/
|
||||||
@@ -252,10 +256,43 @@ public class RepositoryContainer extends AbstractRuntimeContainer
|
|||||||
public void executeScript(WebScriptRequest scriptReq, WebScriptResponse scriptRes, final Authenticator auth)
|
public void executeScript(WebScriptRequest scriptReq, WebScriptResponse scriptRes, final Authenticator auth)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
final boolean debug = logger.isDebugEnabled();
|
try
|
||||||
|
{
|
||||||
|
executeScriptInternal(scriptReq, scriptRes, auth);
|
||||||
|
}
|
||||||
|
catch (RuntimeException e)
|
||||||
|
{
|
||||||
|
Throwable hideCause = ExceptionStackUtil.getCause(e, HIDE_EXCEPTIONS);
|
||||||
|
if (hideCause != null)
|
||||||
|
{
|
||||||
|
AlfrescoRuntimeException alf = null;
|
||||||
|
if (e instanceof AlfrescoRuntimeException)
|
||||||
|
{
|
||||||
|
alf = (AlfrescoRuntimeException) e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The message will not have a numerical identifier
|
||||||
|
alf = new AlfrescoRuntimeException("WebScript execution failed", e);
|
||||||
|
}
|
||||||
|
String num = alf.getNumericalId();
|
||||||
|
logger.error("Server error (" + num + ")", e);
|
||||||
|
throw new RuntimeException("Server error (" + num + "). Details can be found in the server logs.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void executeScriptInternal(WebScriptRequest scriptReq, WebScriptResponse scriptRes, final Authenticator auth)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
final WebScript script = scriptReq.getServiceMatch().getWebScript();
|
final WebScript script = scriptReq.getServiceMatch().getWebScript();
|
||||||
final Description desc = script.getDescription();
|
final Description desc = script.getDescription();
|
||||||
|
final boolean debug = logger.isDebugEnabled();
|
||||||
|
|
||||||
// Escalate the webscript declared level of authentication to the container required authentication
|
// Escalate the webscript declared level of authentication to the container required authentication
|
||||||
// eg. must be guest if MT is enabled unless credentials are empty
|
// eg. must be guest if MT is enabled unless credentials are empty
|
||||||
RequiredAuthentication containerRequiredAuthentication = getRequiredAuthentication();
|
RequiredAuthentication containerRequiredAuthentication = getRequiredAuthentication();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
* Copyright (C) 2005-2014 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -18,19 +18,37 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.web.scripts;
|
package org.alfresco.repo.web.scripts;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.error.ExceptionStackUtil;
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.forms.FormException;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
import org.alfresco.service.cmr.security.MutableAuthenticationService;
|
||||||
import org.alfresco.service.cmr.security.PersonService;
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
import org.alfresco.util.CronTriggerBean;
|
import org.alfresco.util.CronTriggerBean;
|
||||||
import org.alfresco.util.PropertyMap;
|
import org.alfresco.util.PropertyMap;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
|
import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
|
||||||
import org.springframework.extensions.webscripts.TestWebScriptServer.PutRequest;
|
import org.springframework.extensions.webscripts.TestWebScriptServer.PutRequest;
|
||||||
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
|
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
|
||||||
|
import org.springframework.extensions.webscripts.Authenticator;
|
||||||
|
import org.springframework.extensions.webscripts.WebScriptException;
|
||||||
|
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||||
|
import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||||
|
|
||||||
import static org.springframework.extensions.webscripts.Status.*;
|
import static org.springframework.extensions.webscripts.Status.*;
|
||||||
|
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit test to test runas function
|
* Unit test to test runas function
|
||||||
*
|
*
|
||||||
@@ -143,4 +161,107 @@ public class RepositoryContainerTest extends BaseWebScriptTest
|
|||||||
response = sendRequest(new PutRequest("/test/largecontenttest", content, "text/plain"), STATUS_OK);
|
response = sendRequest(new PutRequest("/test/largecontenttest", content, "text/plain"), STATUS_OK);
|
||||||
assertEquals(SUCCESS, response.getContentAsString());
|
assertEquals(SUCCESS, response.getContentAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testHideExceptions() throws Exception
|
||||||
|
{
|
||||||
|
final Pattern patternHiddenException = Pattern.compile("Server error \\(\\d{8}\\)\\. Details can be found in the server logs\\.");
|
||||||
|
final String messageFormException = "Failed to persist field 'prop_cm_name'";
|
||||||
|
final String messageAuthenticationException = "Authentication failed for Web Script";
|
||||||
|
|
||||||
|
RepositoryContainer repoContainer = (RepositoryContainer) getServer().getApplicationContext().getBean("webscripts.container");
|
||||||
|
RepositoryContainer repoContainerMock = Mockito.spy(repoContainer);
|
||||||
|
|
||||||
|
// case: AlfrescoRuntimeException with SQLException cause
|
||||||
|
Mockito.doAnswer(new Answer<Object>()
|
||||||
|
{
|
||||||
|
public Object answer(InvocationOnMock invocation)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("AlfrescoRuntimeException", new SQLException("SQLException"));
|
||||||
|
}
|
||||||
|
}).when(repoContainerMock).executeScriptInternal(any(WebScriptRequest.class), any(WebScriptResponse.class), any(Authenticator.class));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
repoContainerMock.executeScript(null, null, null);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
assertNull("SQLException cause should be hidden for client", ExceptionStackUtil.getCause(e, new Class[] { SQLException.class }));
|
||||||
|
assertTrue("Details should be in the server logs.", patternHiddenException.matcher(e.getMessage()).matches());
|
||||||
|
}
|
||||||
|
|
||||||
|
// case: AlfrescoRuntimeException with NOT SQLException cause
|
||||||
|
Mockito.doAnswer(new Answer<Object>()
|
||||||
|
{
|
||||||
|
public Object answer(InvocationOnMock invocation)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException("AlfrescoRuntimeException", new NullPointerException());
|
||||||
|
}
|
||||||
|
}).when(repoContainerMock).executeScriptInternal(any(WebScriptRequest.class), any(WebScriptResponse.class), any(Authenticator.class));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
repoContainerMock.executeScript(null, null, null);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
assertNotNull("NullPointerException cause should be visible for client", ExceptionStackUtil.getCause(e, new Class[] { NullPointerException.class }));
|
||||||
|
assertFalse("Details should be available for client", patternHiddenException.matcher(e.getMessage()).matches());
|
||||||
|
}
|
||||||
|
|
||||||
|
// case: RuntimeException with SQLException cause
|
||||||
|
Mockito.doAnswer(new Answer<Object>()
|
||||||
|
{
|
||||||
|
public Object answer(InvocationOnMock invocation)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("AlfrescoRuntimeException", new SQLException("SQLException"));
|
||||||
|
}
|
||||||
|
}).when(repoContainerMock).executeScriptInternal(any(WebScriptRequest.class), any(WebScriptResponse.class), any(Authenticator.class));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
repoContainerMock.executeScript(null, null, null);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
assertNull("SQLException cause should be hidden for client", ExceptionStackUtil.getCause(e, new Class[] { SQLException.class }));
|
||||||
|
assertTrue("Details should be in the server logs.", patternHiddenException.matcher(e.getMessage()).matches());
|
||||||
|
}
|
||||||
|
|
||||||
|
// case: FormException
|
||||||
|
Mockito.doAnswer(new Answer<Object>()
|
||||||
|
{
|
||||||
|
public Object answer(InvocationOnMock invocation)
|
||||||
|
{
|
||||||
|
throw new FormException(messageFormException);
|
||||||
|
}
|
||||||
|
}).when(repoContainerMock).executeScriptInternal(any(WebScriptRequest.class), any(WebScriptResponse.class), any(Authenticator.class));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
repoContainerMock.executeScript(null, null, null);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
assertTrue("FormException should be visible for client", e instanceof FormException);
|
||||||
|
assertFalse("Details should be available for client", patternHiddenException.matcher(e.getMessage()).matches());
|
||||||
|
assertTrue("Actual message should be available for client", e.getMessage().contains(messageFormException));
|
||||||
|
}
|
||||||
|
|
||||||
|
// case: WebScriptException
|
||||||
|
Mockito.doAnswer(new Answer<Object>()
|
||||||
|
{
|
||||||
|
public Object answer(InvocationOnMock invocation)
|
||||||
|
{
|
||||||
|
throw new WebScriptException(HttpServletResponse.SC_UNAUTHORIZED, messageAuthenticationException);
|
||||||
|
}
|
||||||
|
}).when(repoContainerMock).executeScriptInternal(any(WebScriptRequest.class), any(WebScriptResponse.class), any(Authenticator.class));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
repoContainerMock.executeScript(null, null, null);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
assertTrue("WebScriptException should be visible for client", e instanceof WebScriptException);
|
||||||
|
assertFalse("Details should be available for client", patternHiddenException.matcher(e.getMessage()).matches());
|
||||||
|
assertTrue("Actual message should be available for client", e.getMessage().contains(messageAuthenticationException));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user