diff --git a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java index 54d75bf66cf13be6a5e25f6f1063ad53ccb888ba..906431328cd84a69752d6b08a1511da61701d683 100644 --- a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java +++ b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java @@ -5,18 +5,45 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.DownloadedContent; +import com.gargoylesoftware.htmlunit.HttpWebConnection; +import com.gargoylesoftware.htmlunit.WebConnection; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.WebResponse; +import com.gargoylesoftware.htmlunit.WebResponseData; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.util.NameValuePair; +import com.gargoylesoftware.htmlunit.util.UrlUtils; import hudson.Util; import hudson.model.User; import jenkins.model.Jenkins; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScheme; import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule.WebClient; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Callable; /** @@ -47,25 +74,10 @@ public class ApiTokenPropertyTest { assertSame(t, u.getProperty(ApiTokenProperty.class)); WebClient wc = j.createWebClient(); - wc.getCredentialsProvider().setCredentials( - new AuthScope("localhost", AuthScope.ANY_PORT), - new UsernamePasswordCredentials("foo", token) - ); -// TODO: Find a way to do this. -// May need to upgrade to httpclient 4.3+ by adding a org.apache.httpcomponents:httpclient exclusion on the maven-plugin -// See http://stackoverflow.com/questions/2014700/preemptive-basic-authentication-with-apache-httpclient-4 etc -// wc.setWebConnection(new HttpWebConnection(wc) { -// @Override -// protected HttpClient getHttpClient() { -// HttpClient c = super.getHttpClient(); -// c.getParams().setAuthenticationPreemptive(true); -// c.getState().setCredentials(new AuthScope("localhost", AuthScope.ANY_PORT, AuthScope.ANY_REALM), new UsernamePasswordCredentials("foo", token)); -// return c; -// } -// }); + configureWebConnection(wc, token); // test the authentication - assertEquals(u,wc.executeOnServer(new Callable() { + assertEquals(u, wc.executeOnServer(new Callable() { public User call() throws Exception { return User.current(); } @@ -94,4 +106,71 @@ public class ApiTokenPropertyTest { u.addProperty(t); assertTrue(t.getApiToken().equals(Util.getDigestOf(historicalInitialValue+"somethingElse"))); } + + private void configureWebConnection(final WebClient wc, final String token) throws IOException { + // See https://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html + final UsernamePasswordCredentials fooCreds = new UsernamePasswordCredentials("foo", token); + + URL hostUrl = j.getURL(); + final HttpHost targetHost = new HttpHost(hostUrl.getHost(), hostUrl.getPort(), hostUrl.getProtocol()); + CredentialsProvider credsProvider = new BasicCredentialsProvider() { + @Override + public Credentials getCredentials(AuthScope authscope) { + return fooCreds; + } + }; + credsProvider.setCredentials( + new AuthScope("localhost", AuthScope.ANY_PORT, AuthScope.ANY_REALM), + fooCreds); + + // Create AuthCache instance + AuthCache authCache = new BasicAuthCache(); + // Generate BASIC scheme object and add it to the local auth cache + AuthScheme authScheme = new BasicScheme(); + authCache.put(targetHost, authScheme); + + // Add AuthCache to the execution context + final HttpClientContext context = HttpClientContext.create(); + context.setCredentialsProvider(credsProvider); + context.setAuthCache(authCache); + + wc.setCredentialsProvider(credsProvider); + + // Need to create our own WebConnection that gives us control of HttpClient execution, + // allowing us to pass our own HttpClientContext etc. HttpWebConnection has its own + // private HttpClientContext instance, which means we can't authenticate properly. + wc.setWebConnection(new WebConnection() { + @Override + public WebResponse getResponse(WebRequest request) throws IOException { + try { + long startTime = System.currentTimeMillis(); + + HttpClientBuilder builder = HttpClientBuilder.create(); + CloseableHttpClient httpClient = builder.build(); + URL url = UrlUtils.encodeUrl(request.getUrl(), false, request.getCharset()); + HttpGet method = new HttpGet(url.toURI()); + + CloseableHttpResponse response = httpClient.execute(targetHost, method, context); + + HttpEntity httpEntity = response.getEntity(); + DownloadedContent responseBody = HttpWebConnection.downloadContent(httpEntity.getContent(), wc.getOptions().getMaxInMemory()); + + String statusMessage = response.getStatusLine().getReasonPhrase(); + if (statusMessage == null) { + statusMessage = "Unknown status message"; + } + int statusCode = response.getStatusLine().getStatusCode(); + List headers = new ArrayList<>(); + for (final Header header : response.getAllHeaders()) { + headers.add(new NameValuePair(header.getName(), header.getValue())); + } + + WebResponseData responseData = new WebResponseData(responseBody, statusCode, statusMessage, headers); + return new WebResponse(responseData, request, (System.currentTimeMillis() - startTime)); + } catch (Exception e) { + throw new AssertionError("Failed to execute WebRequest.", e); + } + } + }); + } }