From 799d362c8b1a60db4eaa007503b0aaf692d8fdfd Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 14 Oct 2014 13:33:02 +0400 Subject: [PATCH 1/7] IDEA-130912 Use different keys (also different from keys used by SVNKit) for caching password/passphrase for svn+ssh repositories for command line (not to use incorrect data from cache or possibly get ClassCastException as objects of different types could be cached with the same key) --- .../src/org/jetbrains/idea/svn/auth/AuthenticationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java index cadd6088eb76..7e7b33ccfd15 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java @@ -153,7 +153,7 @@ public class AuthenticationService { public String requestSshCredentials(@NotNull final String realm, @NotNull final SimpleCredentialsDialog.Mode mode, @NotNull final String key) { - return requestCredentials(realm, ISVNAuthenticationManager.SSH, new Getter() { + return requestCredentials(realm, StringUtil.toLowerCase(mode.toString()), new Getter() { @Override public String get() { final Ref answer = new Ref(); From 8b3bcbcdafaecdedf2d7f2391b29d19dd4ae9af8 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 14 Oct 2014 13:51:55 +0400 Subject: [PATCH 2/7] svn: Use different keys (also different from keys used by SVNKit) for caching server certificate acceptance result (for https repositories) for usual command line and "run under terminal" command line modes (not to get ClassCastException as objects of different types could be cached with the same key) --- .../src/org/jetbrains/idea/svn/auth/AuthenticationService.java | 2 +- .../org/jetbrains/idea/svn/auth/CertificateTrustManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java index 7e7b33ccfd15..f35cefb83efd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/AuthenticationService.java @@ -184,7 +184,7 @@ public class AuthenticationService { @NotNull public AcceptResult acceptCertificate(@NotNull final SVNURL url, @NotNull final String certificateInfo) { // TODO: Probably explicitly construct server url for realm here - like in CertificateTrustManager. - String kind = "svn.ssl.server"; + String kind = "terminal.ssl.server"; String realm = url.toDecodedString(); Object data = SvnConfiguration.RUNTIME_AUTH_CACHE.getDataWithLowerCheck(kind, realm); AcceptResult result; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CertificateTrustManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CertificateTrustManager.java index c5bd5a54182b..07aed1461c91 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CertificateTrustManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/CertificateTrustManager.java @@ -113,7 +113,7 @@ public class CertificateTrustManager extends ClientOnlyTrustManager { } private void acknowledge(@NotNull X509Certificate certificate) throws CertificateEncodingException { - myAuthenticationService.getVcs().getSvnConfiguration().acknowledge("svn.ssl.server", myRealm, certificate); + myAuthenticationService.getVcs().getSvnConfiguration().acknowledge("cmd.ssl.server", myRealm, certificate); } @Override From 7fbd9c3ff342a950dfa9a96347b3bec570fb5451 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 14 Oct 2014 14:44:48 +0400 Subject: [PATCH 3/7] svn: Refactored authentication prompts handling in "run under terminal" mode - always rely that repository url of processed command is not null (as it should be correctly set in CommandParametersResolutionModule) --- .../idea/svn/commandLine/BaseTerminalModule.java | 2 +- .../src/org/jetbrains/idea/svn/commandLine/Command.java | 8 ++++++++ .../idea/svn/commandLine/TerminalSshModule.java | 9 ++------- .../svn/commandLine/TerminalUserNamePasswordModule.java | 3 +-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java index d4b9475ee5d5..95a0e7474f78 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/BaseTerminalModule.java @@ -80,6 +80,6 @@ public abstract class BaseTerminalModule extends LineCommandAdapter implements C } protected void cancelAuthentication() { - myExecutor.destroyProcess("Authentication canceled for repository: " + myExecutor.getCommand().getRepositoryUrl()); + myExecutor.destroyProcess("Authentication canceled for repository: " + myExecutor.getCommand().requireRepositoryUrl()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/Command.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/Command.java index 50215fba76c8..a20e2db48495 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/Command.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/Command.java @@ -79,6 +79,14 @@ public class Command { return myRepositoryUrl; } + @NotNull + public SVNURL requireRepositoryUrl() { + SVNURL result = getRepositoryUrl(); + assert result != null; + + return result; + } + @NotNull public SvnTarget getTarget() { return myTarget; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java index 1ebd86485033..740954cf31ca 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalSshModule.java @@ -112,13 +112,8 @@ public class TerminalSshModule extends BaseTerminalModule { } private boolean handleAuthPrompt(@NotNull final SimpleCredentialsDialog.Mode mode, @NotNull final String key) { - final SVNURL repositoryUrl = myExecutor.getCommand().getRepositoryUrl(); - - // TODO: repositoryUrl could be null for some cases, for instance for info command for file is invoked that requires - // TODO: authentication (like "svn info -r HEAD"), if it is invoked before all working copy roots are resolved. - // TODO: resolving repositoryUrl logic should be updated so that repositoryUrl is not null here. - String auth = - myRuntime.getAuthenticationService().requestSshCredentials(repositoryUrl != null ? repositoryUrl.toDecodedString() : "", mode, key); + SVNURL repositoryUrl = myExecutor.getCommand().requireRepositoryUrl(); + String auth = myRuntime.getAuthenticationService().requestSshCredentials(repositoryUrl.toDecodedString(), mode, key); if (!StringUtil.isEmpty(auth)) { sendData(auth); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalUserNamePasswordModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalUserNamePasswordModule.java index dbb1d211a8b4..489222ab8190 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalUserNamePasswordModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/TerminalUserNamePasswordModule.java @@ -79,8 +79,7 @@ public class TerminalUserNamePasswordModule extends BaseTerminalModule { * (before any user name prompt) for pre-configured/system user name. */ private boolean handleAuthPrompt(boolean isUserName) { - // TODO: check command is not local and get @NotNull url - also make same for for ssh module - SVNURL repositoryUrl = myExecutor.getCommand().getRepositoryUrl(); + SVNURL repositoryUrl = myExecutor.getCommand().requireRepositoryUrl(); if (needAskAuthentication(isUserName)) { // TODO: Probably pass real realm to dialog From 6aacc9695b87ed79da906657dbba59a62a750582 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 14 Oct 2014 15:30:29 +0400 Subject: [PATCH 4/7] svn: Refactored IDEA proxy settings handling for command line integration - only pass proxy settings to svn command line client if currently executing command is non-local (requires repository access) --- .../idea/svn/commandLine/ProxyModule.java | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyModule.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyModule.java index bdfdd55ed6e1..b9e83e7bf850 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyModule.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/ProxyModule.java @@ -15,7 +15,6 @@ */ package org.jetbrains.idea.svn.commandLine; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.IdeaSVNConfigFile; @@ -31,38 +30,29 @@ import java.net.Proxy; */ public class ProxyModule extends BaseCommandRuntimeModule { - private static final Logger LOG = Logger.getInstance(ProxyModule.class); - public ProxyModule(@NotNull CommandRuntime runtime) { super(runtime); } @Override public void onStart(@NotNull Command command) throws SvnBindException { - if (myAuthenticationService.haveDataForTmpConfig()) { + if (myAuthenticationService.haveDataForTmpConfig() && !CommandRuntime.isLocal(command)) { setupProxy(command); } } private void setupProxy(@NotNull Command command) { - // TODO: We assume that if repository url is null - command is local and do not require repository access - // TODO: Check if this is correct for all cases - SVNURL repositoryUrl = command.getRepositoryUrl(); + SVNURL repositoryUrl = command.requireRepositoryUrl(); + Proxy proxy = AuthenticationService.getIdeaDefinedProxy(repositoryUrl); - if (repositoryUrl != null) { - Proxy proxy = AuthenticationService.getIdeaDefinedProxy(repositoryUrl); + if (proxy != null) { + String hostGroup = ensureGroupForHost(command, repositoryUrl.getHost()); + InetSocketAddress address = (InetSocketAddress)proxy.address(); - if (proxy != null) { - String hostGroup = ensureGroupForHost(command, repositoryUrl.getHost()); - InetSocketAddress address = (InetSocketAddress)proxy.address(); - - command.put("--config-option"); - command.put(String.format("servers:%s:http-proxy-host=%s", hostGroup, address.getHostName())); - command.put("--config-option"); - command.put(String.format("servers:%s:http-proxy-port=%s", hostGroup, address.getPort())); - } - } else { - LOG.info("Configured proxy should be used, but repository url is null for command - " + command.getText()); + command.put("--config-option"); + command.put(String.format("servers:%s:http-proxy-host=%s", hostGroup, address.getHostName())); + command.put("--config-option"); + command.put(String.format("servers:%s:http-proxy-port=%s", hostGroup, address.getPort())); } } From b4686b24827596220c51161ff9a8bd4dd78aeca2 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Tue, 14 Oct 2014 16:46:09 +0400 Subject: [PATCH 5/7] svn: Implemented IDEA proxy settings support for command line integration in "run under terminal" mode --- .../idea/svn/commandLine/CommandRuntime.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java index caeb1c26cc67..e3fce7f14253 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java @@ -126,7 +126,7 @@ public class CommandRuntime { private boolean handleErrorText(CommandExecutor executor, Command command) throws SvnBindException { final String errText = executor.getErrorOutput().trim(); - final AuthCallbackCase callback = executor instanceof TerminalExecutor ? null : createCallback(errText, command.getRepositoryUrl()); + final AuthCallbackCase callback = createCallback(errText, command.getRepositoryUrl(), executor instanceof TerminalExecutor); // do not handle possible authentication errors if command was manually cancelled // force checking if command is cancelled and not just use corresponding value from executor - as there could be cases when command // finishes quickly but with some auth error - this way checkCancelled() is not called by executor itself and so command is repeated @@ -166,13 +166,23 @@ public class CommandRuntime { } @Nullable - private AuthCallbackCase createCallback(@NotNull final String errText, @Nullable final SVNURL url) { + private AuthCallbackCase createCallback(@NotNull final String errText, @Nullable final SVNURL url, boolean isUnderTerminal) { List authCases = ContainerUtil.newArrayList(); - authCases.add(new CertificateCallbackCase(myAuthenticationService, url)); - authCases.add(new ProxyCallback(myAuthenticationService, url)); - authCases.add(new TwoWaySslCallback(myAuthenticationService, url)); - authCases.add(new UsernamePasswordCallback(myAuthenticationService, url)); + if (isUnderTerminal) { + // Subversion client does not prompt for proxy credentials (just fails with error) even in terminal mode. So we handle this case the + // same way as in non-terminal mode - repeat command with new credentials. + // NOTE: We could also try getting proxy credentials from user in advance (by issuing separate request and asking for credentials if + // NOTE: required) - not to execute same command several times like it is currently for all other cases in terminal mode. But such + // NOTE: behaviour is not mandatory for now - so we just use "repeat command" logic. + authCases.add(new ProxyCallback(myAuthenticationService, url)); + } + else { + authCases.add(new CertificateCallbackCase(myAuthenticationService, url)); + authCases.add(new ProxyCallback(myAuthenticationService, url)); + authCases.add(new TwoWaySslCallback(myAuthenticationService, url)); + authCases.add(new UsernamePasswordCallback(myAuthenticationService, url)); + } return ContainerUtil.find(authCases, new Condition() { @Override From 43a99912e162f16598e04645256c7a7bdd85daf4 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 15 Oct 2014 17:48:50 +0400 Subject: [PATCH 6/7] svn: Updated settings - renamed "Run under terminal" checkbox to "Interactive mode", added description of "Interactive mode" --- .../jetbrains/idea/svn/SvnBundle.properties | 4 ++++ .../jetbrains/idea/svn/SvnConfigurable.form | 22 +++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties index 12364be04841..e6f36b2b2fb7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties @@ -201,6 +201,10 @@ dialog.edit.http.proxies.settings.test.connection.succes.title=Connection test s confirmation.text.delete.stored.authentication.information=You are about to delete all stored Subversion authentication information.\nWould you like to proceed with deletion? confirmation.title.clear.authentication.cache=Clear Authentication Cache +command.line.interactive.mode.title=Interactive mode +command.line.interactive.mode.description=Emulates behaviour as if Subversion commands were executed directly from terminal (in interactive mode).
\ + Primarily intended to be used for handling password/passphrase prompts for svn+ssh repositories and trusting invalid server certificates for https repositories. + ssh.settings.title=SSH Settings ssh.settings.executable.label=SSH executable\: ssh.settings.browse.executable.dialog.title=SSH executable diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form index f1e61767844b..822ca320c43b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form @@ -18,7 +18,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -87,7 +87,7 @@ - + @@ -96,7 +96,7 @@ - + @@ -123,12 +123,12 @@ - + - + @@ -162,7 +162,15 @@ - + + + + + + + + + From f2b9baafefad1950da7a5fca2559b3f7485a7256 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 17 Oct 2014 13:57:07 +0400 Subject: [PATCH 7/7] IDEA-131280 Implemented client certificate (for https repositories) handling support for command line integration in "run under terminal" mode --- .../src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java index e3fce7f14253..46b716c3bde2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandRuntime.java @@ -176,6 +176,8 @@ public class CommandRuntime { // NOTE: required) - not to execute same command several times like it is currently for all other cases in terminal mode. But such // NOTE: behaviour is not mandatory for now - so we just use "repeat command" logic. authCases.add(new ProxyCallback(myAuthenticationService, url)); + // Same situation (described above) as with proxy settings is here. + authCases.add(new TwoWaySslCallback(myAuthenticationService, url)); } else { authCases.add(new CertificateCallbackCase(myAuthenticationService, url));