{"thread":{"id":"15553","subject":"[JGIT PATCH 2/2] Add support for ~/.ssh/config BatchMode","startedAt":"2008-09-16T15:44:28Z","lastAt":"2008-09-16T22:52:09Z","messageCount":4,"participants":["Shawn O. Pearce","Robin Rosenberg"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"90841","messageId":"1221579869-27835-1-git-send-email-spearce@spearce.org","threadId":"15553","inReplyTo":null,"subject":"[JGIT PATCH 1/2 v2] Add support for ~/.ssh/config PreferredAuthentications","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-16T15:44:28Z","receivedAt":"2008-09-16T15:44:28Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Some configurations may wish to disable interactive methods of\nauthentication, such as when running from automated cron or batch\nstyle jobs that have no user available.\n\nTypically in an OpenSSH based system this would be configured on a\nper-host basis in the current user's ~/.ssh/config file, by setting\nPreferredAuthentications to the list of authentication methods\n(e.g. just \"publickey\") that are reasonable.\n\nJSch honors this configuration setting, but we need to transfer it\nfrom our own OpenSshConfig class, otherwise it has no knowledge of\nthe setting.\n\nhttp://code.google.com/p/egit/issues/detail?id=33\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n\n This replaces my earlier patch of the same title from about 14\n hours ago.  This v2 patch actually parses the data from the\n config file and includes unit tests to verify it is parsing.\n\n .../spearce/egit/ui/EclipseSshSessionFactory.java  |    4 +++\n .../spearce/jgit/transport/OpenSshConfigTest.java  |   22 ++++++++++++++++-\n .../jgit/transport/DefaultSshSessionFactory.java   |    4 +++\n .../org/spearce/jgit/transport/OpenSshConfig.java  |   25 ++++++++++++++++++++\n 4 files changed, 54 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseSshSessionFactory.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseSshSessionFactory.java\nindex 640a165..67c5f16 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseSshSessionFactory.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseSshSessionFactory.java\n@@ -50,6 +50,10 @@ public Session getSession(String user, String pass, String host, int port)\n \t\t\tsession.setPassword(pass);\n \t\telse\n \t\t\tnew UserInfoPrompter(session);\n+\n+\t\tfinal String pauth = hc.getPreferredAuthentications();\n+\t\tif (pauth != null)\n+\t\t\tsession.setConfig(\"PreferredAuthentications\", pauth);\n \t\treturn session;\n \t}\n \ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/OpenSshConfigTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/OpenSshConfigTest.java\nindex a250f9d..1a71d08 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/OpenSshConfigTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/OpenSshConfigTest.java\n@@ -103,7 +103,6 @@ config(\"Host orcz\\n\" + \"\\tHostName repo.or.cz\\n\" + \"\\tPort 2222\\n\"\n \t\tassertEquals(new File(home, \".ssh/id_jex\"), h.getIdentityFile());\n \t}\n \n-\n \tpublic void testAlias_OptionsKeywordCaseInsensitive() throws Exception {\n \t\tconfig(\"hOsT orcz\\n\" + \"\\thOsTnAmE repo.or.cz\\n\" + \"\\tPORT 2222\\n\"\n \t\t\t\t+ \"\\tuser jex\\n\" + \"\\tidentityfile .ssh/id_jex\\n\"\n@@ -128,4 +127,25 @@ config(\"Host orcz\\n\" + \"\\tHostName repo.or.cz\\n\" + \"\\n\" + \"Host *\\n\"\n \t\tassertEquals(2222, h.getPort());\n \t\tassertEquals(new File(home, \".ssh/id_jex\"), h.getIdentityFile());\n \t}\n+\n+\tpublic void testAlias_PreferredAuthenticationsDefault() throws Exception {\n+\t\tfinal Host h = osc.lookup(\"orcz\");\n+\t\tassertNotNull(h);\n+\t\tassertNull(h.getPreferredAuthentications());\n+\t}\n+\n+\tpublic void testAlias_PreferredAuthentications() throws Exception {\n+\t\tconfig(\"Host orcz\\n\" + \"\\tPreferredAuthentications publickey\\n\");\n+\t\tfinal Host h = osc.lookup(\"orcz\");\n+\t\tassertNotNull(h);\n+\t\tassertEquals(\"publickey\", h.getPreferredAuthentications());\n+\t}\n+\n+\tpublic void testAlias_InheritPreferredAuthentications() throws Exception {\n+\t\tconfig(\"Host orcz\\n\" + \"\\tHostName repo.or.cz\\n\" + \"\\n\" + \"Host *\\n\"\n+\t\t\t\t+ \"\\tPreferredAuthentications publickey, hostbased\\n\");\n+\t\tfinal Host h = osc.lookup(\"orcz\");\n+\t\tassertNotNull(h);\n+\t\tassertEquals(\"publickey,hostbased\", h.getPreferredAuthentications());\n+\t}\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/DefaultSshSessionFactory.java b/org.spearce.jgit/src/org/spearce/jgit/transport/DefaultSshSessionFactory.java\nindex 74fca66..b6f58f0 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/DefaultSshSessionFactory.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/DefaultSshSessionFactory.java\n@@ -103,6 +103,10 @@ public synchronized Session getSession(String user, String pass,\n \t\t\tsession.setPassword(pass);\n \t\telse\n \t\t\tsession.setUserInfo(new AWT_UserInfo());\n+\n+\t\tfinal String pauth = hc.getPreferredAuthentications();\n+\t\tif (pauth != null)\n+\t\t\tsession.setConfig(\"PreferredAuthentications\", pauth);\n \t\treturn session;\n \t}\n \ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/OpenSshConfig.java b/org.spearce.jgit/src/org/spearce/jgit/transport/OpenSshConfig.java\nindex cf7c388..2f41e56 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/OpenSshConfig.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/OpenSshConfig.java\n@@ -220,6 +220,10 @@ else if (sp < 0)\n \t\t\t\tfor (final Host c : current)\n \t\t\t\t\tif (c.identityFile == null)\n \t\t\t\t\t\tc.identityFile = toFile(dequote(argValue));\n+\t\t\t} else if (\"PreferredAuthentications\".equalsIgnoreCase(keyword)) {\n+\t\t\t\tfor (final Host c : current)\n+\t\t\t\t\tif (c.preferredAuthentications == null)\n+\t\t\t\t\t\tc.preferredAuthentications = nows(dequote(argValue));\n \t\t\t}\n \t\t}\n \n@@ -247,6 +251,15 @@ private static String dequote(final String value) {\n \t\treturn value;\n \t}\n \n+\tprivate static String nows(final String value) {\n+\t\tfinal StringBuilder b = new StringBuilder();\n+\t\tfor (int i = 0; i < value.length(); i++) {\n+\t\t\tif (!Character.isSpaceChar(value.charAt(i)))\n+\t\t\t\tb.append(value.charAt(i));\n+\t\t}\n+\t\treturn b.toString();\n+\t}\n+\n \tprivate File toFile(final String path) {\n \t\tif (path.startsWith(\"~/\"))\n \t\t\treturn new File(home, path.substring(2));\n@@ -278,6 +291,8 @@ private File toFile(final String path) {\n \n \t\tString user;\n \n+\t\tString preferredAuthentications;\n+\n \t\tvoid copyFrom(final Host src) {\n \t\t\tif (hostName == null)\n \t\t\t\thostName = src.hostName;\n@@ -287,6 +302,8 @@ void copyFrom(final Host src) {\n \t\t\t\tidentityFile = src.identityFile;\n \t\t\tif (user == null)\n \t\t\t\tuser = src.user;\n+\t\t\tif (preferredAuthentications == null)\n+\t\t\t\tpreferredAuthentications = src.preferredAuthentications;\n \t\t}\n \n \t\t/**\n@@ -317,5 +334,13 @@ public File getIdentityFile() {\n \t\tpublic String getUser() {\n \t\t\treturn user;\n \t\t}\n+\n+\t\t/**\n+\t\t * @return the preferred authentication methods, separated by commas if\n+\t\t *         more than one authentication method is preferred.\n+\t\t */\n+\t\tpublic String getPreferredAuthentications() {\n+\t\t\treturn preferredAuthentications;\n+\t\t}\n \t}\n }\n-- \n1.6.0.2.389.g421e0\n"},{"id":"90840","messageId":"1221579869-27835-2-git-send-email-spearce@spearce.org","threadId":"15553","inReplyTo":"1221579869-27835-1-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 2/2] Add support for ~/.ssh/config BatchMode","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-16T15:44:29Z","receivedAt":"2008-09-16T15:44:29Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Connections created through batch processes (e.g. those started by\ncron) don't have a terminal to interact with a user through.  A\ncommon way to disable password prompting with OpenSSH is to setup\na Host block in ~/.ssh/config with \"BatchMode yes\" enabled, thus\ntelling the client not to prompt for passphases or passwords.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../spearce/egit/ui/EclipseSshSessionFactory.java  |    2 +-\n .../spearce/jgit/transport/OpenSshConfigTest.java  |   21 +++++++++++++++++++\n .../jgit/transport/DefaultSshSessionFactory.java   |    2 +-\n .../org/spearce/jgit/transport/OpenSshConfig.java  |   22 ++++++++++++++++++++\n 4 files changed, 45 insertions(+), 2 deletions(-)\n\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseSshSessionFactory.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseSshSessionFactory.java\nindex 67c5f16..098d234 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseSshSessionFactory.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseSshSessionFactory.java\n@@ -48,7 +48,7 @@ public Session getSession(String user, String pass, String host, int port)\n \t\t\taddIdentity(hc.getIdentityFile());\n \t\tif (pass != null)\n \t\t\tsession.setPassword(pass);\n-\t\telse\n+\t\telse if (!hc.isBatchMode())\n \t\t\tnew UserInfoPrompter(session);\n \n \t\tfinal String pauth = hc.getPreferredAuthentications();\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/OpenSshConfigTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/OpenSshConfigTest.java\nindex 1a71d08..959b6b7 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/OpenSshConfigTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/OpenSshConfigTest.java\n@@ -148,4 +148,25 @@ config(\"Host orcz\\n\" + \"\\tHostName repo.or.cz\\n\" + \"\\n\" + \"Host *\\n\"\n \t\tassertNotNull(h);\n \t\tassertEquals(\"publickey,hostbased\", h.getPreferredAuthentications());\n \t}\n+\n+\tpublic void testAlias_BatchModeDefault() throws Exception {\n+\t\tfinal Host h = osc.lookup(\"orcz\");\n+\t\tassertNotNull(h);\n+\t\tassertEquals(false, h.isBatchMode());\n+\t}\n+\n+\tpublic void testAlias_BatchModeYes() throws Exception {\n+\t\tconfig(\"Host orcz\\n\" + \"\\tBatchMode yes\\n\");\n+\t\tfinal Host h = osc.lookup(\"orcz\");\n+\t\tassertNotNull(h);\n+\t\tassertEquals(true, h.isBatchMode());\n+\t}\n+\n+\tpublic void testAlias_InheritBatchMode() throws Exception {\n+\t\tconfig(\"Host orcz\\n\" + \"\\tHostName repo.or.cz\\n\" + \"\\n\" + \"Host *\\n\"\n+\t\t\t\t+ \"\\tBatchMode yes\\n\");\n+\t\tfinal Host h = osc.lookup(\"orcz\");\n+\t\tassertNotNull(h);\n+\t\tassertEquals(true, h.isBatchMode());\n+\t}\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/DefaultSshSessionFactory.java b/org.spearce.jgit/src/org/spearce/jgit/transport/DefaultSshSessionFactory.java\nindex b6f58f0..89beab7 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/DefaultSshSessionFactory.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/DefaultSshSessionFactory.java\n@@ -101,7 +101,7 @@ public synchronized Session getSession(String user, String pass,\n \t\t\taddIdentity(hc.getIdentityFile());\n \t\tif (pass != null)\n \t\t\tsession.setPassword(pass);\n-\t\telse\n+\t\telse if (!hc.isBatchMode())\n \t\t\tsession.setUserInfo(new AWT_UserInfo());\n \n \t\tfinal String pauth = hc.getPreferredAuthentications();\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/OpenSshConfig.java b/org.spearce.jgit/src/org/spearce/jgit/transport/OpenSshConfig.java\nindex 2f41e56..df38e18 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/OpenSshConfig.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/OpenSshConfig.java\n@@ -224,6 +224,10 @@ else if (sp < 0)\n \t\t\t\tfor (final Host c : current)\n \t\t\t\t\tif (c.preferredAuthentications == null)\n \t\t\t\t\t\tc.preferredAuthentications = nows(dequote(argValue));\n+\t\t\t} else if (\"BatchMode\".equalsIgnoreCase(keyword)) {\n+\t\t\t\tfor (final Host c : current)\n+\t\t\t\t\tif (c.batchMode == null)\n+\t\t\t\t\t\tc.batchMode = yesno(dequote(argValue));\n \t\t\t}\n \t\t}\n \n@@ -260,6 +264,12 @@ private static String nows(final String value) {\n \t\treturn b.toString();\n \t}\n \n+\tprivate static Boolean yesno(final String value) {\n+\t\tif (\"yes\".equalsIgnoreCase(value))\n+\t\t\treturn Boolean.TRUE;\n+\t\treturn Boolean.FALSE;\n+\t}\n+\n \tprivate File toFile(final String path) {\n \t\tif (path.startsWith(\"~/\"))\n \t\t\treturn new File(home, path.substring(2));\n@@ -293,6 +303,8 @@ private File toFile(final String path) {\n \n \t\tString preferredAuthentications;\n \n+\t\tBoolean batchMode;\n+\n \t\tvoid copyFrom(final Host src) {\n \t\t\tif (hostName == null)\n \t\t\t\thostName = src.hostName;\n@@ -304,6 +316,8 @@ void copyFrom(final Host src) {\n \t\t\t\tuser = src.user;\n \t\t\tif (preferredAuthentications == null)\n \t\t\t\tpreferredAuthentications = src.preferredAuthentications;\n+\t\t\tif (batchMode == null)\n+\t\t\t\tbatchMode = src.batchMode;\n \t\t}\n \n \t\t/**\n@@ -342,5 +356,13 @@ public String getUser() {\n \t\tpublic String getPreferredAuthentications() {\n \t\t\treturn preferredAuthentications;\n \t\t}\n+\n+\t\t/**\n+\t\t * @return true if batch (non-interactive) mode is preferred for this\n+\t\t *         host connection.\n+\t\t */\n+\t\tpublic boolean isBatchMode() {\n+\t\t\treturn batchMode != null && batchMode.booleanValue();\n+\t\t}\n \t}\n }\n-- \n1.6.0.2.389.g421e0\n"},{"id":"90869","messageId":"200809170046.31859.robin.rosenberg@dewire.com","threadId":"15553","inReplyTo":"1221579869-27835-2-git-send-email-spearce@spearce.org","subject":"Re: [JGIT PATCH 2/2] Add support for ~/.ssh/config BatchMode","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2008-09-16T22:46:31Z","receivedAt":"2008-09-16T22:46:31Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"tisdagen den 16 september 2008 17.44.29 skrev Shawn O. Pearce:\n> Connections created through batch processes (e.g. those started by\n> cron) don't have a terminal to interact with a user through.  A\n> common way to disable password prompting with OpenSSH is to setup\n> a Host block in ~/.ssh/config with \"BatchMode yes\" enabled, thus\n> telling the client not to prompt for passphases or passwords.\n\nThat did not work when any of the identities in  ~/.ssh matched. Though\nI specifically told jgit to use an identity that should not work, it found another\nthat did. During setup all identities are loaded and made available to JSch.\n\nThat bug is not related to this code (so I pushed it) other than it made it tricky\nto test. OpenSSH only tries the identity I tell it to, or default  if not told.\n\n-- robin\n"},{"id":"90870","messageId":"20080916225209.GC22021@spearce.org","threadId":"15553","inReplyTo":"200809170046.31859.robin.rosenberg@dewire.com","subject":"Re: [JGIT PATCH 2/2] Add support for ~/.ssh/config BatchMode","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-09-16T22:52:09Z","receivedAt":"2008-09-16T22:52:09Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Robin Rosenberg <robin.rosenberg@dewire.com> wrote:\n> tisdagen den 16 september 2008 17.44.29 skrev Shawn O. Pearce:\n> > Connections created through batch processes (e.g. those started by\n> > cron) don't have a terminal to interact with a user through.  A\n> > common way to disable password prompting with OpenSSH is to setup\n> > a Host block in ~/.ssh/config with \"BatchMode yes\" enabled, thus\n> > telling the client not to prompt for passphases or passwords.\n> \n> That did not work when any of the identities in  ~/.ssh matched. Though\n> I specifically told jgit to use an identity that should not work, it found another\n> that did. During setup all identities are loaded and made available to JSch.\n\nYes, that's a known bug.\n \n> That bug is not related to this code (so I pushed it) other than it made it tricky\n> to test. OpenSSH only tries the identity I tell it to, or default  if not told.\n\nI have a plan on how to fix it.  I just didn't find the time today\nto actually implement it.  I'll put an issue on the issue tracker\nwith my thoughts on how IdentityFile can be implemented correctly.\nIf I don't get to it this week maybe someone else can, it looks\npretty simple on the surface.\n\n-- \nShawn.\n"}]}