/*******************************************************************************
* Copyright (c) 2009 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* Thomas Joiner - HttpClient 4 implementation
*******************************************************************************/
package org.eclipse.ecf.internal.provider.filetransfer.httpclient4;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.eclipse.ecf.core.util.Proxy;
import org.eclipse.ecf.core.util.ProxyAddress;
import org.eclipse.ecf.core.util.Trace;
public abstract class HttpClientProxyCredentialProvider implements CredentialsProvider {
abstract protected Proxy getECFProxy();
abstract protected Credentials getNTLMCredentials(Proxy proxy);
private Map cachedCredentials;
public HttpClientProxyCredentialProvider() {
cachedCredentials = new ConcurrentHashMap<AuthScope, Credentials>();
}
public void setCredentials(AuthScope authscope, Credentials credentials) {
if (authscope == null)
throw new IllegalArgumentException("Authentication scope may not be null"); //$NON-NLS-1$
this.cachedCredentials.put(authscope, credentials);
}
public Credentials getCredentials(AuthScope authscope) {
Trace.entering(Activator.PLUGIN_ID, DebugOptions.METHODS_ENTERING, HttpClientProxyCredentialProvider.class, "getCredentials " + authscope); //$NON-NLS-1$
// First check to see whether given authscope matches any authscope
// already cached.
Credentials result = matchCredentials(this.cachedCredentials, authscope);
// If we have a match, return credentials
if (result != null)
return result;
// If we don't have a match, first get ECF proxy, if any
Proxy proxy = getECFProxy();
if (proxy == null)
return null;
// Make sure that authscope and proxy host and port match
if (!matchAuthScopeAndProxy(authscope, proxy))
return null;
// Then match scheme, and get credentials from proxy (if it's scheme we know about)
Credentials credentials = null;
if ("ntlm".equalsIgnoreCase(authscope.getScheme())) { //$NON-NLS-1$
credentials = getNTLMCredentials(proxy);
} else if ("basic".equalsIgnoreCase(authscope.getScheme()) || //$NON-NLS-1$
"digest".equalsIgnoreCase(authscope.getScheme())) { //$NON-NLS-1$
final String proxyUsername = proxy.getUsername();
final String proxyPassword = proxy.getPassword();
// If credentials present for proxy then we're done
if (proxyUsername != null) {
credentials = new UsernamePasswordCredentials(proxyUsername, proxyPassword);
}
} else if ("negotiate".equalsIgnoreCase(authscope.getScheme())) { //$NON-NLS-1$
Trace.trace(Activator.PLUGIN_ID, "SPNEGO is not supported, if you can contribute support, please do so."); //$NON-NLS-1$
} else {
Trace.trace(Activator.PLUGIN_ID, "Unrecognized authentication scheme."); //$NON-NLS-1$
}
// Put found credentials in cache for next time
if (credentials != null)
cachedCredentials.put(authscope, credentials);
return credentials;
}
private boolean matchAuthScopeAndProxy(AuthScope authscope, Proxy proxy) {
ProxyAddress proxyAddress = proxy.getAddress();
return (authscope.getHost().equals(proxyAddress.getHostName()) && (authscope.getPort() == proxyAddress.getPort()));
}
private static Credentials matchCredentials(final Map<AuthScope, Credentials> map, final AuthScope authscope) {
// see if we get a direct hit
Credentials creds = map.get(authscope);
if (creds == null) {
// Nope.
// Do a full scan
int bestMatchFactor = -1;
AuthScope bestMatch = null;
for (AuthScope current : map.keySet()) {
int factor = authscope.match(current);
if (factor > bestMatchFactor) {
bestMatchFactor = factor;
bestMatch = current;
}
}
if (bestMatch != null) {
creds = map.get(bestMatch);
}
}
return creds;
}
public void clear() {
this.cachedCredentials.clear();
}
}