diff options
author | spingel | 2008-10-13 08:36:36 +0000 |
---|---|---|
committer | spingel | 2008-10-13 08:36:36 +0000 |
commit | f543f0985301bbe1831a089a45a4bfcea4e65ff7 (patch) | |
tree | a29a14cabfd29d3a0addb81c018551c71cf1c036 /org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac | |
parent | d2b8cfa3e734b46ae99750bb0335b1d1cc5e05cf (diff) | |
download | org.eclipse.mylyn.tasks-f543f0985301bbe1831a089a45a4bfcea4e65ff7.tar.gz org.eclipse.mylyn.tasks-f543f0985301bbe1831a089a45a4bfcea4e65ff7.tar.xz org.eclipse.mylyn.tasks-f543f0985301bbe1831a089a45a4bfcea4e65ff7.zip |
NEW - bug 214341: Large XML-RPC requests fail when using digest authentication and tracd
https://bugs.eclipse.org/bugs/show_bug.cgi?id=214341
Diffstat (limited to 'org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac')
4 files changed, 131 insertions, 50 deletions
diff --git a/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/client/TracWebClient.java b/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/client/TracWebClient.java index faeffe1e0..c60f4e56c 100644 --- a/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/client/TracWebClient.java +++ b/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/client/TracWebClient.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2006, 2008 Steffen Pingel and others. + * Copyright (c) 2006, 2008 Steffen Pingel 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 @@ -126,8 +126,9 @@ public class TracWebClient extends AbstractTracClient { throw new TracLoginException(); } - // try standard basic/digest authentication first - AuthScope authScope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM); + // try standard basic/digest/ntlm authentication first + AuthScope authScope = new AuthScope(WebUtil.getHost(repositoryUrl), WebUtil.getPort(repositoryUrl), + null, AuthScope.ANY_SCHEME); httpClient.getState().setCredentials(authScope, WebUtil.getHttpClientCredentials(credentials, WebUtil.getHost(repositoryUrl))); @@ -135,14 +136,12 @@ public class TracWebClient extends AbstractTracClient { method.setFollowRedirects(false); int code; try { - httpClient.getParams().setAuthenticationPreemptive(true); code = WebUtil.execute(httpClient, hostConfiguration, method, monitor); if (needsReauthentication(code, monitor)) { continue; } } finally { method.releaseConnection(); - httpClient.getParams().setAuthenticationPreemptive(false); } // the expected return code is a redirect, anything else is suspicious diff --git a/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/client/TracXmlRpcClient.java b/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/client/TracXmlRpcClient.java index 01b1e2afd..68f9e96de 100644 --- a/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/client/TracXmlRpcClient.java +++ b/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/client/TracXmlRpcClient.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2006, 2008 Steffen Pingel and others. + * Copyright (c) 2006, 2008 Steffen Pingel 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 @@ -27,9 +27,18 @@ import java.util.Map; import java.util.Set; import java.util.TimeZone; +import org.apache.commons.httpclient.Credentials; +import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.auth.AuthScope; +import org.apache.commons.httpclient.auth.AuthenticationException; +import org.apache.commons.httpclient.auth.DigestScheme; +import org.apache.commons.httpclient.auth.MalformedChallengeException; +import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; @@ -62,6 +71,7 @@ import org.eclipse.mylyn.internal.trac.core.model.TracVersion; import org.eclipse.mylyn.internal.trac.core.model.TracWikiPage; import org.eclipse.mylyn.internal.trac.core.model.TracWikiPageInfo; import org.eclipse.mylyn.internal.trac.core.model.TracTicket.Key; +import org.eclipse.mylyn.internal.trac.core.util.HttpRequestInterceptor; import org.eclipse.mylyn.internal.trac.core.util.TracHttpClientTransportFactory; import org.eclipse.mylyn.internal.trac.core.util.TracUtil; import org.eclipse.mylyn.internal.trac.core.util.TracXmlRpcClientRequest; @@ -124,7 +134,7 @@ public class TracXmlRpcClient extends AbstractTracClient implements ITracWikiCli throw e; } - factory.setCookies(httpClient.getState().getCookies()); + // the authentication information is available through the shared state in httpClient } // second attempt @@ -138,8 +148,10 @@ public class TracXmlRpcClient extends AbstractTracClient implements ITracWikiCli return xmlrpc.execute(request); } catch (TracHttpException e) { if (e.code == HttpStatus.SC_UNAUTHORIZED) { + digestScheme = null; throw new TracLoginException(); } else if (e.code == HttpStatus.SC_FORBIDDEN) { + digestScheme = null; throw new TracPermissionDeniedException(); } else if (e.code == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) { throw new TracProxyAuthenticationException(); @@ -193,9 +205,17 @@ public class TracXmlRpcClient extends AbstractTracClient implements ITracWikiCli private final HttpClient httpClient; + private boolean probed; + + private volatile DigestScheme digestScheme; + + private final AuthScope authScope; + public TracXmlRpcClient(AbstractWebLocation location, Version version) { super(location, version); this.httpClient = createHttpClient(); + this.authScope = new AuthScope(WebUtil.getHost(repositoryUrl), WebUtil.getPort(repositoryUrl), null, + AuthScope.ANY_SCHEME); } public synchronized XmlRpcClient getClient() throws TracException { @@ -212,19 +232,33 @@ public class TracXmlRpcClient extends AbstractTracClient implements ITracWikiCli factory = new TracHttpClientTransportFactory(xmlrpc, httpClient); factory.setLocation(location); + factory.setInterceptor(new HttpRequestInterceptor() { + public void process(HttpMethod method) { + DigestScheme scheme = digestScheme; + if (scheme != null) { + Credentials creds = httpClient.getState().getCredentials(authScope); + if (creds != null) { + try { + method.addRequestHeader("Authorization", scheme.authenticate(creds, method)); + } catch (AuthenticationException e) { + // ignore + } + } + } + } + }); xmlrpc.setTransportFactory(factory); } // update configuration with latest values AuthenticationCredentials credentials = location.getCredentials(AuthenticationType.REPOSITORY); + config.setServerURL(getXmlRpcUrl(credentials)); if (credentialsValid(credentials)) { - config.setBasicUserName(credentials.getUserName()); - config.setBasicPassword(credentials.getPassword()); + Credentials creds = new UsernamePasswordCredentials(credentials.getUserName(), credentials.getPassword()); + httpClient.getState().setCredentials(authScope, creds); } else { - config.setBasicUserName(null); - config.setBasicPassword(null); + httpClient.getState().clearCredentials(); } - config.setServerURL(getXmlRpcUrl(credentials)); return xmlrpc; } @@ -243,9 +277,51 @@ public class TracXmlRpcClient extends AbstractTracClient implements ITracWikiCli } } + private void probeAuthenticationScheme(IProgressMonitor monitor) throws TracException { + if (probed) { + return; + } + + try { + AuthenticationCredentials credentials = location.getCredentials(AuthenticationType.REPOSITORY); + if (!credentialsValid(credentials)) { + return; + } + + HostConfiguration hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor); + HeadMethod method = new HeadMethod(getXmlRpcUrl(credentials).toString()); + try { + int result = WebUtil.execute(httpClient, hostConfiguration, method, monitor); + if (result == HttpStatus.SC_UNAUTHORIZED || result == HttpStatus.SC_FORBIDDEN) { + Header header = method.getResponseHeader("WWW-Authenticate"); + if (header != null) { + if (header.getValue().startsWith("Basic")) { + httpClient.getParams().setAuthenticationPreemptive(true); + } else if (header.getValue().startsWith("Digest")) { + DigestScheme scheme = new DigestScheme(); + try { + scheme.processChallenge(header.getValue()); + this.digestScheme = scheme; + } catch (MalformedChallengeException e) { + // ignore + } + } + } + } + } catch (IOException e) { + // ignore + } finally { + method.releaseConnection(); + } + } finally { + probed = true; + } + } + private Object call(IProgressMonitor monitor, String method, Object... parameters) throws TracException { monitor = Policy.monitorFor(monitor); while (true) { + probeAuthenticationScheme(monitor); getClient(); try { diff --git a/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/util/HttpRequestInterceptor.java b/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/util/HttpRequestInterceptor.java new file mode 100644 index 000000000..bc2938a8d --- /dev/null +++ b/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/util/HttpRequestInterceptor.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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.internal.trac.core.util; + +import org.apache.commons.httpclient.HttpMethod; + +/** + * @author Steffen Pingel + */ +public interface HttpRequestInterceptor { + + public abstract void process(HttpMethod method); + +} diff --git a/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/util/TracHttpClientTransportFactory.java b/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/util/TracHttpClientTransportFactory.java index 94f787caa..1033f7ec2 100644 --- a/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/util/TracHttpClientTransportFactory.java +++ b/org.eclipse.mylyn.trac.core/src/org/eclipse/mylyn/internal/trac/core/util/TracHttpClientTransportFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2006, 2008 Steffen Pingel and others. + * Copyright (c) 2006, 2008 Steffen Pingel 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 @@ -18,18 +18,13 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; -import org.apache.commons.httpclient.Cookie; -import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpVersion; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.RequestEntity; -import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.XmlRpcRequest; import org.apache.xmlrpc.client.XmlRpcClient; @@ -38,7 +33,6 @@ import org.apache.xmlrpc.client.XmlRpcHttpClientConfig; import org.apache.xmlrpc.client.XmlRpcHttpTransport; import org.apache.xmlrpc.client.XmlRpcTransport; import org.apache.xmlrpc.client.XmlRpcTransportFactory; -import org.apache.xmlrpc.common.XmlRpcStreamConfig; import org.apache.xmlrpc.common.XmlRpcStreamRequestConfig; import org.apache.xmlrpc.util.HttpUtil; import org.apache.xmlrpc.util.XmlRpcIOException; @@ -63,8 +57,6 @@ public class TracHttpClientTransportFactory implements XmlRpcTransportFactory { private final AbstractWebLocation location; - private final Cookie[] cookies; - private PostMethod method; private int contentLength = -1; @@ -75,13 +67,14 @@ public class TracHttpClientTransportFactory implements XmlRpcTransportFactory { private HostConfiguration hostConfiguration; + private final HttpRequestInterceptor interceptor; + public TracHttpClientTransport(XmlRpcClient client, HttpClient httpClient, AbstractWebLocation location, - Cookie[] cookies) { + HttpRequestInterceptor interceptor) { super(client, ""); - this.httpClient = httpClient; this.location = location; - this.cookies = cookies; + this.interceptor = interceptor; } @Override @@ -127,9 +120,6 @@ public class TracHttpClientTransportFactory implements XmlRpcTransportFactory { String url = config.getServerURL().toString(); hostConfiguration = WebUtil.createHostConfiguration(httpClient, location, monitor); - if (cookies != null) { - httpClient.getState().addCookies(cookies); - } method = new PostMethod(WebUtil.getRequestPath(url)); super.initHttpHeaders(request); @@ -143,6 +133,10 @@ public class TracHttpClientTransportFactory implements XmlRpcTransportFactory { } method.getParams().setVersion(HttpVersion.HTTP_1_1); + + if (interceptor != null) { + interceptor.process(method); + } } @Override @@ -158,18 +152,7 @@ public class TracHttpClientTransportFactory implements XmlRpcTransportFactory { @Override protected void setCredentials(XmlRpcHttpClientConfig config) throws XmlRpcClientException { - String userName = config.getBasicUserName(); - if (userName != null) { - String encoding = config.getBasicEncoding(); - if (encoding == null) { - encoding = XmlRpcStreamConfig.UTF8_ENCODING; - } - httpClient.getParams().setParameter(HttpMethodParams.CREDENTIAL_CHARSET, encoding); - Credentials creds = new UsernamePasswordCredentials(userName, config.getBasicPassword()); - AuthScope scope = new AuthScope(null, AuthScope.ANY_PORT, null, AuthScope.ANY_SCHEME); - httpClient.getState().setCredentials(scope, creds); - httpClient.getParams().setAuthenticationPreemptive(true); - } + // handled by TracXmlRpcClient } @Override @@ -253,35 +236,35 @@ public class TracHttpClientTransportFactory implements XmlRpcTransportFactory { private final XmlRpcClient xmlRpcClient; - private Cookie[] cookies; - private AbstractWebLocation location; private final HttpClient httpClient; + private HttpRequestInterceptor interceptor; + public TracHttpClientTransportFactory(XmlRpcClient xmlRpcClient, HttpClient httpClient) { this.xmlRpcClient = xmlRpcClient; this.httpClient = httpClient; } - public Cookie[] getCookies() { - return cookies; - } - public AbstractWebLocation getLocation() { return location; } public XmlRpcTransport getTransport() { - return new TracHttpClientTransport(xmlRpcClient, httpClient, location, cookies); - } - - public void setCookies(Cookie[] cookies) { - this.cookies = cookies; + return new TracHttpClientTransport(xmlRpcClient, httpClient, location, interceptor); } public void setLocation(AbstractWebLocation location) { this.location = location; } + public HttpRequestInterceptor getInterceptor() { + return interceptor; + } + + public void setInterceptor(HttpRequestInterceptor interceptor) { + this.interceptor = interceptor; + } + } |