1) no proxy with current thread (same host can serve Svn and other services)

2) correctly form proxy auth request from Svn when IDEA proxy is used (requestor type = proxy)
3) release no proxy after Svn request
4) correctly check in passive validation (whether remote calls have credentials) - when IDEA proxy & autodetection & no credentials
This commit is contained in:
irengrig
2013-01-31 15:21:17 +04:00
parent 23624e90af
commit 85d61fbdb9
3 changed files with 84 additions and 38 deletions
@@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.util.PopupUtil;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.net.HTTPProxySettingsPanel;
import org.jetbrains.annotations.NotNull;
@@ -47,11 +48,11 @@ public class CommonProxy extends ProxySelector {
private static final Logger LOG = Logger.getInstance("#com.intellij.util.proxy.CommonProxy");
private final Object myLock;
private final Set<HostInfo> myNoProxy;
private final Set<Pair<HostInfo, Thread>> myNoProxy;
private final Map<String, ProxySelector> myCustom;
private final Map<String, NonStaticAuthenticator> myCustomAuth;
private final Set<HostInfo> myNoAuthentication;
private final Set<Pair<HostInfo, Thread>> myNoAuthentication;
public static CommonProxy getInstance() {
return ourInstance;
@@ -59,12 +60,12 @@ public class CommonProxy extends ProxySelector {
public CommonProxy() {
myLock = new Object();
myNoProxy = new HashSet<HostInfo>();
myNoProxy = new HashSet<Pair<HostInfo, Thread>>();
myCustom = new HashMap<String, ProxySelector>();
myCustomAuth = new HashMap<String, NonStaticAuthenticator>();
myAuthenticator = new CommonAuthenticator();
ensureAuthenticator();
myNoAuthentication = new HashSet<HostInfo>();
myNoAuthentication = new HashSet<Pair<HostInfo, Thread>>();
}
public static void isInstalledAssertion() {
@@ -110,28 +111,28 @@ public class CommonProxy extends ProxySelector {
public void noProxy(@NotNull final String protocol, @NotNull final String host, final int port) {
synchronized (myLock) {
LOG.debug("no proxy added: " + protocol + "://" + host + ":" + port);
myNoProxy.add(new HostInfo(protocol, host, port));
myNoProxy.add(Pair.create(new HostInfo(protocol, host, port), Thread.currentThread()));
}
}
public void removeNoProxy(@NotNull final String protocol, @NotNull final String host, final int port) {
synchronized (myLock) {
LOG.debug("no proxy removed: " + protocol + "://" + host + ":" + port);
myNoProxy.remove(new HostInfo(protocol, host, port));
myNoProxy.remove(Pair.create(new HostInfo(protocol, host, port), Thread.currentThread()));
}
}
public void noAuthentication(@NotNull final String protocol, @NotNull final String host, final int port) {
synchronized (myLock) {
LOG.debug("no proxy added: " + protocol + "://" + host + ":" + port);
myNoProxy.add(new HostInfo(protocol, host, port));
myNoProxy.add(Pair.create(new HostInfo(protocol, host, port), Thread.currentThread()));
}
}
public void removeNoAuthentication(@NotNull final String protocol, @NotNull final String host, final int port) {
synchronized (myLock) {
LOG.debug("no proxy removed: " + protocol + "://" + host + ":" + port);
myNoProxy.remove(new HostInfo(protocol, host, port));
myNoProxy.remove(Pair.create(new HostInfo(protocol, host, port), Thread.currentThread()));
}
}
@@ -179,7 +180,7 @@ public class CommonProxy extends ProxySelector {
final HostInfo info = new HostInfo(protocol, host, port);
final Map<String, ProxySelector> copy;
synchronized (myLock) {
if (myNoProxy.contains(info)) {
if (myNoProxy.contains(Pair.create(info, Thread.currentThread()))) {
LOG.debug("CommonProxy.select returns no proxy (in no proxy list) for " + uri.toString());
return NO_PROXY_LIST;
}
@@ -220,11 +221,12 @@ public class CommonProxy extends ProxySelector {
synchronized (myLock) {
// for hosts defined as no proxy we will NOT pass authentication to not provoke credentials
final HostInfo hostInfo = new HostInfo(getRequestingProtocol(), host, port);
if (myNoProxy.contains(hostInfo)) {
final Pair<HostInfo, Thread> pair = Pair.create(hostInfo, Thread.currentThread());
if (myNoProxy.contains(pair)) {
LOG.debug("CommonAuthenticator.getPasswordAuthentication found host in no proxies set (" + siteStr + ")");
return null;
}
if (myNoAuthentication.contains(hostInfo)) {
if (myNoAuthentication.contains(pair)) {
LOG.debug("CommonAuthenticator.getPasswordAuthentication found host in no authentication set (" + siteStr + ")");
return null;
}
@@ -389,7 +389,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
String realm,
SVNErrorMessage errorMessage,
SVNAuthentication authentication,
SVNURL accessedLocation) throws SVNException {
SVNURL url) throws SVNException {
CommonProxy.getInstance().removeNoProxy(url.getProtocol(), url.getHost(), url.getPort());
}
public ISVNProxyManager getProxyManager(SVNURL url) throws SVNException {
@@ -465,7 +466,8 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im
try {
final InetAddress ia = InetAddress.getByName(getProxyHost());
final PasswordAuthentication authentication =
Authenticator.requestPasswordAuthentication(ia, getProxyPort(), myProtocol, getProxyHost(), myProtocol);
Authenticator.requestPasswordAuthentication(getProxyHost(), ia, getProxyPort(), myProtocol, getProxyHost(), myProtocol,
null, Authenticator.RequestorType.PROXY);
if (authentication != null) {
myProxyUser = authentication.getUserName();
myProxyPassword = String.valueOf(authentication.getPassword());
@@ -37,6 +37,7 @@ import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Consumer;
import com.intellij.util.ThreeState;
import com.intellij.util.net.HttpConfigurable;
import com.intellij.util.proxy.CommonProxy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.dialogs.SvnInteractiveAuthenticationProvider;
@@ -51,6 +52,7 @@ import org.tmatesoft.svn.core.wc.SVNWCClient;
import javax.swing.*;
import java.awt.*;
import java.net.*;
import java.util.*;
import java.util.List;
import java.util.Timer;
@@ -316,12 +318,36 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
final String realm,
final String kind, boolean interactive) {
// we should also NOT show proxy credentials dialog if at least fixed proxy was used, so
if (configuration.isIsUseDefaultProxy()) {
Proxy proxyToRelease = null;
if (! interactive && configuration.isIsUseDefaultProxy()) {
final HttpConfigurable instance = HttpConfigurable.getInstance();
if (instance.USE_HTTP_PROXY && instance.PROXY_AUTHENTICATION && (StringUtil.isEmptyOrSpaces(instance.PROXY_LOGIN) ||
StringUtil.isEmptyOrSpaces(instance.getPlainProxyPassword()))) {
return false;
}
if (instance.USE_PROXY_PAC) {
final List<Proxy> select;
try {
select = CommonProxy.getInstance().select(new URI(url.toString()));
}
catch (URISyntaxException e) {
LOG.info("wrong URL: " + url.toString());
return false;
}
if (select != null && ! select.isEmpty()) {
for (Proxy proxy : select) {
if (HttpConfigurable.isRealProxy(proxy) && Proxy.Type.HTTP.equals(proxy.type())) {
final InetSocketAddress address = (InetSocketAddress)proxy.address();
final PasswordAuthentication password =
HttpConfigurable.getInstance().getGenericPassword(address.getHostName(), address.getPort());
if (password == null) {
CommonProxy.getInstance().noAuthentication("http", address.getHostName(), address.getPort());
proxyToRelease = proxy;
}
}
}
}
}
}
SvnInteractiveAuthenticationProvider.clearCallState();
try {
@@ -339,32 +365,14 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
}
LOG.info("some other exc", e);
if (interactive) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
VcsBalloonProblemNotifier.showOverChangesView(project, "Authentication failed: " + e.getMessage(), MessageType.ERROR,
new NamedRunnable(SvnBundle.message("confirmation.title.clear.authentication.cache")) {
@Override
public void run() {
SvnConfigurable.clearAuthenticationCache(project, null, configuration.getConfigurationDirectory());
}
},
new NamedRunnable(SvnBundle.message("action.title.select.configuration.directory")) {
@Override
public void run() {
SvnConfigurable.selectConfigirationDirectory(configuration.getConfigurationDirectory(),
new Consumer<String>() {
@Override
public void consume(String s) {
configuration.setConfigurationDirParameters(false, s);
}
}, project, null);
}
});
}
}, ModalityState.NON_MODAL, project.getDisposed());
showAuthenticationFailedWithHotFixes(project, configuration, e);
}
return false; /// !!!! any exception means user should be notified that authorization failed
} finally {
if (! interactive && configuration.isIsUseDefaultProxy() && proxyToRelease != null) {
final InetSocketAddress address = (InetSocketAddress)proxyToRelease.address();
CommonProxy.getInstance().noAuthentication("http", address.getHostName(), address.getPort());
}
}
if (! checkWrite) {
@@ -393,4 +401,38 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
}
return false;
}
private static void showAuthenticationFailedWithHotFixes(final Project project,
final SvnConfiguration configuration,
final SVNException e) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
VcsBalloonProblemNotifier.showOverChangesView(project, "Authentication failed: " + e.getMessage(), MessageType.ERROR,
new NamedRunnable(
SvnBundle.message("confirmation.title.clear.authentication.cache")) {
@Override
public void run() {
SvnConfigurable.clearAuthenticationCache(project, null, configuration
.getConfigurationDirectory());
}
},
new NamedRunnable(SvnBundle.message("action.title.select.configuration.directory")) {
@Override
public void run() {
SvnConfigurable
.selectConfigirationDirectory(configuration.getConfigurationDirectory(),
new Consumer<String>() {
@Override
public void consume(String s) {
configuration
.setConfigurationDirParameters(false, s);
}
}, project, null);
}
}
);
}
}, ModalityState.NON_MODAL, project.getDisposed());
}
}