From 6c407b1ef5b9002534b2e114e186a0e273495d5a Mon Sep 17 00:00:00 2001 From: mikolajbrzezinski <86791239+mikolajbrzezinski@users.noreply.github.com> Date: Wed, 10 Aug 2022 14:36:25 +0200 Subject: [PATCH] Revert "ACS-3316 Fix HTML sanitisation bypass (#1266)" (#1294) This reverts commit 885f21ff86e2a2fdae0d6d9f83bfc6df2e6fc648. --- .../web/scripts/SlingshotContentGetTest.java | 52 ++------------- .../repo/web/scripts/MimeTypeUtil.java | 64 ------------------ .../repo/web/scripts/content/ContentGet.java | 36 ++-------- .../repo/web/scripts/content/ContentInfo.java | 65 +++++++++++-------- .../web/scripts/content/ContentStreamer.java | 16 ++++- .../web-scripts-application-context.xml | 1 - .../web/scripts/content/ContentGetTest.java | 60 ++++------------- 7 files changed, 70 insertions(+), 224 deletions(-) delete mode 100644 remote-api/src/main/java/org/alfresco/repo/web/scripts/MimeTypeUtil.java diff --git a/amps/share-services/src/test/java/org/alfresco/slingshot/web/scripts/SlingshotContentGetTest.java b/amps/share-services/src/test/java/org/alfresco/slingshot/web/scripts/SlingshotContentGetTest.java index 00c646c99b..f500bf0cd2 100644 --- a/amps/share-services/src/test/java/org/alfresco/slingshot/web/scripts/SlingshotContentGetTest.java +++ b/amps/share-services/src/test/java/org/alfresco/slingshot/web/scripts/SlingshotContentGetTest.java @@ -40,7 +40,6 @@ import org.json.JSONObject; import org.junit.Assert; import org.springframework.extensions.webscripts.TestWebScriptServer; import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest; -import org.springframework.extensions.webscripts.TestWebScriptServer.Response; import java.io.Serializable; import java.util.ArrayList; @@ -195,13 +194,13 @@ public class SlingshotContentGetTest extends BaseWebScriptTest NodeRef rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER); - NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN); + NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content"); NodeRef folderX = createNode(rootFolder, "X", ContentModel.TYPE_FOLDER); NodeRef folderY = createNode(folderX, "Y", ContentModel.TYPE_FOLDER); NodeRef folderZ = createNode(folderY, "Z", ContentModel.TYPE_FOLDER); - NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN); + NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content"); // uri with relative path at the end String uri = URL_CONTENT_DOWNLOAD + doc1.getId() + "/X/Y/Z/doc2"; @@ -213,50 +212,7 @@ public class SlingshotContentGetTest extends BaseWebScriptTest nodeService.deleteNode(rootFolder); } - public void testForcedAttachment() throws Exception - { - Repository repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper"); - NodeRef companyHome = repositoryHelper.getCompanyHome(); - - NodeRef rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER); - NodeRef testhtml = createNodeWithTextContent(rootFolder, "testhtml", ContentModel.TYPE_CONTENT, "testhtml content", MimetypeMap.MIMETYPE_HTML); - NodeRef testpdf = createNodeWithTextContent(rootFolder, "testpdf", ContentModel.TYPE_CONTENT, "testpdf content", MimetypeMap.MIMETYPE_PDF); - - String uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=false"; - GetRequest req = new GetRequest(uri); - Response res = sendRequest(req, 200); - assertEquals("attachment", res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testhtml.getId(); - res = sendRequest(new GetRequest(uri), 200); - assertEquals("attachment", res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=true"; - res = sendRequest(new GetRequest(uri), 200); - assertEquals("attachment", res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=false"; - res = sendRequest(new GetRequest(uri), 200); - assertNull(res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testpdf.getId(); - res = sendRequest(new GetRequest(uri), 200); - assertNull(res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=true"; - res = sendRequest(new GetRequest(uri), 200); - assertEquals("attachment", res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType()); - - nodeService.deleteNode(rootFolder); - } - - public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content, String mimetype) + public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content) { NodeRef nodeRef = createNode(parentNode, nodeCmName, nodeType); @@ -264,7 +220,7 @@ public class SlingshotContentGetTest extends BaseWebScriptTest if (content != null) { ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); - writer.setMimetype(mimetype); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); writer.setEncoding("UTF-8"); writer.putContent(content); } diff --git a/remote-api/src/main/java/org/alfresco/repo/web/scripts/MimeTypeUtil.java b/remote-api/src/main/java/org/alfresco/repo/web/scripts/MimeTypeUtil.java deleted file mode 100644 index 9d245ad4ea..0000000000 --- a/remote-api/src/main/java/org/alfresco/repo/web/scripts/MimeTypeUtil.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2022 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 . - * #L% - */ -package org.alfresco.repo.web.scripts; - -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.cmr.repository.MimetypeService; -import org.springframework.extensions.webscripts.WebScriptRequest; - -public class MimeTypeUtil -{ - - /** - * Get the file mimetype from the file ContentReader, and if its null then set the mimetype to binary by default - * and try to get the correct one from file extension - * - * - * @param reader reader of the file in the request - * @param req request relating to the file - * @param mimetypeService MimetypeService - * - * @return mimetype of the file as a string - */ - public static String determineMimetype(ContentReader reader, WebScriptRequest req, MimetypeService mimetypeService) - { - String mimetype = reader.getMimetype(); - if (mimetype == null || mimetype.length() == 0) - { - String extensionPath = req.getExtensionPath(); - mimetype = MimetypeMap.MIMETYPE_BINARY; - int extIndex = extensionPath.lastIndexOf('.'); - if (extIndex != -1) - { - String ext = extensionPath.substring(extIndex + 1); - mimetype = mimetypeService.getMimetype(ext); - } - } - return mimetype; - } - -} diff --git a/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentGet.java b/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentGet.java index 1efa6b42ee..83e32679d7 100644 --- a/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentGet.java +++ b/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentGet.java @@ -2,7 +2,7 @@ * #%L * Alfresco Remote API * %% - * Copyright (C) 2005 - 2022 Alfresco Software Limited + * 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 @@ -26,18 +26,14 @@ package org.alfresco.repo.web.scripts.content; import java.io.IOException; -import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletResponse; import org.alfresco.model.ContentModel; -import org.alfresco.repo.web.scripts.MimeTypeUtil; import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.NamespaceService; @@ -69,19 +65,6 @@ public class ContentGet extends StreamContent implements ServletContextAware private NamespaceService namespaceService; private ContentService contentService; - private List nonAttachContentTypes = Collections.emptyList(); - - /** - * @param nonAttachContentTypes List - */ - public void setNonAttachContentTypes(List nonAttachContentTypes) - { - if (nonAttachContentTypes != null && !nonAttachContentTypes.isEmpty()) - { - this.nonAttachContentTypes = nonAttachContentTypes; - } - } - /** * @param servletContext ServletContext */ @@ -138,7 +121,9 @@ public class ContentGet extends StreamContent implements ServletContextAware { throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + reference.toString()); } - + + // determine attachment + boolean attach = Boolean.valueOf(req.getParameter("a")); // render content QName propertyQName = ContentModel.PROP_CONTENT; @@ -155,19 +140,6 @@ public class ContentGet extends StreamContent implements ServletContextAware propertyQName = QName.createQName(propertyName, namespaceService); } } - // determine attachment and force download for specific mimetypes - see PRODSEC-5862 - boolean attach = Boolean.valueOf(req.getParameter("a")); - ContentReader reader = contentService.getReader(nodeRef, propertyQName); - String mimetype = MimeTypeUtil.determineMimetype(reader, req, mimetypeService); - - if (!attach) - { - if (nonAttachContentTypes == null || !nonAttachContentTypes.contains(mimetype)) - { - attach = true; - logger.warn("Ignored a=false for " + nodeRef.getId() + " since " + mimetype + " is not in the whitelist for non-attach content types"); - } - } // Stream the content streamContentLocal(req, res, nodeRef, attach, propertyQName, null); diff --git a/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentInfo.java b/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentInfo.java index 9e8b8c2572..2e34694c24 100644 --- a/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentInfo.java +++ b/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentInfo.java @@ -1,28 +1,28 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2022 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 . - * #L% - */ +/* + * #%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 . + * #L% + */ package org.alfresco.repo.web.scripts.content; import java.io.IOException; @@ -33,7 +33,7 @@ import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.alfresco.model.ContentModel; -import org.alfresco.repo.web.scripts.MimeTypeUtil; +import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; @@ -79,7 +79,18 @@ public class ContentInfo extends StreamContent delegate.setAttachment(req, res, attach, attachFileName); // establish mimetype - String mimetype = MimeTypeUtil.determineMimetype(reader, req, mimetypeService); + String mimetype = reader.getMimetype(); + String extensionPath = req.getExtensionPath(); + if (mimetype == null || mimetype.length() == 0) + { + mimetype = MimetypeMap.MIMETYPE_BINARY; + int extIndex = extensionPath.lastIndexOf('.'); + if (extIndex != -1) + { + String ext = extensionPath.substring(extIndex + 1); + mimetype = mimetypeService.getMimetype(ext); + } + } // set mimetype for the content and the character encoding + length for the stream res.setContentType(mimetype); diff --git a/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentStreamer.java b/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentStreamer.java index 8c418ce92d..75a4948cd5 100644 --- a/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentStreamer.java +++ b/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentStreamer.java @@ -2,7 +2,7 @@ * #%L * Alfresco Remote API * %% - * Copyright (C) 2005 - 2022 Alfresco Software Limited + * 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 @@ -43,7 +43,6 @@ import javax.servlet.http.HttpServletResponse; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.filestore.FileContentReader; -import org.alfresco.repo.web.scripts.MimeTypeUtil; import org.alfresco.sync.repo.events.EventPublisher; import org.alfresco.repo.web.util.HttpRangeProcessor; import org.alfresco.rest.framework.resource.content.CacheDirective; @@ -362,7 +361,18 @@ public class ContentStreamer implements ResourceLoaderAware setAttachment(req, res, attach, attachFileName); // establish mimetype - String mimetype = MimeTypeUtil.determineMimetype(reader, req, mimetypeService); + String mimetype = reader.getMimetype(); + String extensionPath = req.getExtensionPath(); + if (mimetype == null || mimetype.length() == 0) + { + mimetype = MimetypeMap.MIMETYPE_BINARY; + int extIndex = extensionPath.lastIndexOf('.'); + if (extIndex != -1) + { + String ext = extensionPath.substring(extIndex + 1); + mimetype = mimetypeService.getMimetype(ext); + } + } res.setHeader(HEADER_ACCEPT_RANGES, "bytes"); try diff --git a/remote-api/src/main/resources/alfresco/web-scripts-application-context.xml b/remote-api/src/main/resources/alfresco/web-scripts-application-context.xml index 4da5da51b0..47d5358de3 100644 --- a/remote-api/src/main/resources/alfresco/web-scripts-application-context.xml +++ b/remote-api/src/main/resources/alfresco/web-scripts-application-context.xml @@ -249,7 +249,6 @@ - diff --git a/remote-api/src/test/java/org/alfresco/repo/web/scripts/content/ContentGetTest.java b/remote-api/src/test/java/org/alfresco/repo/web/scripts/content/ContentGetTest.java index 8a93587f58..3e0e2f0f0d 100644 --- a/remote-api/src/test/java/org/alfresco/repo/web/scripts/content/ContentGetTest.java +++ b/remote-api/src/test/java/org/alfresco/repo/web/scripts/content/ContentGetTest.java @@ -66,17 +66,13 @@ public class ContentGetTest extends BaseWebScriptTest { super.setUp(); - this.authenticationService = (MutableAuthenticationService)getServer().getApplicationContext().getBean("AuthenticationService"); + this.authenticationService = (MutableAuthenticationService) getServer().getApplicationContext() + .getBean("AuthenticationService"); this.personService = (PersonService) getServer().getApplicationContext().getBean("PersonService"); this.nodeService = (NodeService) getServer().getApplicationContext().getBean("NodeService"); this.contentService = (ContentService) getServer().getApplicationContext().getBean("ContentService"); AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); createUser(USER_ONE); - - Repository repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper"); - NodeRef companyHome = repositoryHelper.getCompanyHome(); - - rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER); } private void createUser(String userName) @@ -121,13 +117,18 @@ public class ContentGetTest extends BaseWebScriptTest */ public void testRelativePath() throws Exception { - NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN); + Repository repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper"); + NodeRef companyHome = repositoryHelper.getCompanyHome(); + + rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER); + + NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content"); NodeRef folderX = createNode(rootFolder, "X", ContentModel.TYPE_FOLDER); NodeRef folderY = createNode(folderX, "Y", ContentModel.TYPE_FOLDER); NodeRef folderZ = createNode(folderY, "Z", ContentModel.TYPE_FOLDER); - NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN); + NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content"); // uri with relative path at the end String uri = URL_CONTENT_DOWNLOAD + doc1.getId() + "/X/Y/Z/doc2"; @@ -137,46 +138,7 @@ public class ContentGetTest extends BaseWebScriptTest Assert.assertEquals("doc2 file content", resp.getContentAsString()); } - - - public void testForcedAttachment() throws Exception - { - NodeRef testhtml = createNodeWithTextContent(rootFolder, "testhtml", ContentModel.TYPE_CONTENT, "testhtml content", MimetypeMap.MIMETYPE_HTML); - NodeRef testpdf = createNodeWithTextContent(rootFolder, "testpdf", ContentModel.TYPE_CONTENT, "testpdf content", MimetypeMap.MIMETYPE_PDF); - - String uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=false"; - GetRequest req = new GetRequest(uri); - Response res = sendRequest(req, 200); - assertEquals("attachment", res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testhtml.getId(); - res = sendRequest(new GetRequest(uri), 200); - assertEquals("attachment", res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=true"; - res = sendRequest(new GetRequest(uri), 200); - assertEquals("attachment", res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=false"; - res = sendRequest(new GetRequest(uri), 200); - assertNull(res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testpdf.getId(); - res = sendRequest(new GetRequest(uri), 200); - assertNull(res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType()); - - uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=true"; - res = sendRequest(new GetRequest(uri), 200); - assertEquals("attachment", res.getHeader("Content-Disposition")); - assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType()); - } - - public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content, String mimetype) + public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content) { NodeRef nodeRef = createNode(parentNode, nodeCmName, nodeType); @@ -184,7 +146,7 @@ public class ContentGetTest extends BaseWebScriptTest if (content != null) { ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true); - writer.setMimetype(mimetype); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); writer.setEncoding("UTF-8"); writer.putContent(content); }