From 9d979384e757161a9c6854ef4da16938238e46e0 Mon Sep 17 00:00:00 2001 From: Kevin Guerroudj <91883215+Kevin-CB@users.noreply.github.com> Date: Fri, 10 Mar 2023 23:01:49 +0100 Subject: [PATCH] Merge March 8 security tests into their main class (#7700) --- .../hudson/PluginManagerSecurity2823Test.java | 57 ---- .../hudson/PluginManagerSecurity3037Test.java | 101 ------ .../test/java/hudson/PluginManagerTest.java | 121 +++++++ .../hudson/model/ComputerSEC2120Test.java | 85 ----- .../java/hudson/model/ComputerSetTest.java | 43 +++ .../DirectoryBrowserSupportSEC1807Test.java | 302 ------------------ .../model/DirectoryBrowserSupportTest.java | 205 ++++++++++++ .../hudson/model/ExecutorSEC2120Test.java | 86 ----- .../test/java/hudson/model/ExecutorTest.java | 19 ++ .../hudson/search/SearchSecurity2399Test.java | 58 ---- .../test/java/hudson/search/SearchTest.java | 39 +++ .../security3037-update-center.json} | 0 12 files changed, 427 insertions(+), 689 deletions(-) delete mode 100644 test/src/test/java/hudson/PluginManagerSecurity2823Test.java delete mode 100644 test/src/test/java/hudson/PluginManagerSecurity3037Test.java delete mode 100644 test/src/test/java/hudson/model/ComputerSEC2120Test.java delete mode 100644 test/src/test/java/hudson/model/DirectoryBrowserSupportSEC1807Test.java delete mode 100644 test/src/test/java/hudson/model/ExecutorSEC2120Test.java delete mode 100644 test/src/test/java/hudson/search/SearchSecurity2399Test.java rename test/src/test/resources/{hudson/PluginManagerSecurity3037Test/update-center.json => plugins/security3037-update-center.json} (100%) diff --git a/test/src/test/java/hudson/PluginManagerSecurity2823Test.java b/test/src/test/java/hudson/PluginManagerSecurity2823Test.java deleted file mode 100644 index 8488a727562f..000000000000 --- a/test/src/test/java/hudson/PluginManagerSecurity2823Test.java +++ /dev/null @@ -1,57 +0,0 @@ -package hudson; - -import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; -import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; -import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeFalse; - -import com.gargoylesoftware.htmlunit.html.HtmlForm; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import java.io.File; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.attribute.PosixFilePermission; -import java.util.Arrays; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.JenkinsRule; - -public class PluginManagerSecurity2823Test { - - @Rule - public JenkinsRule r = PluginManagerUtil.newJenkinsRule(); - - @Rule - public TemporaryFolder tmp = new TemporaryFolder(); - - @Test - @Issue("SECURITY-2823") - public void verifyUploadedPluginPermission() throws Exception { - assumeFalse(Functions.isWindows()); - - HtmlPage page = r.createWebClient().goTo("pluginManager/advanced"); - HtmlForm f = page.getFormByName("uploadPlugin"); - File dir = tmp.newFolder(); - File plugin = new File(dir, "htmlpublisher.jpi"); - FileUtils.copyURLToFile(Objects.requireNonNull(getClass().getClassLoader().getResource("plugins/htmlpublisher.jpi")), plugin); - f.getInputByName("name").setValueAttribute(plugin.getAbsolutePath()); - r.submit(f); - - File tmpDir = Files.createTempFile("tmp", ".tmp").getParent().toFile(); - tmpDir.deleteOnExit(); - - Optional lastUploadedPlugin = Arrays.stream(Objects.requireNonNull(tmpDir.listFiles((file, fileName) -> fileName.startsWith("uploaded")))).max(Comparator.comparingLong(File::lastModified)); - Set filesPermission = Files.getPosixFilePermissions(lastUploadedPlugin.get().toPath(), LinkOption.NOFOLLOW_LINKS); - - assertEquals(EnumSet.of(OWNER_READ, OWNER_WRITE), filesPermission); - } - -} diff --git a/test/src/test/java/hudson/PluginManagerSecurity3037Test.java b/test/src/test/java/hudson/PluginManagerSecurity3037Test.java deleted file mode 100644 index cdc420d86eab..000000000000 --- a/test/src/test/java/hudson/PluginManagerSecurity3037Test.java +++ /dev/null @@ -1,101 +0,0 @@ -package hudson; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import com.gargoylesoftware.htmlunit.AlertHandler; -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.html.HtmlAnchor; -import com.gargoylesoftware.htmlunit.html.HtmlElement; -import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import hudson.model.DownloadService; -import hudson.model.RootAction; -import hudson.model.UpdateSite; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import javax.servlet.ServletException; -import jenkins.model.Jenkins; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.FlagRule; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.TestExtension; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; - -public class PluginManagerSecurity3037Test { - @Rule - public JenkinsRule r = new JenkinsRule(); - - @Rule - public FlagRule signatureCheck = new FlagRule<>(() -> DownloadService.signatureCheck, x -> DownloadService.signatureCheck = x); - - @Test - public void noInjectionOnAvailablePluginsPage() throws Exception { - DownloadService.signatureCheck = false; - Jenkins.get().getUpdateCenter().getSites().clear(); - UpdateSite us = new UpdateSite("Security3037", Jenkins.get().getRootUrl() + "security3037UpdateCenter/update-center.json"); - Jenkins.get().getUpdateCenter().getSites().add(us); - - try (JenkinsRule.WebClient wc = r.createWebClient()) { - HtmlPage p = wc.goTo("pluginManager"); - List elements = p.getElementById("bottom-sticker") - .getElementsByTagName("a") - .stream() - .filter(link -> link.getAttribute("href").equals("checkUpdatesServer")) - .collect(Collectors.toList()); - assertEquals(1, elements.size()); - AlertHandlerImpl alertHandler = new AlertHandlerImpl(); - wc.setAlertHandler(alertHandler); - - HtmlElementUtil.click(elements.get(0)); - HtmlPage available = wc.goTo("pluginManager/available"); - assertTrue(available.querySelector(".alert-danger") - .getTextContent().contains("This plugin is built for Jenkins 2.999")); - wc.waitForBackgroundJavaScript(100); - - HtmlAnchor anchor = available.querySelector(".jenkins-table__link"); - anchor.click(true, false, false); - wc.waitForBackgroundJavaScript(100); - assertTrue(alertHandler.messages.isEmpty()); - } - } - - static class AlertHandlerImpl implements AlertHandler { - List messages = Collections.synchronizedList(new ArrayList<>()); - - @Override - public void handleAlert(final Page page, final String message) { - messages.add(message); - } - } - - @TestExtension("noInjectionOnAvailablePluginsPage") - public static final class Security3037UpdateCenter implements RootAction { - - @Override - public String getIconFileName() { - return "gear2.png"; - } - - @Override - public String getDisplayName() { - return "security-3037-update-center"; - } - - @Override - public String getUrlName() { - return "security3037UpdateCenter"; - } - - public void doDynamic(StaplerRequest staplerRequest, StaplerResponse staplerResponse) throws ServletException, IOException { - staplerResponse.setContentType("application/json"); - staplerResponse.setStatus(200); - staplerResponse.serveFile(staplerRequest, PluginManagerSecurity3037Test.class.getResource("PluginManagerSecurity3037Test/update-center.json")); - } - } -} diff --git a/test/src/test/java/hudson/PluginManagerTest.java b/test/src/test/java/hudson/PluginManagerTest.java index 13e4de6d5e02..da444cf29057 100644 --- a/test/src/test/java/hudson/PluginManagerTest.java +++ b/test/src/test/java/hudson/PluginManagerTest.java @@ -24,6 +24,9 @@ package hudson; +import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; +import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; +import static org.awaitility.Awaitility.await; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -32,9 +35,15 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; +import com.gargoylesoftware.htmlunit.AlertHandler; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.html.HtmlAnchor; +import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.PluginManager.UberClassLoader; +import hudson.model.DownloadService; import hudson.model.Hudson; import hudson.model.RootAction; import hudson.model.UpdateCenter; @@ -59,10 +68,23 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.attribute.PosixFilePermission; import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.HashSet; import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import javax.servlet.ServletException; import jenkins.ClassLoaderReflectionToolkit; import jenkins.RestartRequiredException; @@ -75,6 +97,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.jvnet.hudson.test.FlagRule; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.MockAuthorizationStrategy; @@ -92,6 +115,7 @@ public class PluginManagerTest { @Rule public JenkinsRule r = PluginManagerUtil.newJenkinsRule(); @Rule public TemporaryFolder tmp = new TemporaryFolder(); + @Rule public FlagRule signatureCheck = new FlagRule<>(() -> DownloadService.signatureCheck, x -> DownloadService.signatureCheck = x); /** * Manual submission form. @@ -711,4 +735,101 @@ public void installNecessaryPluginsTest() throws Exception { // Redirect reported 404 before bug was fixed assertEquals("Bad response for installNecessaryPlugins", 200, response.statusCode()); } + + @Test + @Issue("SECURITY-2823") + public void verifyUploadedPluginPermission() throws Exception { + assumeFalse(Functions.isWindows()); + + HtmlPage page = r.createWebClient().goTo("pluginManager/advanced"); + HtmlForm f = page.getFormByName("uploadPlugin"); + File dir = tmp.newFolder(); + File plugin = new File(dir, "htmlpublisher.jpi"); + FileUtils.copyURLToFile(Objects.requireNonNull(getClass().getClassLoader().getResource("plugins/htmlpublisher.jpi")), plugin); + f.getInputByName("name").setValueAttribute(plugin.getAbsolutePath()); + r.submit(f); + + File tmpDir = new File(File.createTempFile("tmp", ".tmp").getParent()); + tmpDir.deleteOnExit(); + final Set[] filesPermission = new Set[]{new HashSet<>()}; + await().pollInterval(250, TimeUnit.MILLISECONDS) + .atMost(10, TimeUnit.SECONDS) + .until(() -> { + Optional lastUploadedPlugin = Arrays.stream(Objects.requireNonNull(tmpDir.listFiles((file, fileName) -> fileName.startsWith("uploaded")))).max(Comparator.comparingLong(File::lastModified)); + if (lastUploadedPlugin.isPresent()) { + filesPermission[0] = Files.getPosixFilePermissions(lastUploadedPlugin.get().toPath(), LinkOption.NOFOLLOW_LINKS); + return true; + } else { + return false; + } + }); + assertEquals(EnumSet.of(OWNER_READ, OWNER_WRITE), filesPermission[0]); + } + + @Test + @Issue("SECURITY-3037") + public void noInjectionOnAvailablePluginsPage() throws Exception { + DownloadService.signatureCheck = false; + Jenkins.get().getUpdateCenter().getSites().clear(); + UpdateSite us = new UpdateSite("Security3037", Jenkins.get().getRootUrl() + "security3037UpdateCenter/security3037-update-center.json"); + Jenkins.get().getUpdateCenter().getSites().add(us); + + try (JenkinsRule.WebClient wc = r.createWebClient()) { + HtmlPage p = wc.goTo("pluginManager"); + List elements = p.getElementById("bottom-sticker") + .getElementsByTagName("a") + .stream() + .filter(link -> link.getAttribute("href").equals("checkUpdatesServer")) + .collect(Collectors.toList()); + assertEquals(1, elements.size()); + AlertHandlerImpl alertHandler = new AlertHandlerImpl(); + wc.setAlertHandler(alertHandler); + + HtmlElementUtil.click(elements.get(0)); + HtmlPage available = wc.goTo("pluginManager/available"); + assertTrue(available.querySelector(".alert-danger") + .getTextContent().contains("This plugin is built for Jenkins 2.999")); + wc.waitForBackgroundJavaScript(100); + + HtmlAnchor anchor = available.querySelector(".jenkins-table__link"); + anchor.click(true, false, false); + wc.waitForBackgroundJavaScript(100); + assertTrue(alertHandler.messages.isEmpty()); + } + } + + static class AlertHandlerImpl implements AlertHandler { + List messages = Collections.synchronizedList(new ArrayList<>()); + + @Override + public void handleAlert(final Page page, final String message) { + messages.add(message); + } + } + + @TestExtension("noInjectionOnAvailablePluginsPage") + public static final class Security3037UpdateCenter implements RootAction { + + @Override + public String getIconFileName() { + return "gear2.png"; + } + + @Override + public String getDisplayName() { + return "security-3037-update-center"; + } + + @Override + public String getUrlName() { + return "security3037UpdateCenter"; + } + + public void doDynamic(StaplerRequest staplerRequest, StaplerResponse staplerResponse) throws ServletException, IOException { + staplerResponse.setContentType("application/json"); + staplerResponse.setStatus(200); + staplerResponse.serveFile(staplerRequest, PluginManagerTest.class.getResource("/plugins/security3037-update-center.json")); + } + } + } diff --git a/test/src/test/java/hudson/model/ComputerSEC2120Test.java b/test/src/test/java/hudson/model/ComputerSEC2120Test.java deleted file mode 100644 index cfbddf64c857..000000000000 --- a/test/src/test/java/hudson/model/ComputerSEC2120Test.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2015 Red Hat, Inc.; Christopher Simons - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package hudson.model; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; - -import com.gargoylesoftware.htmlunit.Page; -import hudson.slaves.DumbSlave; -import hudson.slaves.OfflineCause; -import java.util.concurrent.Future; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.JenkinsRule.WebClient; -import org.jvnet.hudson.test.SmokeTest; - -@Category(SmokeTest.class) -public class ComputerSEC2120Test { - - @Rule public JenkinsRule j = new JenkinsRule(); - - @Test - public void testTerminatedNodeStatusPageDoesNotShowTrace() throws Exception { - DumbSlave agent = j.createOnlineSlave(); - FreeStyleProject p = j.createFreeStyleProject(); - p.setAssignedNode(agent); - - Future r = ExecutorTest.startBlockingBuild(p); - - String message = "It went away"; - p.getLastBuild().getBuiltOn().toComputer().disconnect( - new OfflineCause.ChannelTermination(new RuntimeException(message)) - ); - - WebClient wc = j.createWebClient(); - Page page = wc.getPage(wc.createCrumbedUrl(agent.toComputer().getUrl())); - String content = page.getWebResponse().getContentAsString(); - assertThat(content, not(containsString(message))); - } - - @Test - public void testTerminatedNodeAjaxExecutorsDoesNotShowTrace() throws Exception { - DumbSlave agent = j.createOnlineSlave(); - FreeStyleProject p = j.createFreeStyleProject(); - p.setAssignedNode(agent); - - Future r = ExecutorTest.startBlockingBuild(p); - - String message = "It went away"; - p.getLastBuild().getBuiltOn().toComputer().disconnect( - new OfflineCause.ChannelTermination(new RuntimeException(message)) - ); - - WebClient wc = j.createWebClient(); - Page page = wc.getPage(wc.createCrumbedUrl("ajaxExecutors")); - String content = page.getWebResponse().getContentAsString(); - assertThat(content, not(containsString(message))); - } - -} diff --git a/test/src/test/java/hudson/model/ComputerSetTest.java b/test/src/test/java/hudson/model/ComputerSetTest.java index 871e50d08bc8..e7a584809979 100644 --- a/test/src/test/java/hudson/model/ComputerSetTest.java +++ b/test/src/test/java/hudson/model/ComputerSetTest.java @@ -33,11 +33,14 @@ import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; +import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.cli.CLICommandInvoker; import hudson.slaves.DumbSlave; +import hudson.slaves.OfflineCause; import java.net.HttpURLConnection; +import java.util.concurrent.Future; import jenkins.model.Jenkins; import org.junit.Rule; import org.junit.Test; @@ -133,4 +136,44 @@ public void managePermissionCanConfigure() throws Exception { responseContent = page.getWebResponse().getContentAsString(); assertThat(responseContent, containsString("OK")); } + + @Test + @Issue("SECURITY-2120") + public void testTerminatedNodeStatusPageDoesNotShowTrace() throws Exception { + DumbSlave agent = j.createOnlineSlave(); + FreeStyleProject p = j.createFreeStyleProject(); + p.setAssignedNode(agent); + + Future r = ExecutorTest.startBlockingBuild(p); + + String message = "It went away"; + p.getLastBuild().getBuiltOn().toComputer().disconnect( + new OfflineCause.ChannelTermination(new RuntimeException(message)) + ); + + WebClient wc = j.createWebClient(); + Page page = wc.getPage(wc.createCrumbedUrl(agent.toComputer().getUrl())); + String content = page.getWebResponse().getContentAsString(); + assertThat(content, not(containsString(message))); + } + + @Test + @Issue("SECURITY-2120") + public void testTerminatedNodeAjaxExecutorsDoesNotShowTrace() throws Exception { + DumbSlave agent = j.createOnlineSlave(); + FreeStyleProject p = j.createFreeStyleProject(); + p.setAssignedNode(agent); + + Future r = ExecutorTest.startBlockingBuild(p); + + String message = "It went away"; + p.getLastBuild().getBuiltOn().toComputer().disconnect( + new OfflineCause.ChannelTermination(new RuntimeException(message)) + ); + + WebClient wc = j.createWebClient(); + Page page = wc.getPage(wc.createCrumbedUrl("ajaxExecutors")); + String content = page.getWebResponse().getContentAsString(); + assertThat(content, not(containsString(message))); + } } diff --git a/test/src/test/java/hudson/model/DirectoryBrowserSupportSEC1807Test.java b/test/src/test/java/hudson/model/DirectoryBrowserSupportSEC1807Test.java deleted file mode 100644 index 8d9e242704bb..000000000000 --- a/test/src/test/java/hudson/model/DirectoryBrowserSupportSEC1807Test.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package hudson.model; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.UnexpectedPage; -import hudson.FilePath; -import hudson.Launcher; -import hudson.slaves.WorkspaceList; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.nio.file.Files; -import java.util.List; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import org.apache.commons.io.IOUtils; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.TestBuilder; - -/** - * @author Kohsuke Kawaguchi - */ -public class DirectoryBrowserSupportSEC1807Test { - - @Rule public JenkinsRule j = new JenkinsRule(); - - private File download(UnexpectedPage page) throws IOException { - - File file = File.createTempFile("DirectoryBrowserSupport", "zipDownload"); - file.delete(); - try (InputStream is = page.getInputStream(); - OutputStream os = Files.newOutputStream(file.toPath())) { - IOUtils.copy(is, os); - } - - return file; - } - - private List getListOfEntriesInDownloadedZip(UnexpectedPage zipPage) throws Exception { - List result; - - File zipfile = null; - ZipFile readzip = null; - try { - zipfile = download(zipPage); - - readzip = new ZipFile(zipfile); - result = readzip.stream().map(ZipEntry::getName).collect(Collectors.toList()); - } - finally { - if (readzip != null) { - readzip.close(); - } - if (zipfile != null) { - zipfile.delete(); - } - } - return result; - } - - @Test - @Issue("SECURITY-1807") - public void tmpNotListed() throws Exception { - FreeStyleProject p = j.createFreeStyleProject(); - p.getBuildersList().add(new TestBuilder() { - @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - FilePath ws = build.getWorkspace(); - ws.child("anotherDir").mkdirs(); - WorkspaceList.tempDir(ws.child("subdir")).mkdirs(); - return true; - } - }); - assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); - - String text = j.createWebClient().goTo("job/" + p.getName() + "/ws/").asNormalizedText(); - assertTrue(text, text.contains("anotherDir")); - assertFalse(text, text.contains("subdir")); - } - - @Test - @Issue("SECURITY-1807") - public void tmpNotListedWithGlob() throws Exception { - FreeStyleProject p = j.createFreeStyleProject(); - - assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); - FilePath ws = p.getSomeWorkspace(); - - FilePath anotherDir = ws.child("anotherDir"); - anotherDir.mkdirs(); - anotherDir.child("insideDir").mkdirs(); - - FilePath mainTmp = WorkspaceList.tempDir(ws.child("subDir")); - mainTmp.mkdirs(); - - FilePath anotherTmp = WorkspaceList.tempDir(anotherDir.child("insideDir")); - anotherTmp.mkdirs(); - - ws.child("anotherDir/one.txt").touch(0); - ws.child("anotherDir/insideDir/two.txt").touch(0); - mainTmp.child("three.txt").touch(0); - anotherTmp.child("four.txt").touch(0); - - assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); - - String text = j.createWebClient().goTo("job/" + p.getName() + "/ws/**/*.txt").asNormalizedText(); - assertTrue(text, text.contains("one.txt")); - assertTrue(text, text.contains("two.txt")); - assertFalse(text, text.contains("three.txt")); - assertFalse(text, text.contains("four.txt")); - } - - @Test - @Issue("SECURITY-1807") - public void noDirectAccessToTmp() throws Exception { - FreeStyleProject p = j.createFreeStyleProject(); - p.getBuildersList().add(new TestBuilder() { - @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - FilePath ws = build.getWorkspace(); - - FilePath folder = ws.child("anotherDir"); - folder.mkdirs(); - folder.child("one.txt").touch(0); - - FilePath mainTmp = WorkspaceList.tempDir(ws.child("subDir")); - mainTmp.mkdirs(); - mainTmp.child("two.txt").touch(0); - - return true; - } - }); - assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); - - JenkinsRule.WebClient wc = j.createWebClient(); - wc.getOptions().setThrowExceptionOnFailingStatusCode(false); - - Page page = wc.goTo(p.getUrl() + "ws/anotherDir/", null); - assertThat(page.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); - page = wc.goTo(p.getUrl() + "ws/anotherDir/one.txt", null); - assertThat(page.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); - - page = wc.goTo(p.getUrl() + "ws/subdir@tmp/", null); - assertThat(page.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_NOT_FOUND)); - - page = wc.goTo(p.getUrl() + "ws/subdir@tmp/two.txt", null); - assertThat(page.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_NOT_FOUND)); - } - - @Test - @Issue("SECURITY-1807") - public void tmpNotListedInPlain() throws Exception { - FreeStyleProject p = j.createFreeStyleProject(); - p.getBuildersList().add(new TestBuilder() { - @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - FilePath ws = build.getWorkspace(); - ws.child("anotherDir").mkdirs(); - WorkspaceList.tempDir(ws.child("subdir")).mkdirs(); - return true; - } - }); - assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); - - String text = j.createWebClient().goTo("job/" + p.getName() + "/ws/*plain*", "text/plain").getWebResponse().getContentAsString(); - assertTrue(text, text.contains("anotherDir")); - assertFalse(text, text.contains("subdir")); - } - - @Test - @Issue("SECURITY-1807") - public void tmpNotListedInZipWithoutGlob() throws Exception { - FreeStyleProject p = j.createFreeStyleProject(); - p.getBuildersList().add(new TestBuilder() { - @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - FilePath ws = build.getWorkspace(); - - FilePath anotherDir = ws.child("anotherDir"); - anotherDir.mkdirs(); - anotherDir.child("insideDir").mkdirs(); - - FilePath mainTmp = WorkspaceList.tempDir(ws.child("subDir")); - mainTmp.mkdirs(); - - FilePath anotherTmp = WorkspaceList.tempDir(anotherDir.child("insideDir")); - anotherTmp.mkdirs(); - - ws.child("anotherDir/one.txt").touch(0); - ws.child("anotherDir/insideDir/two.txt").touch(0); - mainTmp.child("three.txt").touch(0); - anotherTmp.child("four.txt").touch(0); - return true; - } - }); - assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); - - JenkinsRule.WebClient wc = j.createWebClient(); - wc.getOptions().setThrowExceptionOnFailingStatusCode(false); - - //http://localhost:54407/jenkins/job/test0/ws/**/*.txt/*zip*/glob.zip - Page zipPage = wc.goTo("job/" + p.getName() + "/ws/*zip*/" + p.getName(), null); - assertThat(zipPage.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); - - List entryNames = getListOfEntriesInDownloadedZip((UnexpectedPage) zipPage); - assertThat(entryNames, hasSize(2)); - assertThat(entryNames, containsInAnyOrder( - "test0/anotherDir/one.txt", - "test0/anotherDir/insideDir/two.txt" - )); - - zipPage = wc.goTo("job/" + p.getName() + "/ws/anotherDir/*zip*/" + p.getName(), null); - assertThat(zipPage.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); - - entryNames = getListOfEntriesInDownloadedZip((UnexpectedPage) zipPage); - assertThat(entryNames, hasSize(2)); - assertThat(entryNames, containsInAnyOrder( - "anotherDir/one.txt", - "anotherDir/insideDir/two.txt" - )); - } - - @Test - @Issue("SECURITY-1807") - public void tmpNotListedInZipWithGlob() throws Exception { - FreeStyleProject p = j.createFreeStyleProject(); - p.getBuildersList().add(new TestBuilder() { - @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - FilePath ws = build.getWorkspace(); - - FilePath anotherDir = ws.child("anotherDir"); - anotherDir.mkdirs(); - anotherDir.child("insideDir").mkdirs(); - - FilePath mainTmp = WorkspaceList.tempDir(ws.child("subDir")); - mainTmp.mkdirs(); - - FilePath anotherTmp = WorkspaceList.tempDir(anotherDir.child("insideDir")); - anotherTmp.mkdirs(); - - ws.child("anotherDir/one.txt").touch(0); - ws.child("anotherDir/insideDir/two.txt").touch(0); - mainTmp.child("three.txt").touch(0); - anotherTmp.child("four.txt").touch(0); - return true; - } - }); - assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); - - JenkinsRule.WebClient wc = j.createWebClient(); - wc.getOptions().setThrowExceptionOnFailingStatusCode(false); - - Page zipPage = wc.goTo("job/" + p.getName() + "/ws/**/*.txt/*zip*/glob.zip", null); - assertThat(zipPage.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); - - List entryNames = getListOfEntriesInDownloadedZip((UnexpectedPage) zipPage); - assertThat(entryNames, hasSize(2)); - assertThat(entryNames, containsInAnyOrder( - "anotherDir/one.txt", - "anotherDir/insideDir/two.txt" - )); - } - -} diff --git a/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java b/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java index b62663aa4fc3..fcaa06bc8035 100644 --- a/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java +++ b/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java @@ -50,6 +50,7 @@ import hudson.Functions; import hudson.Launcher; import hudson.Util; +import hudson.slaves.WorkspaceList; import hudson.tasks.ArtifactArchiver; import hudson.tasks.BatchFile; import hudson.tasks.Shell; @@ -1138,6 +1139,210 @@ public void windows_canViewAbsolutePath_withEscapeHatch() throws Exception { } + @Test + @Issue("SECURITY-1807") + public void tmpNotListed() throws Exception { + FreeStyleProject p = j.createFreeStyleProject(); + p.getBuildersList().add(new TestBuilder() { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + FilePath ws = build.getWorkspace(); + ws.child("anotherDir").mkdirs(); + WorkspaceList.tempDir(ws.child("subdir")).mkdirs(); + return true; + } + }); + assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); + + String text = j.createWebClient().goTo("job/" + p.getName() + "/ws/").asNormalizedText(); + assertTrue(text, text.contains("anotherDir")); + assertFalse(text, text.contains("subdir")); + } + + @Test + @Issue("SECURITY-1807") + public void tmpNotListedWithGlob() throws Exception { + FreeStyleProject p = j.createFreeStyleProject(); + + assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); + FilePath ws = p.getSomeWorkspace(); + + FilePath anotherDir = ws.child("anotherDir"); + anotherDir.mkdirs(); + anotherDir.child("insideDir").mkdirs(); + + FilePath mainTmp = WorkspaceList.tempDir(ws.child("subDir")); + mainTmp.mkdirs(); + + FilePath anotherTmp = WorkspaceList.tempDir(anotherDir.child("insideDir")); + anotherTmp.mkdirs(); + + ws.child("anotherDir/one.txt").touch(0); + ws.child("anotherDir/insideDir/two.txt").touch(0); + mainTmp.child("three.txt").touch(0); + anotherTmp.child("four.txt").touch(0); + + assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); + + String text = j.createWebClient().goTo("job/" + p.getName() + "/ws/**/*.txt").asNormalizedText(); + assertTrue(text, text.contains("one.txt")); + assertTrue(text, text.contains("two.txt")); + assertFalse(text, text.contains("three.txt")); + assertFalse(text, text.contains("four.txt")); + } + + @Test + @Issue("SECURITY-1807") + public void noDirectAccessToTmp() throws Exception { + FreeStyleProject p = j.createFreeStyleProject(); + p.getBuildersList().add(new TestBuilder() { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + FilePath ws = build.getWorkspace(); + + FilePath folder = ws.child("anotherDir"); + folder.mkdirs(); + folder.child("one.txt").touch(0); + + FilePath mainTmp = WorkspaceList.tempDir(ws.child("subDir")); + mainTmp.mkdirs(); + mainTmp.child("two.txt").touch(0); + + return true; + } + }); + assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); + + JenkinsRule.WebClient wc = j.createWebClient(); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); + + Page page = wc.goTo(p.getUrl() + "ws/anotherDir/", null); + assertThat(page.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); + page = wc.goTo(p.getUrl() + "ws/anotherDir/one.txt", null); + assertThat(page.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); + + page = wc.goTo(p.getUrl() + "ws/subdir@tmp/", null); + assertThat(page.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_NOT_FOUND)); + + page = wc.goTo(p.getUrl() + "ws/subdir@tmp/two.txt", null); + assertThat(page.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_NOT_FOUND)); + } + + @Test + @Issue("SECURITY-1807") + public void tmpNotListedInPlain() throws Exception { + FreeStyleProject p = j.createFreeStyleProject(); + p.getBuildersList().add(new TestBuilder() { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + FilePath ws = build.getWorkspace(); + ws.child("anotherDir").mkdirs(); + WorkspaceList.tempDir(ws.child("subdir")).mkdirs(); + return true; + } + }); + assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); + + String text = j.createWebClient().goTo("job/" + p.getName() + "/ws/*plain*", "text/plain").getWebResponse().getContentAsString(); + assertTrue(text, text.contains("anotherDir")); + assertFalse(text, text.contains("subdir")); + } + + @Test + @Issue("SECURITY-1807") + public void tmpNotListedInZipWithoutGlob() throws Exception { + FreeStyleProject p = j.createFreeStyleProject(); + p.getBuildersList().add(new TestBuilder() { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + FilePath ws = build.getWorkspace(); + + FilePath anotherDir = ws.child("anotherDir"); + anotherDir.mkdirs(); + anotherDir.child("insideDir").mkdirs(); + + FilePath mainTmp = WorkspaceList.tempDir(ws.child("subDir")); + mainTmp.mkdirs(); + + FilePath anotherTmp = WorkspaceList.tempDir(anotherDir.child("insideDir")); + anotherTmp.mkdirs(); + + ws.child("anotherDir/one.txt").touch(0); + ws.child("anotherDir/insideDir/two.txt").touch(0); + mainTmp.child("three.txt").touch(0); + anotherTmp.child("four.txt").touch(0); + return true; + } + }); + assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); + + JenkinsRule.WebClient wc = j.createWebClient(); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); + + //http://localhost:54407/jenkins/job/test0/ws/**/*.txt/*zip*/glob.zip + Page zipPage = wc.goTo("job/" + p.getName() + "/ws/*zip*/" + p.getName(), null); + assertThat(zipPage.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); + + List entryNames = getListOfEntriesInDownloadedZip((UnexpectedPage) zipPage); + assertThat(entryNames, hasSize(2)); + assertThat(entryNames, containsInAnyOrder( + "test0/anotherDir/one.txt", + "test0/anotherDir/insideDir/two.txt" + )); + + zipPage = wc.goTo("job/" + p.getName() + "/ws/anotherDir/*zip*/" + p.getName(), null); + assertThat(zipPage.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); + + entryNames = getListOfEntriesInDownloadedZip((UnexpectedPage) zipPage); + assertThat(entryNames, hasSize(2)); + assertThat(entryNames, containsInAnyOrder( + "anotherDir/one.txt", + "anotherDir/insideDir/two.txt" + )); + } + + @Test + @Issue("SECURITY-1807") + public void tmpNotListedInZipWithGlob() throws Exception { + FreeStyleProject p = j.createFreeStyleProject(); + p.getBuildersList().add(new TestBuilder() { + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + FilePath ws = build.getWorkspace(); + + FilePath anotherDir = ws.child("anotherDir"); + anotherDir.mkdirs(); + anotherDir.child("insideDir").mkdirs(); + + FilePath mainTmp = WorkspaceList.tempDir(ws.child("subDir")); + mainTmp.mkdirs(); + + FilePath anotherTmp = WorkspaceList.tempDir(anotherDir.child("insideDir")); + anotherTmp.mkdirs(); + + ws.child("anotherDir/one.txt").touch(0); + ws.child("anotherDir/insideDir/two.txt").touch(0); + mainTmp.child("three.txt").touch(0); + anotherTmp.child("four.txt").touch(0); + return true; + } + }); + assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); + + JenkinsRule.WebClient wc = j.createWebClient(); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); + + Page zipPage = wc.goTo("job/" + p.getName() + "/ws/**/*.txt/*zip*/glob.zip", null); + assertThat(zipPage.getWebResponse().getStatusCode(), equalTo(HttpURLConnection.HTTP_OK)); + + List entryNames = getListOfEntriesInDownloadedZip((UnexpectedPage) zipPage); + assertThat(entryNames, hasSize(2)); + assertThat(entryNames, containsInAnyOrder( + "anotherDir/one.txt", + "anotherDir/insideDir/two.txt" + )); + } + @Test public void canViewRelativePath() throws Exception { File testFile = new File(j.jenkins.getRootDir(), "userContent/test.txt"); diff --git a/test/src/test/java/hudson/model/ExecutorSEC2120Test.java b/test/src/test/java/hudson/model/ExecutorSEC2120Test.java deleted file mode 100644 index 2874129a6180..000000000000 --- a/test/src/test/java/hudson/model/ExecutorSEC2120Test.java +++ /dev/null @@ -1,86 +0,0 @@ -package hudson.model; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import hudson.Launcher; -import hudson.remoting.VirtualChannel; -import hudson.slaves.DumbSlave; -import hudson.slaves.OfflineCause; -import hudson.tasks.Builder; -import hudson.util.OneShotEvent; -import java.io.IOException; -import java.util.concurrent.Future; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.TestExtension; - -public class ExecutorSEC2120Test { - - @Rule - public JenkinsRule j = new JenkinsRule(); - - @Test - public void disconnectCause_WithoutTrace() throws Exception { - DumbSlave slave = j.createOnlineSlave(); - FreeStyleProject p = j.createFreeStyleProject(); - p.setAssignedNode(slave); - - Future r = startBlockingBuild(p); - - String message = "It went away"; - p.getLastBuild().getBuiltOn().toComputer().disconnect( - new OfflineCause.ChannelTermination(new RuntimeException(message)) - ); - - OfflineCause offlineCause = p.getLastBuild().getBuiltOn().toComputer().getOfflineCause(); - assertThat(offlineCause.toString(), not(containsString(message))); - } - - /** - * Start a project with an infinite build step - * - * @param project {@link FreeStyleProject} to start - * @return A {@link Future} object represents the started build - * @throws Exception if somethink wrong happened - */ - public static Future startBlockingBuild(FreeStyleProject project) throws Exception { - final OneShotEvent e = new OneShotEvent(); - - project.getBuildersList().add(new BlockingBuilder(e)); - - Future r = project.scheduleBuild2(0); - e.block(); // wait until we are safe to interrupt - assertTrue(project.getLastBuild().isBuilding()); - - return r; - } - - private static final class BlockingBuilder extends Builder { - private final OneShotEvent e; - - private BlockingBuilder(OneShotEvent e) { - this.e = e; - } - - @Override - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - VirtualChannel channel = launcher.getChannel(); - Node node = build.getBuiltOn(); - - e.signal(); // we are safe to be interrupted - for (;;) { - // Keep using the channel - channel.call(node.getClockDifferenceCallable()); - Thread.sleep(100); - } - } - - @TestExtension - public static class DescriptorImpl extends Descriptor {} - } - -} diff --git a/test/src/test/java/hudson/model/ExecutorTest.java b/test/src/test/java/hudson/model/ExecutorTest.java index ec84a5aaabab..0f83110f52e9 100644 --- a/test/src/test/java/hudson/model/ExecutorTest.java +++ b/test/src/test/java/hudson/model/ExecutorTest.java @@ -21,6 +21,7 @@ import jenkins.model.CauseOfInterruption.UserInterruption; import jenkins.model.InterruptedBuildAction; import jenkins.model.Jenkins; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; @@ -152,6 +153,24 @@ public void apiPermissions() throws Exception { assertThat(api, allOf(containsString("public-project"), not(containsString("secret-project")))); } + @Test + @Issue("SECURITY-2120") + public void disconnectCause_WithoutTrace() throws Exception { + DumbSlave slave = j.createOnlineSlave(); + FreeStyleProject p = j.createFreeStyleProject(); + p.setAssignedNode(slave); + + Future r = startBlockingBuild(p); + + String message = "It went away"; + p.getLastBuild().getBuiltOn().toComputer().disconnect( + new OfflineCause.ChannelTermination(new RuntimeException(message)) + ); + + OfflineCause offlineCause = p.getLastBuild().getBuiltOn().toComputer().getOfflineCause(); + Assert.assertThat(offlineCause.toString(), not(containsString(message))); + } + /** * Start a project with an infinite build step * diff --git a/test/src/test/java/hudson/search/SearchSecurity2399Test.java b/test/src/test/java/hudson/search/SearchSecurity2399Test.java deleted file mode 100644 index 56eb7e1a8336..000000000000 --- a/test/src/test/java/hudson/search/SearchSecurity2399Test.java +++ /dev/null @@ -1,58 +0,0 @@ -package hudson.search; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import com.gargoylesoftware.htmlunit.Page; -import java.lang.reflect.Field; -import net.sf.json.JSONArray; -import net.sf.json.JSONObject; -import net.sf.json.JSONSerializer; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.JenkinsRule; - -public class SearchSecurity2399Test { - - @Rule - public JenkinsRule j = new JenkinsRule(); - - @Issue("SECURITY-2399") - @Test - public void testSearchBound() throws Exception { - - final String projectName1 = "projectName1"; - final String projectName2 = "projectName2"; - final String projectName3 = "projectName3"; - - j.createFreeStyleProject(projectName1); - j.createFreeStyleProject(projectName2); - j.createFreeStyleProject(projectName3); - - final JenkinsRule.WebClient wc = j.createWebClient(); - - Page result = wc.goTo("search/suggest?query=projectName", "application/json"); - JSONArray suggestions = getSearchJson(result); - assertEquals(3, suggestions.size()); - - Field declaredField = Search.class.getDeclaredField("MAX_SEARCH_SIZE"); - declaredField.setAccessible(true); - declaredField.set(null, 2); - - Page maximizedResult = wc.goTo("search/suggest?query=projectName", "application/json"); - JSONArray maximizedSuggestions = getSearchJson(maximizedResult); - assertEquals(2, maximizedSuggestions.size()); - } - - private JSONArray getSearchJson(Page page) { - assertNotNull(page); - j.assertGoodStatus(page); - String content = page.getWebResponse().getContentAsString(); - JSONObject jsonContent = (JSONObject) JSONSerializer.toJSON(content); - assertNotNull(jsonContent); - JSONArray jsonArray = jsonContent.getJSONArray("suggestions"); - assertNotNull(jsonArray); - return jsonArray; - } -} diff --git a/test/src/test/java/hudson/search/SearchTest.java b/test/src/test/java/hudson/search/SearchTest.java index c466530c4c5c..d67b864591fe 100644 --- a/test/src/test/java/hudson/search/SearchTest.java +++ b/test/src/test/java/hudson/search/SearchTest.java @@ -39,6 +39,7 @@ import hudson.security.ACLContext; import hudson.security.GlobalMatrixAuthorizationStrategy; import java.io.IOException; +import java.lang.reflect.Field; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; @@ -477,4 +478,42 @@ public void testProjectNameInAListView() throws Exception { URL resultUrl = searchResult.getUrl(); assertEquals(j.getInstance().getRootUrl() + freeStyleProject.getUrl(), resultUrl.toString()); } + + @Test + @Issue("SECURITY-2399") + public void testSearchBound() throws Exception { + + final String projectName1 = "projectName1"; + final String projectName2 = "projectName2"; + final String projectName3 = "projectName3"; + + j.createFreeStyleProject(projectName1); + j.createFreeStyleProject(projectName2); + j.createFreeStyleProject(projectName3); + + final JenkinsRule.WebClient wc = j.createWebClient(); + + Page result = wc.goTo("search/suggest?query=projectName", "application/json"); + JSONArray suggestions = getSearchJson(result); + assertEquals(3, suggestions.size()); + + Field declaredField = Search.class.getDeclaredField("MAX_SEARCH_SIZE"); + declaredField.setAccessible(true); + declaredField.set(null, 2); + + Page maximizedResult = wc.goTo("search/suggest?query=projectName", "application/json"); + JSONArray maximizedSuggestions = getSearchJson(maximizedResult); + assertEquals(2, maximizedSuggestions.size()); + } + + private JSONArray getSearchJson(Page page) { + assertNotNull(page); + j.assertGoodStatus(page); + String content = page.getWebResponse().getContentAsString(); + JSONObject jsonContent = (JSONObject) JSONSerializer.toJSON(content); + assertNotNull(jsonContent); + JSONArray jsonArray = jsonContent.getJSONArray("suggestions"); + assertNotNull(jsonArray); + return jsonArray; + } } diff --git a/test/src/test/resources/hudson/PluginManagerSecurity3037Test/update-center.json b/test/src/test/resources/plugins/security3037-update-center.json similarity index 100% rename from test/src/test/resources/hudson/PluginManagerSecurity3037Test/update-center.json rename to test/src/test/resources/plugins/security3037-update-center.json