Java tutorial
/* * Copyright 2019 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.thoughtworks.go.server.web; import com.thoughtworks.go.agent.common.ssl.GoAgentServerHttpClientBuilder; import com.thoughtworks.go.domain.ServerSiteUrlConfig; import com.thoughtworks.go.server.service.support.toggle.FeatureToggleService; import com.thoughtworks.go.server.service.support.toggle.Toggles; import com.thoughtworks.go.server.util.HttpTestUtil; import com.thoughtworks.go.server.util.ServletHelper; import com.thoughtworks.go.util.SslVerificationMode; import com.thoughtworks.go.util.SystemEnvironment; import org.apache.commons.io.IOUtils; import org.apache.http.client.methods.*; import org.apache.http.impl.client.CloseableHttpClient; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppContext; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.experimental.theories.DataPoint; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; import org.springframework.web.context.WebApplicationContext; import org.tuckey.web.filters.urlrewrite.UrlRewriteFilter; import javax.servlet.DispatcherType; import java.io.File; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.EnumSet; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(Theories.class) public class UrlRewriterIntegrationTest { private static final String IP_1 = "127.1.1.1"; private static final String IP_2 = "127.2.2.2"; private static final int HTTP = 5197; private static final int HTTPS = 9071; private static final String HTTP_URL = "http://" + IP_1 + ":" + HTTP; private static final String HTTPS_URL = "https://" + IP_1 + ":" + HTTPS; private static final String HTTP_SITE_URL = "http://" + IP_2 + ":" + HTTP; private static final String HTTPS_SITE_URL = "https://" + IP_2 + ":" + HTTPS; private static HttpTestUtil httpUtil; private static WebApplicationContext wac; private static boolean useConfiguredUrls; private static String originalSslPort; @DataPoint public static ResponseAssertion NO_REWRITE = new ResponseAssertion(HTTP_URL + "/go/quux?hello=world", HTTP_URL + "/go/quux?hello=world"); @DataPoint public static ResponseAssertion NO_REWRITE_SSL = new ResponseAssertion(HTTPS_URL + "/go/quux?hello=world", HTTPS_URL + "/go/quux?hello=world"); @DataPoint public static ResponseAssertion RAILS_BOUND = new ResponseAssertion(HTTP_URL + "/go/agents/foo?hello=world", HTTP_URL + "/go/rails/agents/foo?hello=world"); @DataPoint public static ResponseAssertion RAILS_BOUND_SSL = new ResponseAssertion( HTTPS_URL + "/go/agents/foo?hello=world", HTTPS_URL + "/go/rails/agents/foo?hello=world"); @DataPoint public static ResponseAssertion PIPELINE_GROUPS_LISTING = new ResponseAssertion( HTTP_URL + "/go/admin/pipelines?foo=bar&baz=quux", HTTP_URL + "/go/rails/admin/pipelines?foo=bar&baz=quux", true); @DataPoint public static ResponseAssertion PIPELINE_GROUP_EDIT = new ResponseAssertion( HTTP_URL + "/go/admin/pipeline_group/group.name?foo=bar&baz=quux", HTTP_URL + "/go/rails/admin/pipeline_group/group.name?foo=bar&baz=quux", true); @DataPoint public static ResponseAssertion PIPELINE_GROUP_CREATE = new ResponseAssertion( HTTP_URL + "/go/admin/pipeline_group", HTTP_URL + "/go/rails/admin/pipeline_group", true); @DataPoint public static ResponseAssertion TEMPLATES_LISTING = new ResponseAssertion( HTTP_URL + "/go/admin/templates?foo=bar&baz=quux", HTTP_URL + "/go/rails/admin/templates?foo=bar&baz=quux", true); @DataPoint public static ResponseAssertion CONFIG_VIEW = new ResponseAssertion( HTTP_URL + "/go/config_view/templates/template_name", HTTP_URL + "/go/rails/config_view/templates/template_name"); @DataPoint public static ResponseAssertion PIPELINE_NEW = new ResponseAssertion(HTTP_URL + "/go/admin/pipeline/new", HTTP_URL + "/go/rails/admin/pipeline/new", true); @DataPoint public static ResponseAssertion PIPELINE_CREATE = new ResponseAssertion(HTTP_URL + "/go/admin/pipelines", HTTP_URL + "/go/rails/admin/pipelines", METHOD.POST); @DataPoint public static ResponseAssertion SERVER_BACKUP = new ResponseAssertion(HTTP_URL + "/go/admin/backup", HTTP_URL + "/go/spark/admin/backup", true); @DataPoint public static ResponseAssertion STATIC_PAGES = new ResponseAssertion(HTTP_URL + "/go/static/foo.html?bar=baz", HTTP_URL + "/go/static/foo.html?bar=baz", true); @DataPoint public static final ResponseAssertion CONFIG_FILE_XML = new ResponseAssertion( HTTP_URL + "/go/admin/configuration/file.xml", HTTP_URL + "/go/admin/restful/configuration/file/GET/xml"); @DataPoint public static final ResponseAssertion CONFIG_API_FOR_CURRENT = new ResponseAssertion( HTTP_URL + "/go/api/admin/config.xml", HTTP_URL + "/go/admin/restful/configuration/file/GET/xml?version=current"); @DataPoint public static final ResponseAssertion CONFIG_API_FOR_HISTORICAL = new ResponseAssertion( HTTP_URL + "/go/api/admin/config/some-md5.xml", HTTP_URL + "/go/admin/restful/configuration/file/GET/historical-xml?version=some-md5"); @DataPoint public static ResponseAssertion IMAGES_WHILE_BACKUP_IS_IN_PROGRESS = new ResponseAssertion( HTTP_URL + "/go/images/foo.png", HTTP_URL + "/go/images/foo.png"); @DataPoint public static ResponseAssertion JAVASCRIPT_WHILE_BACKUP_IS_IN_PROGRESS = new ResponseAssertion( HTTP_URL + "/go/javascripts/foo.js", HTTP_URL + "/go/javascripts/foo.js"); @DataPoint public static ResponseAssertion COMPRESSED_JAVASCRIPT_WHILE_BACKUP_IS_IN_PROGRESS = new ResponseAssertion( HTTP_URL + "/go/compressed/all.js", HTTP_URL + "/go/compressed/all.js"); @DataPoint public static ResponseAssertion STYLESHEETS_WHILE_BACKUP_IS_IN_PROGRESS = new ResponseAssertion( HTTP_URL + "/go/stylesheets/foo.css", HTTP_URL + "/go/stylesheets/foo.css", true); @DataPoint public static ResponseAssertion TASKS_LOOKUP_LISTING = new ResponseAssertion(HTTP_URL + "/go/admin/commands", HTTP_URL + "/go/rails/admin/commands", true); @DataPoint public static ResponseAssertion TASKS_LOOKUP_SHOW = new ResponseAssertion(HTTP_URL + "/go/admin/commands/show", HTTP_URL + "/go/rails/admin/commands/show", true); @DataPoint public static ResponseAssertion PLUGINS_LISTING = new ResponseAssertion(HTTP_URL + "/go/admin/plugins", HTTP_URL + "/go/spark/admin/plugins", true); @DataPoint public static ResponseAssertion PACKAGE_REPOSITORIES_LISTING = new ResponseAssertion( HTTP_URL + "/go/admin/package_repositories", HTTP_URL + "/go/rails/admin/package_repositories", true); @DataPoint public static ResponseAssertion PACKAGE_DEFINITIONS = new ResponseAssertion( HTTP_URL + "/go/admin/package_definitions", HTTP_URL + "/go/rails/admin/package_definitions", true); @DataPoint public static ResponseAssertion PLUGGABLE_SCM = new ResponseAssertion( HTTP_URL + "/go/admin/materials/pluggable_scm/check_connection/plugin_id", HTTP_URL + "/go/rails/admin/materials/pluggable_scm/check_connection/plugin_id", true); @DataPoint public static ResponseAssertion CONFIG_CHANGE = new ResponseAssertion( HTTP_URL + "/go/admin/config_change/md5_value", HTTP_URL + "/go/rails/admin/config_change/md5_value", true); @DataPoint public static ResponseAssertion CONFIG_XML_VIEW = new ResponseAssertion(HTTP_URL + "/go/admin/config_xml", HTTP_URL + "/go/rails/admin/config_xml", METHOD.GET, true); @DataPoint public static ResponseAssertion CONFIG_XML_EDIT = new ResponseAssertion(HTTP_URL + "/go/admin/config_xml/edit", HTTP_URL + "/go/rails/admin/config_xml/edit", METHOD.GET, true); @DataPoint public static ResponseAssertion ARTIFACT_API_HTML_LISTING = new ResponseAssertion( HTTP_URL + "/go/files/pipeline/1/stage/1/job.html", HTTP_URL + "/go/repository/restful/artifact/GET/html?pipelineName=pipeline&pipelineCounter=1&stageName=stage&stageCounter=1&buildName=job&filePath=", true); @DataPoint public static ResponseAssertion ARTIFACT_API_HTML_LISTING_FILENAME = new ResponseAssertion( HTTP_URL + "/go/files/pipeline/1/stage/1/target/abc%2Bfoo.txt", HTTP_URL + "/go/repository/restful/artifact/GET/?pipelineName=pipeline&pipelineCounter=1&stageName=stage&stageCounter=1&buildName=target&filePath=abc%2Bfoo.txt", true); @DataPoint public static ResponseAssertion ARTIFACT_API_JSON_LISTING = new ResponseAssertion( HTTP_URL + "/go/files/pipeline/1/stage/1/job.json", HTTP_URL + "/go/repository/restful/artifact/GET/json?pipelineName=pipeline&pipelineCounter=1&stageName=stage&stageCounter=1&buildName=job&filePath=", true); @DataPoint public static ResponseAssertion ARTIFACT_API_GET_FILE = new ResponseAssertion( HTTP_URL + "/go/files/pipeline/1/stage/1/job//tmp/file", HTTP_URL + "/go/repository/restful/artifact/GET/?pipelineName=pipeline&pipelineCounter=1&stageName=stage&stageCounter=1&buildName=job&filePath=%2Ftmp%2Ffile", true); @DataPoint public static ResponseAssertion ARTIFACT_API_PUSH_FILE = new ResponseAssertion( HTTP_URL + "/go/files/pipeline/1/stage/1/job//tmp/file", HTTP_URL + "/go/repository/restful/artifact/POST/?pipelineName=pipeline&pipelineCounter=1&stageName=stage&stageCounter=1&buildName=job&filePath=%2Ftmp%2Ffile", METHOD.POST, true); @DataPoint public static ResponseAssertion ARTIFACT_API_CHANGE_FILE = new ResponseAssertion( HTTP_URL + "/go/files/pipeline/1/stage/1/job/file", HTTP_URL + "/go/repository/restful/artifact/PUT/?pipelineName=pipeline&pipelineCounter=1&stageName=stage&stageCounter=1&buildName=job&filePath=file", METHOD.PUT, true); @DataPoint public static ResponseAssertion PIPELINE_DASHBOARD_JSON = new ResponseAssertion(HTTP_URL + "/go/pipelines.json", HTTP_URL + "/go/rails/pipelines.json", METHOD.GET); @DataPoint public static ResponseAssertion MATERIALS_VALUE_STREAM_MAP = new ResponseAssertion( HTTP_URL + "/go/materials/value_stream_map/fingerprint/revision", HTTP_URL + "/go/rails/materials/value_stream_map/fingerprint/revision", METHOD.GET); @DataPoint public static ResponseAssertion DATA_SHARING_SETTINGS = new ResponseAssertion( HTTP_URL + "/go/api/data_sharing/settings", HTTP_URL + "/go/spark/api/data_sharing/settings", true); @DataPoint public static ResponseAssertion DATA_SHARING_USAGE_DATA = new ResponseAssertion( HTTP_URL + "/go/api/internal/data_sharing/usagedata", HTTP_URL + "/go/spark/api/internal/data_sharing/usagedata", true); @DataPoint public static ResponseAssertion DATA_SHARING_REPORTING = new ResponseAssertion( HTTP_URL + "/go/api/internal/data_sharing/reporting", HTTP_URL + "/go/spark/api/internal/data_sharing/reporting", true); @DataPoint public static ResponseAssertion LANDING_PAGE_SLASH = new ResponseAssertion(HTTP_URL + "/go/", HTTP_URL + "/go/spark/dashboard", true); @DataPoint public static ResponseAssertion LANDING_PAGE_HOME = new ResponseAssertion(HTTP_URL + "/go/home", HTTP_URL + "/go/spark/dashboard", true); @BeforeClass public static void beforeClass() throws Exception { ServletHelper.init(); httpUtil = new HttpTestUtil(new HttpTestUtil.ContextCustomizer() { public void customize(WebAppContext ctx) throws Exception { wac = mock(WebApplicationContext.class); ctx.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); URL resource = getClass().getClassLoader().getResource("WEB-INF/urlrewrite.xml"); if (resource == null) { throw new RuntimeException("Cannot load WEB-INF/urlrewrite.xml"); } ctx.setBaseResource(Resource.newResource(new File(resource.getFile()).getParent())); ctx.addFilter(UrlRewriteFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)) .setInitParameter("confPath", "/urlrewrite.xml"); ctx.addServlet(HttpTestUtil.EchoServlet.class, "/*"); } }); httpUtil.httpConnector(HTTP); httpUtil.httpsConnector(HTTPS); when(wac.getBean("serverConfigService")).thenReturn(new BaseUrlProvider() { public boolean hasAnyUrlConfigured() { return useConfiguredUrls; } public String siteUrlFor(String url, boolean forceSsl) throws URISyntaxException { ServerSiteUrlConfig siteUrl = forceSsl ? new ServerSiteUrlConfig(HTTPS_SITE_URL) : new ServerSiteUrlConfig(HTTP_SITE_URL); return siteUrl.siteUrlFor(url); } }); httpUtil.start(); originalSslPort = System.getProperty(SystemEnvironment.CRUISE_SERVER_SSL_PORT); System.setProperty(SystemEnvironment.CRUISE_SERVER_SSL_PORT, String.valueOf(HTTPS)); FeatureToggleService featureToggleService = mock(FeatureToggleService.class); when(featureToggleService.isToggleOn(anyString())).thenReturn(true); Toggles.initializeWith(featureToggleService); } @AfterClass public static void afterClass() { if (originalSslPort == null) { System.getProperties().remove(SystemEnvironment.CRUISE_SERVER_SSL_PORT); } else { System.setProperty(SystemEnvironment.CRUISE_SERVER_SSL_PORT, originalSslPort); } httpUtil.stop(); } enum METHOD { GET, POST, PUT } private static class ResponseAssertion { private final String requestedUrl; private final String servedUrl; private boolean useConfiguredUrls = false; private int responseCode = 200; private METHOD method; ResponseAssertion(String requestedUrl, String servedUrl, METHOD method) { this.requestedUrl = requestedUrl; this.servedUrl = servedUrl; this.method = method; } ResponseAssertion(String requestedUrl, String servedUrl) { this(requestedUrl, servedUrl, METHOD.GET); } ResponseAssertion(String requestedUrl, String servedUrl, boolean useConfiguredUrls) { this(requestedUrl, servedUrl); this.useConfiguredUrls = useConfiguredUrls; } ResponseAssertion(String requestedUrl, String servedUrl, METHOD method, boolean useConfiguredUrls) { this(requestedUrl, servedUrl, method); this.useConfiguredUrls = useConfiguredUrls; } } @Theory public void shouldRewrite(final ResponseAssertion assertion) throws Exception { useConfiguredUrls = assertion.useConfiguredUrls; GoAgentServerHttpClientBuilder builder = new GoAgentServerHttpClientBuilder(null, SslVerificationMode.NONE); try (CloseableHttpClient httpClient = builder.build()) { HttpRequestBase httpMethod; if (assertion.method == METHOD.GET) { httpMethod = new HttpGet(assertion.requestedUrl); } else if (assertion.method == METHOD.POST) { httpMethod = new HttpPost(assertion.requestedUrl); } else if (assertion.method == METHOD.PUT) { httpMethod = new HttpPut(assertion.requestedUrl); } else { throw new RuntimeException("Method has to be one of GET, POST and PUT. Was: " + assertion.method); } try (CloseableHttpResponse response = httpClient.execute(httpMethod)) { assertThat("status code match failed", response.getStatusLine().getStatusCode(), is(assertion.responseCode)); assertThat("handler url match failed", IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8), is(assertion.servedUrl)); } } } }