| author | Steffen Pingel | 2012-01-17 18:51:38 (EST) |
|---|---|---|
| committer | Steffen Pingel | 2012-01-17 18:51:38 (EST) |
| commit | bba2de5766319ad8697bef544e49145dbf9bcd60 (patch) (side-by-side diff) | |
| tree | 78a25fee83b52240c9d7b655998c146e0bf92396 | |
| parent | 6eba6ca65b76ed6589cc2f81c103d17e36fc055f (diff) | |
| download | org.eclipse.mylyn.commons-bba2de5766319ad8697bef544e49145dbf9bcd60.zip org.eclipse.mylyn.commons-bba2de5766319ad8697bef544e49145dbf9bcd60.tar.gz org.eclipse.mylyn.commons-bba2de5766319ad8697bef544e49145dbf9bcd60.tar.bz2 | |
NEW - bug 368777: [api] support pre-emptive authentication in
CommonHttpClient
https://bugs.eclipse.org/bugs/show_bug.cgi?id=368777
Change-Id: I1e0b2f0d8cf864703b650b64217683da7d676919
6 files changed, 151 insertions, 1 deletions
diff --git a/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/operations/IOperationMonitor.java b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/operations/IOperationMonitor.java index 2b869a2..b563cc1 100644 --- a/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/operations/IOperationMonitor.java +++ b/org.eclipse.mylyn.commons.core/src/org/eclipse/mylyn/commons/core/operations/IOperationMonitor.java @@ -18,6 +18,7 @@ import org.eclipse.core.runtime.IProgressMonitorWithBlocking; * @noimplement This interface is not intended to be implemented by clients. * @noextend This interface is not intended to be extended by clients. * @since 3.7 + * @see OperationUtil */ public interface IOperationMonitor extends IProgressMonitorWithBlocking { diff --git a/org.eclipse.mylyn.commons.repositories.http.core/META-INF/MANIFEST.MF b/org.eclipse.mylyn.commons.repositories.http.core/META-INF/MANIFEST.MF index 111a796..1c91a6b 100644 --- a/org.eclipse.mylyn.commons.repositories.http.core/META-INF/MANIFEST.MF +++ b/org.eclipse.mylyn.commons.repositories.http.core/META-INF/MANIFEST.MF @@ -18,6 +18,7 @@ Import-Package: org.apache.commons.logging;version="[1.0.4,2.0.0)", org.apache.http.impl;version="4.1.0", org.apache.http.auth;version="4.1.0", org.apache.http.auth.params;version="4.1.0", + org.apache.http.impl.auth;version="4.1.0", org.apache.http.util;version="4.1.0", org.apache.http.client;version="4.1.0", org.apache.http.client.methods;version="4.1.0", diff --git a/org.eclipse.mylyn.commons.repositories.http.core/src/org/eclipse/mylyn/commons/repositories/http/core/CommonHttpClient.java b/org.eclipse.mylyn.commons.repositories.http.core/src/org/eclipse/mylyn/commons/repositories/http/core/CommonHttpClient.java index 38a85d7..c070178 100644 --- a/org.eclipse.mylyn.commons.repositories.http.core/src/org/eclipse/mylyn/commons/repositories/http/core/CommonHttpClient.java +++ b/org.eclipse.mylyn.commons.repositories.http.core/src/org/eclipse/mylyn/commons/repositories/http/core/CommonHttpClient.java @@ -15,13 +15,16 @@ import java.io.IOException; import javax.net.ssl.TrustManager; +import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.protocol.ClientContext; import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.AbstractHttpClient; +import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.SyncBasicHttpContext; @@ -44,6 +47,8 @@ import org.eclipse.mylyn.commons.repositories.core.auth.UserCredentials; */ public class CommonHttpClient { + private boolean preemptiveAuthenticationEnabled; + private boolean authenticated; private final SyncBasicHttpContext context; @@ -95,6 +100,10 @@ public class CommonHttpClient { return authenticated; } + public boolean isPreemptiveAuthenticationEnabled() { + return preemptiveAuthenticationEnabled; + } + public boolean needsAuthentication() { return !isAuthenticated() && getLocation().getCredentials(AuthenticationType.REPOSITORY, false) != null; } @@ -107,13 +116,31 @@ public class CommonHttpClient { this.httpAuthenticationType = httpAuthenticationType; } + public void setPreemptiveAuthenticationEnabled(boolean preemptiveAuthenticationEnabled) { + this.preemptiveAuthenticationEnabled = preemptiveAuthenticationEnabled; + } + private void prepareRequest(HttpRequestBase request, IOperationMonitor monitor) { UserCredentials httpCredentials = location.getCredentials(httpAuthenticationType); if (httpCredentials != null) { HttpUtil.configureAuthentication(getHttpClient(), location, httpCredentials); + + if (isPreemptiveAuthenticationEnabled()) { + // create or pre-populate auth cache + HttpHost host = HttpUtil.createHost(request); + Object authCache = context.getAttribute(ClientContext.AUTH_CACHE); + if (authCache == null) { + authCache = new BasicAuthCache(); + context.setAttribute(ClientContext.AUTH_CACHE, authCache); + } + if (authCache instanceof BasicAuthCache) { + if (((BasicAuthCache) authCache).get(host) == null) { + ((BasicAuthCache) authCache).put(host, new BasicScheme()); + } + } + } } HttpUtil.configureProxy(getHttpClient(), location); - HttpUtil.configureProxy(getHttpClient(), location); CertificateCredentials socketCredentials = location.getCredentials(AuthenticationType.CERTIFICATE); if (socketCredentials != null) { diff --git a/org.eclipse.mylyn.commons.repositories.http.core/src/org/eclipse/mylyn/commons/repositories/http/core/HttpRequestProcessor.java b/org.eclipse.mylyn.commons.repositories.http.core/src/org/eclipse/mylyn/commons/repositories/http/core/HttpRequestProcessor.java index ec27d8b..5e45e59 100644 --- a/org.eclipse.mylyn.commons.repositories.http.core/src/org/eclipse/mylyn/commons/repositories/http/core/HttpRequestProcessor.java +++ b/org.eclipse.mylyn.commons.repositories.http.core/src/org/eclipse/mylyn/commons/repositories/http/core/HttpRequestProcessor.java @@ -20,6 +20,14 @@ import org.eclipse.mylyn.commons.core.operations.IOperationMonitor; */ public abstract class HttpRequestProcessor<T> { + public static final HttpRequestProcessor<CommonHttpResponse> DEFAULT = new HttpRequestProcessor<CommonHttpResponse>() { + @Override + protected CommonHttpResponse doProcess(CommonHttpResponse response, IOperationMonitor monitor) + throws IOException { + return response; + } + }; + private final boolean autoRelease; public HttpRequestProcessor() { diff --git a/org.eclipse.mylyn.commons.repositories.http.tests/src/org/eclipse/mylyn/commons/repositories/http/tests/CommonHttpClientProxyTest.java b/org.eclipse.mylyn.commons.repositories.http.tests/src/org/eclipse/mylyn/commons/repositories/http/tests/CommonHttpClientProxyTest.java new file mode 100644 index 0000000..9500ee4 --- a/dev/null +++ b/org.eclipse.mylyn.commons.repositories.http.tests/src/org/eclipse/mylyn/commons/repositories/http/tests/CommonHttpClientProxyTest.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2004, 2010 Tasktop Technologies and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Tasktop Technologies - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.commons.repositories.http.tests; + +import static org.junit.Assert.assertEquals; + +import org.apache.http.HttpStatus; +import org.eclipse.mylyn.commons.repositories.core.RepositoryLocation; +import org.eclipse.mylyn.commons.repositories.core.auth.AuthenticationException; +import org.eclipse.mylyn.commons.repositories.core.auth.AuthenticationType; +import org.eclipse.mylyn.commons.repositories.core.auth.UserCredentials; +import org.eclipse.mylyn.commons.repositories.http.core.CommonHttpClient; +import org.eclipse.mylyn.commons.repositories.http.core.CommonHttpResponse; +import org.eclipse.mylyn.commons.repositories.http.core.HttpRequestProcessor; +import org.eclipse.mylyn.commons.sdk.util.TestProxy; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Steffen Pingel + */ +public class CommonHttpClientProxyTest { + + private TestProxy testProxy; + + public CommonHttpClientProxyTest() { + } + + @Before + public void setUp() throws Exception { + testProxy = new TestProxy(); + testProxy.startAndWait(); + } + + @After + public void tearDown() throws Exception { + testProxy.stop(); + } + + @Test + public void testExecuteGetNoPreemptiveAuth() throws Exception { + RepositoryLocation location = new RepositoryLocation(testProxy.getUrl()); + location.setCredentials(AuthenticationType.HTTP, new UserCredentials("user", "pass")); + CommonHttpClient client = new CommonHttpClient(location); + + testProxy.addResponse(TestProxy.OK); + CommonHttpResponse response = client.executeGet("/", null, HttpRequestProcessor.DEFAULT); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(null, testProxy.getRequest().getHeader("Authorization")); + } + + @Test(expected = AuthenticationException.class) + public void testExecuteGetAuthChallengeNoCredentials() throws Exception { + RepositoryLocation location = new RepositoryLocation(testProxy.getUrl()); + CommonHttpClient client = new CommonHttpClient(location); + + testProxy.addResponse(TestProxy.UNAUTHORIZED); + client.executeGet("/", null, HttpRequestProcessor.DEFAULT); + } + + @Test + public void testExecuteGetAuthChallenge() throws Exception { + RepositoryLocation location = new RepositoryLocation(testProxy.getUrl()); + location.setCredentials(AuthenticationType.HTTP, new UserCredentials("user", "pass")); + CommonHttpClient client = new CommonHttpClient(location); + + testProxy.addResponse(TestProxy.UNAUTHORIZED); + testProxy.addResponse(TestProxy.OK); + CommonHttpResponse response = client.executeGet("/", null, HttpRequestProcessor.DEFAULT); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals("Did not expect preemptive credentails", null, testProxy.getRequest().getHeader("Authorization")); + assertEquals("Expect credentails on challenge", "Authorization: Basic dXNlcjpwYXNz", testProxy.getRequest() + .getHeader("Authorization")); + } + + @Test + public void testExecuteGetPreemptiveAuth() throws Exception { + RepositoryLocation location = new RepositoryLocation(testProxy.getUrl()); + location.setCredentials(AuthenticationType.HTTP, new UserCredentials("user", "pass")); + CommonHttpClient client = new CommonHttpClient(location); + + client.setPreemptiveAuthenticationEnabled(true); + testProxy.addResponse(TestProxy.OK); + CommonHttpResponse response = client.executeGet("/", null, HttpRequestProcessor.DEFAULT); + assertEquals("Authorization: Basic dXNlcjpwYXNz", testProxy.getRequest().getHeader("Authorization")); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + // subsequent requests will have cached credentials + client.setPreemptiveAuthenticationEnabled(false); + testProxy.addResponse(TestProxy.OK); + response = client.executeGet("/", null, HttpRequestProcessor.DEFAULT); + assertEquals("Authorization: Basic dXNlcjpwYXNz", testProxy.getRequest().getHeader("Authorization")); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + } + +} diff --git a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/TestProxy.java b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/TestProxy.java index 336521d..ac8702e 100644 --- a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/TestProxy.java +++ b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/TestProxy.java @@ -112,6 +112,8 @@ public class TestProxy implements Runnable { public static final Message TIMEOUT = new Message("HTTP/1.1 200 OK"); + public static final Message UNAUTHORIZED = new Message("HTTP/1.1 401 Unauthorized"); + public static final Message SERVICE_UNVAILABLE = createEmptyMessage("HTTP/1.1 503 Service Unavailable"); static { @@ -119,6 +121,7 @@ public class TestProxy implements Runnable { OK.headers.add(HEADER_CONNECTION_CLOSE); SERVICE_UNVAILABLE.headers.add(HEADER_CONNECTION_CLOSE); TIMEOUT.headers.add("Content-Length: 500"); + UNAUTHORIZED.headers.add("WWW-Authenticate: Basic realm=\"Test\""); } private static Message createEmptyMessage(String status) { @@ -317,6 +320,10 @@ public class TestProxy implements Runnable { return serverSocket.getLocalPort(); } + public String getUrl() { + return "http://" + serverSocket.getInetAddress().getHostAddress() + ":" + serverSocket.getLocalPort(); + } + public void stop() { stopped = true; try { |

