diff --git a/config/alfresco/messages/rest-framework-messages.properties b/config/alfresco/messages/rest-framework-messages.properties index eb55278bd1..3fd1259015 100644 --- a/config/alfresco/messages/rest-framework-messages.properties +++ b/config/alfresco/messages/rest-framework-messages.properties @@ -13,4 +13,5 @@ framework.exception.UnsupportedResourceOperation=The operation is unsupported framework.exception.DeletedResource=In this version of the REST API resource {0} has been deleted framework.exception.RequestEntityTooLarge=Request entity too large framework.exception.InsufficientStorage=Content storage quota exceeded +framework.no.stacktrace=For security reasons the stack trace is no longer displayed, but the property is kept for previous versions. diff --git a/source/java/org/alfresco/rest/framework/core/exceptions/DefaultExceptionResolver.java b/source/java/org/alfresco/rest/framework/core/exceptions/DefaultExceptionResolver.java index 7e8ebf3be6..21b9af254b 100644 --- a/source/java/org/alfresco/rest/framework/core/exceptions/DefaultExceptionResolver.java +++ b/source/java/org/alfresco/rest/framework/core/exceptions/DefaultExceptionResolver.java @@ -9,6 +9,7 @@ import javax.servlet.http.HttpServletResponse; */ public class DefaultExceptionResolver implements ExceptionResolver { + public static final String STACK_MESSAGE_ID = "framework.no.stacktrace"; public static final String ERROR_URL = "https://api-explorer.alfresco.com"; public static final String DEFAULT_MESSAGE_ID = "framework.exception.ApiDefault"; diff --git a/source/java/org/alfresco/rest/framework/core/exceptions/ErrorResponse.java b/source/java/org/alfresco/rest/framework/core/exceptions/ErrorResponse.java index bd0f416560..ee77083b26 100644 --- a/source/java/org/alfresco/rest/framework/core/exceptions/ErrorResponse.java +++ b/source/java/org/alfresco/rest/framework/core/exceptions/ErrorResponse.java @@ -11,13 +11,14 @@ import java.util.Map; */ public class ErrorResponse { - final private String errorKey; - final private int statusCode; - final private String briefSummary; - final private String stackTrace; - final private Map additionalState; - final private String descriptionURL; - + private final String errorKey; + private final int statusCode; + private final String briefSummary; + private final String stackTrace; + private final Map additionalState; + private final String descriptionURL; + private final String logId; + public ErrorResponse(String errorKey, int statusCode, String briefSummary, StackTraceElement[] stackTrace, Map additionalState) { @@ -28,16 +29,18 @@ public class ErrorResponse this.stackTrace = Arrays.toString(stackTrace); this.additionalState = additionalState==null?null:Collections.unmodifiableMap(additionalState); this.descriptionURL = null; + this.logId = null; } public ErrorResponse(String errorKey, int statusCode, String briefSummary, - String stackTrace, Map additionalState, String descriptionURL) + String stackMessage, String logId, Map additionalState, String descriptionURL) { super(); this.errorKey = errorKey; this.statusCode = statusCode; this.briefSummary = briefSummary; - this.stackTrace = stackTrace; + this.stackTrace = stackMessage; + this.logId = logId; this.additionalState = additionalState==null?null:Collections.unmodifiableMap(additionalState); this.descriptionURL = descriptionURL; } @@ -72,6 +75,10 @@ public class ErrorResponse return this.additionalState; } + public String getLogId() { + return logId; + } + @Override public String toString() { @@ -79,6 +86,7 @@ public class ErrorResponse builder.append("ErrorResponse [errorKey=").append(this.errorKey).append(", statusCode=") .append(this.statusCode).append(", briefSummary=").append(this.briefSummary) .append(", descriptionURL=").append(this.descriptionURL) + .append(", logId=").append(this.logId) .append(", stackTrace=").append(this.stackTrace).append(", additionalState=") .append(this.additionalState).append("]"); return builder.toString(); diff --git a/source/java/org/alfresco/rest/framework/webscripts/ApiWebScript.java b/source/java/org/alfresco/rest/framework/webscripts/ApiWebScript.java index 1992168a27..a98a7fcc38 100644 --- a/source/java/org/alfresco/rest/framework/webscripts/ApiWebScript.java +++ b/source/java/org/alfresco/rest/framework/webscripts/ApiWebScript.java @@ -43,6 +43,7 @@ import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.json.simple.JSONObject; +import org.springframework.extensions.surf.util.I18NUtil; import org.springframework.extensions.webscripts.*; import org.springframework.extensions.webscripts.Description.RequiredCache; import org.springframework.extensions.webscripts.servlet.WebScriptServletResponse; @@ -202,18 +203,21 @@ public abstract class ApiWebScript extends AbstractWebScript */ public void renderErrorResponse(ErrorResponse errorResponse, final WebScriptResponse res) throws IOException { - String logKey = " "; + String logId = ""; if (Status.STATUS_INTERNAL_SERVER_ERROR == errorResponse.getStatusCode() || logger.isDebugEnabled()) { - logKey = GUID.generate(); - logger.error(logKey+" : "+errorResponse.getStackTrace()); + logId = GUID.generate(); + logger.error(logId+" : "+errorResponse.getStackTrace()); } + String stackMessage = I18NUtil.getMessage(DefaultExceptionResolver.STACK_MESSAGE_ID); + final ErrorResponse errorToWrite = new ErrorResponse(errorResponse.getErrorKey(), errorResponse.getStatusCode(), errorResponse.getBriefSummary(), - logKey, + stackMessage, + logId, errorResponse.getAdditionalState(), DefaultExceptionResolver.ERROR_URL); diff --git a/source/test-java/org/alfresco/rest/framework/tests/core/ExecutionTests.java b/source/test-java/org/alfresco/rest/framework/tests/core/ExecutionTests.java index 8258f465e5..0503e6f419 100644 --- a/source/test-java/org/alfresco/rest/framework/tests/core/ExecutionTests.java +++ b/source/test-java/org/alfresco/rest/framework/tests/core/ExecutionTests.java @@ -287,20 +287,22 @@ public class ExecutionTests extends AbstractContextTest ByteArrayOutputStream out = new ByteArrayOutputStream(); executor.renderErrorResponse(defaultError, mockResponse(out)); String errorMessage = out.toString(); - //System.out.println(errorMessage); +// System.out.println(errorMessage); assertTrue(errorMessage.contains("\"errorKey\":\"framework.exception.ApiDefault\"")); assertTrue(errorMessage.contains("\"statusCode\":500")); - assertTrue(errorMessage.contains("\"stackTrace\":\"")); + assertTrue(errorMessage.contains("\"logId\":\"")); + assertTrue(errorMessage.contains("\"stackTrace\":\"For security reasons the stack trace is no longer displayed")); assertTrue(errorMessage.contains("\"descriptionURL\":\""+DefaultExceptionResolver.ERROR_URL+"\"")); ErrorResponse anError = simpleMappingExceptionResolver.resolveException(new ApiException("nothing")); out = new ByteArrayOutputStream(); executor.renderErrorResponse(anError, mockResponse(out)); errorMessage = out.toString(); - System.out.println(errorMessage); + // System.out.println(errorMessage); assertTrue(errorMessage.contains("\"errorKey\":\"nothing\"")); assertTrue(errorMessage.contains("\"statusCode\":500")); - assertTrue(errorMessage.contains("\"stackTrace\":\"")); + assertTrue(errorMessage.contains("\"stackTrace\":\"For security reasons the stack trace is no longer displayed")); + assertTrue(errorMessage.contains("\"logId\":\"")); anError = simpleMappingExceptionResolver.resolveException(new EntityNotFoundException("2")); out = new ByteArrayOutputStream(); @@ -309,7 +311,7 @@ public class ExecutionTests extends AbstractContextTest System.out.println(errorMessage); assertTrue(errorMessage.contains("\"errorKey\":\"framework.exception.EntityNotFound\"")); assertTrue(errorMessage.contains("\"statusCode\":404")); - assertTrue("Only 500 errors should have a stracktrace", errorMessage.contains("\"stackTrace\":\" \"")); + assertFalse("Only 500 errors should have a logId", errorMessage.contains("\"logId\":\" \"")); } private WebScriptResponse mockResponse() throws IOException