diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationManager.java index 988a2a66180c..9198b0d642e6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationManager.java @@ -18,17 +18,20 @@ package org.jetbrains.idea.svn; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vcs.changes.ui.ChangesViewBalloonProblemNotifier; import com.intellij.util.containers.SoftHashMap; import com.intellij.util.net.HttpConfigurable; +import org.jetbrains.annotations.Nullable; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider; -import org.tmatesoft.svn.core.auth.ISVNProxyManager; -import org.tmatesoft.svn.core.auth.SVNAuthentication; +import org.tmatesoft.svn.core.auth.*; import org.tmatesoft.svn.core.internal.wc.DefaultSVNAuthenticationManager; import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions; +import org.tmatesoft.svn.core.internal.wc.SVNConfigFile; +import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.io.SVNRepository; import java.io.File; @@ -41,13 +44,15 @@ import java.util.StringTokenizer; */ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager { private final Project myProject; + private final File myConfigDirectory; private PersistentAuthenticationProviderProxy myPersistentAuthenticationProviderProxy; private SvnConfiguration myConfig; public SvnAuthenticationManager(final Project project, final File configDirectory) { super(configDirectory, true, null, null); myProject = project; - myConfig = SvnConfiguration.getInstance(myProject); + myConfigDirectory = configDirectory; + myConfig = SvnConfiguration.getInstance(myProject); if (myPersistentAuthenticationProviderProxy != null) { myPersistentAuthenticationProviderProxy.setProject(myProject); } @@ -317,4 +322,115 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager { return SvnAuthEquals.hashCode(getT()); } } + + private void setPropertyForHost(final String host, final String property, final String value) { + final SVNConfigFile userConfig = new SVNConfigFile(new File(myConfigDirectory, "servers")); + + String groupName = getGroupName(userConfig.getProperties("groups"), host); + if (groupName != null) { + userConfig.setPropertyValue(groupName, property, value, true); + } else { + final SVNConfigFile systemConfig = new SVNConfigFile(new File(SVNFileUtil.getSystemConfigurationDirectory(), "servers")); + final String systemGroupName = getGroupName(systemConfig.getProperties("groups"), host); + if (systemGroupName != null) { + systemConfig.setPropertyValue(systemGroupName, property, value, true); + } else { + // global + userConfig.setPropertyValue("global", property, value, true); + } + } + } + + // default = yes + private boolean isTurned(final String value) { + return value == null || "yes".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value); + } + + @Nullable + protected Boolean isAuthStorageEnabledMy(SVNURL url) { + String host = url != null ? url.getHost() : null; + Map properties = getHostProperties(host); + String storeAuthCreds = (String) properties.get("store-auth-creds"); + if (storeAuthCreds == null) { + return null; + } + + return "yes".equalsIgnoreCase(storeAuthCreds) || "on".equalsIgnoreCase(storeAuthCreds) || "true".equalsIgnoreCase(storeAuthCreds); + } + + public boolean checkContinueSaveCredentials(final SVNAuthentication auth, final String kind, final String realm) { + final SVNURL url = auth.getURL(); + + //final SVNConfigFile userConfig = new SVNConfigFile(new File(myConfigDirectory, "config")); + final boolean authStorageEnabled = isAuthStorageEnabled(url); + final String storeCredentials = getConfigFile().getPropertyValue("auth", "store-auth-creds"); + if ((Boolean.FALSE.equals(isAuthStorageEnabledMy(url))) || (! isTurned(storeCredentials))) { + //userConfig.setPropertyValue("auth", "store-auth-creds", "yes", true); + ChangesViewBalloonProblemNotifier.showMe(myProject, "Cannot store credentials: forbidden by \"store-auth-creds\"=\"no\"", MessageType.ERROR); + return false; + } + final boolean passwordStorageEnabled = isStorePasswords(url); + // check can store + final String storePasswords = getConfigFile().getPropertyValue("auth", "store-passwords"); + if ((! ISVNAuthenticationManager.SSL.equals(kind)) && (! passwordStorageEnabled)) { + // but it should be + //userConfig.setPropertyValue("auth", "store-passwords", "yes", true); + ChangesViewBalloonProblemNotifier.showMe(myProject, "Cannot store password: forbidden by \"store-passwords\"=\"no\"", MessageType.ERROR); + return false; + } + if (ISVNAuthenticationManager.SSL.equals(kind) && (! isStoreSSLClientCertificatePassphrases(url))) { + //setPropertyForHost(url.getHost(), "store-ssl-client-cert-pp", "yes"); + ChangesViewBalloonProblemNotifier.showMe(myProject, "Cannot store passphrase: forbidden by \"store-ssl-client-cert-pp\"=\"no\"", MessageType.ERROR); + return false; + } + + // check can encrypt + if (! SystemInfo.isWindows) { + if (ISVNAuthenticationManager.SSL.equals(kind)) { + try { + if (! isStorePlainTextPassphrases(realm, auth)) { + final SVNSSLAuthentication svnsslAuthentication = (SVNSSLAuthentication)auth; + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + Messages.showWarningDialog(myProject, "Your passphrase for client certificate:\n\n" + + svnsslAuthentication.getCertificateFile().getPath() + + "\n\ncan only be stored to disk unencrypted. (Encryption is not supported)\n\n" + + "But storage in plain text is not allowed.\nTo allow plain text passphrases caching, set \"store-ssl-client-cert-pp-plaintext\"=\"yes\"", + "Cannot save passphrase"); + } + }); + /*ChangesViewBalloonProblemNotifier.showMe(myProject, "Your passphrase for client certificate:\n" + + svnsslAuthentication.getCertificateFile().getPath() + + "\ncan only be stored to disk unencrypted! (Encryption is not supported)\n" + + "But storage in plain text is not allowed.\nTo allow plain text passphrases caching, set \"store-ssl-client-cert-pp-plaintext\"=\"yes\"", MessageType.ERROR);*/ + return false; + } + } + catch (SVNException e) { + // should not occur, anyway means not allowed + } + } else { + try { + if (! isStorePlainTextPasswords(realm, auth)) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + Messages.showWarningDialog(myProject, "Your password for authentication realm:\n\n" + realm + + "\n\ncan only be stored to disk unencrypted. (Encryption is not supported)\n\n" + + "But storage in plain text is not allowed.\nTo allow plain text passwords caching, set \"store-plaintext-passwords\"=\"yes\"", + "Cannot save password"); + } + }); + /*ChangesViewBalloonProblemNotifier.showMe(myProject, "Your password for authentication realm:\n" + realm + + "\ncan only be stored to disk unencrypted! (Encryption is not supported)\n" + + "But storage in plain text is not allowed.\nTo allow plain text passwords caching, set \"store-plaintext-passwords\"=\"yes\"", MessageType.ERROR);*/ + return false; + } + } + catch (SVNException e) { + // + } + } + } + return true; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java index ca38d355f33d..14a891032fae 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java @@ -216,11 +216,11 @@ public class SvnConfiguration implements ProjectComponent, JDOMExternalizable { return myOptions; } - public ISVNAuthenticationManager getAuthenticationManager(final SvnVcs svnVcs) { + public SvnAuthenticationManager getAuthenticationManager(final SvnVcs svnVcs) { if (myAuthManager == null) { // reloaded when configuration directory changes myAuthManager = new SvnAuthenticationManager(myProject, new File(getConfigurationDirectory())); - myAuthManager.setAuthenticationProvider(new SvnAuthenticationProvider(svnVcs)); + myAuthManager.setAuthenticationProvider(new SvnAuthenticationProvider(svnVcs, myInteractiveManager)); myAuthManager.setRuntimeStorage(RUNTIME_AUTH_CACHE); } return myAuthManager; @@ -234,11 +234,11 @@ public class SvnConfiguration implements ProjectComponent, JDOMExternalizable { return myPassiveAuthManager; } - public ISVNAuthenticationManager getInteractiveManager(final SvnVcs svnVcs) { + public SvnAuthenticationManager getInteractiveManager(final SvnVcs svnVcs) { if (myInteractiveManager == null) { myInteractiveManager = new SvnAuthenticationManager(myProject, new File(getConfigurationDirectory())); myInteractiveManager.setRuntimeStorage(RUNTIME_AUTH_CACHE); - myInteractiveManager.setAuthenticationProvider(new SvnInteractiveAuthenticationProvider(svnVcs)); + myInteractiveManager.setAuthenticationProvider(new SvnInteractiveAuthenticationProvider(svnVcs, myInteractiveManager)); } return myInteractiveManager; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnAuthenticationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnAuthenticationProvider.java index dac18ccb01c1..850d8f524f46 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnAuthenticationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnAuthenticationProvider.java @@ -20,14 +20,16 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.ui.GuiUtils; import com.intellij.util.SystemProperties; +import org.jetbrains.idea.svn.SvnAuthenticationManager; import org.jetbrains.idea.svn.SvnAuthenticationNotifier; -import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.auth.*; +import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager; +import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider; +import org.tmatesoft.svn.core.auth.SVNAuthentication; +import org.tmatesoft.svn.core.auth.SVNUserNameAuthentication; -import java.io.File; import java.lang.reflect.InvocationTargetException; import java.security.cert.X509Certificate; @@ -40,10 +42,10 @@ public class SvnAuthenticationProvider implements ISVNAuthenticationProvider { private final SvnAuthenticationNotifier myAuthenticationNotifier; private final SvnInteractiveAuthenticationProvider mySvnInteractiveAuthenticationProvider; - public SvnAuthenticationProvider(final SvnVcs svnVcs) { + public SvnAuthenticationProvider(final SvnVcs svnVcs, final SvnAuthenticationManager manager) { myProject = svnVcs.getProject(); myAuthenticationNotifier = svnVcs.getAuthNotifier(); - mySvnInteractiveAuthenticationProvider = new SvnInteractiveAuthenticationProvider(svnVcs); + mySvnInteractiveAuthenticationProvider = new SvnInteractiveAuthenticationProvider(svnVcs, manager); } private void log(final String s) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnInteractiveAuthenticationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnInteractiveAuthenticationProvider.java index d5c4cca4fb9c..7670f272f76e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnInteractiveAuthenticationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnInteractiveAuthenticationProvider.java @@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.ui.GuiUtils; import com.intellij.util.SystemProperties; +import org.jetbrains.idea.svn.SvnAuthenticationManager; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnConfiguration; import org.jetbrains.idea.svn.SvnVcs; @@ -35,9 +36,11 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP private final Project myProject; private static final ThreadLocal myCallState = new ThreadLocal(); private final SvnVcs myVcs; + private final SvnAuthenticationManager myManager; - public SvnInteractiveAuthenticationProvider(final SvnVcs vcs) { + public SvnInteractiveAuthenticationProvider(final SvnVcs vcs, SvnAuthenticationManager manager) { myVcs = vcs; + myManager = manager; myProject = vcs.getProject(); } @@ -83,7 +86,7 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP } dialog.show(); if (dialog.isOK()) { - result[0] = new SVNPasswordAuthentication(dialog.getUserName(), dialog.getPassword(), dialog.isSaveAllowed()); + result[0] = new SVNPasswordAuthentication(dialog.getUserName(), dialog.getPassword(), dialog.isSaveAllowed(), url, false); } } }; @@ -104,7 +107,7 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP } dialog.show(); if (dialog.isOK()) { - result[0] = new SVNUserNameAuthentication(dialog.getUserName(), dialog.isSaveAllowed()); + result[0] = new SVNUserNameAuthentication(dialog.getUserName(), dialog.isSaveAllowed(), url, false); } } }; @@ -129,10 +132,11 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP passphrase = null; } result[0] = - new SVNSSHAuthentication(dialog.getUserName(), new File(dialog.getKeyFile()), passphrase, port, dialog.isSaveAllowed()); + new SVNSSHAuthentication(dialog.getUserName(), new File(dialog.getKeyFile()), passphrase, port, dialog.isSaveAllowed(), + url, false); } else { - result[0] = new SVNSSHAuthentication(dialog.getUserName(), dialog.getPassword(), port, dialog.isSaveAllowed()); + result[0] = new SVNSSHAuthentication(dialog.getUserName(), dialog.getPassword(), port, dialog.isSaveAllowed(), url, false); } } } @@ -150,7 +154,7 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP dialog.show(); if (dialog.isOK()) { result[0] = new SVNSSLAuthentication(new File(dialog.getCertificatePath()), String.valueOf(dialog.getCertificatePassword()), - dialog.getSaveAuth()); + dialog.getSaveAuth(), url, false); } } }; @@ -168,7 +172,11 @@ public class SvnInteractiveAuthenticationProvider implements ISVNAuthenticationP } log("3 authentication result: " + result[0]); } - callState.setWasCancelled(result[0] == null); + final boolean wasCanceled = result[0] == null; + callState.setWasCancelled(wasCanceled); + if ((! wasCanceled) && (ISVNAuthenticationManager.USERNAME != kind) && (result[0].isStorageAllowed())) { + myManager.checkContinueSaveCredentials(result[0], kind, realm); + } return result[0]; }