From 5cab0ecc95047d5d5c714b22724e5202c98e7509 Mon Sep 17 00:00:00 2001 From: Javier Domingo Cansino Date: Wed, 13 May 2015 17:43:59 +0200 Subject: [PATCH 1/4] ssh: AuthorizedKeysFile expands defined tokens --- salt/modules/ssh.py | 29 ++++++++++++++++++++++++++++- salt/states/ssh_auth.py | 8 ++++++-- tests/unit/modules/ssh_test.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 tests/unit/modules/ssh_test.py diff --git a/salt/modules/ssh.py b/salt/modules/ssh.py index ac45bd2ca2..1e4a9aae27 100644 --- a/salt/modules/ssh.py +++ b/salt/modules/ssh.py @@ -78,6 +78,31 @@ def _format_auth_line(key, enc, comment, options): return line +def _expand_authorized_keys_path(path, user, home): + ''' + Expand the AuthorizedKeysFile expression. Defined in man sshd_config(5) + ''' + converted_object = [] + had_escape = False + for char in path: + if had_escape: + had_escape = False + if char == '%': + converted_object.append('%') + elif char == 'u': + converted_object.append(user) + elif char == 'h': + converted_object.append(home) + else: + raise CommandExecutionError('Unknown token character ' + char) + continue + if char == '%': + had_escape = True + if had_escape: + raise CommandExecutionError("Last character can't be scape character") + return "".join(converted_object) + + def _get_config_file(user, config): ''' Get absolute path to a user's ssh_config. @@ -85,8 +110,10 @@ def _get_config_file(user, config): uinfo = __salt__['user.info'](user) if not uinfo: raise CommandExecutionError('User {0!r} does not exist'.format(user)) + home = uinfo['home'] if not os.path.isabs(config): - config = os.path.join(uinfo['home'], config) + config = os.path.join(home, config) + config = _expand_authorized_keys_path(config, user, home) return config diff --git a/salt/states/ssh_auth.py b/salt/states/ssh_auth.py index 0fa1b4aeef..842149812c 100644 --- a/salt/states/ssh_auth.py +++ b/salt/states/ssh_auth.py @@ -29,6 +29,7 @@ to use a YAML 'explicit key', as demonstrated in the second example below. ssh_auth.present: - user: root - source: salt://ssh_keys/thatch.id_rsa.pub + - config: %h/.ssh/authorized_keys sshkeys: ssh_auth.present: @@ -239,7 +240,8 @@ def present( config The location of the authorized keys file relative to the user's home - directory, defaults to ".ssh/authorized_keys" + directory, defaults to ".ssh/authorized_keys". Token expansion %u and + %h for username and home path supported. ''' ret = {'name': name, 'changes': {}, @@ -382,7 +384,9 @@ def absent(name, config The location of the authorized keys file relative to the user's home - directory, defaults to ".ssh/authorized_keys" + directory, defaults to ".ssh/authorized_keys". Token expansion %u and + %h for username and home path supported. + ''' ret = {'name': name, 'changes': {}, diff --git a/tests/unit/modules/ssh_test.py b/tests/unit/modules/ssh_test.py new file mode 100644 index 0000000000..086f8efd04 --- /dev/null +++ b/tests/unit/modules/ssh_test.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# import Python Libs +from __future__ import absolute_import + +# Import Salt Testing Libs +from salttesting import TestCase +from salttesting.helpers import ensure_in_syspath + +# Import Salt Libs +ensure_in_syspath('../../') +from salt.modules import ssh + + +class SSHAuthKeyPathTestCase(TestCase): + ''' + TestCase for salt.modules.ssh module's ssh AuthorizedKeysFile path + expansion + ''' + def test_expand_user_token(self): + ''' + Test if the %u token is correctly expanded + ''' + output = ssh._expand_authorized_keys_path('/home/%u', 'user', + '/home/user') + self.assertEqual(output, '/home/user') + + output = ssh._expand_authorized_keys_path('/home/%h', 'user', + '/home/user') + self.assertEqual(output, '/home//home/user') + + output = ssh._expand_authorized_keys_path('/srv/%h/aaa/%u%%', 'user', + '/home/user') + self.assertEqual(output, '/srv//home/user/aaa/user%') From 63620725c3a4c2035a48144614228c0dfa1170f7 Mon Sep 17 00:00:00 2001 From: Javier Domingo Date: Fri, 15 May 2015 13:00:11 +0200 Subject: [PATCH 2/4] Remove trailing whitespace --- tests/unit/modules/ssh_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/modules/ssh_test.py b/tests/unit/modules/ssh_test.py index 086f8efd04..ee80a7dff1 100644 --- a/tests/unit/modules/ssh_test.py +++ b/tests/unit/modules/ssh_test.py @@ -29,6 +29,6 @@ class SSHAuthKeyPathTestCase(TestCase): '/home/user') self.assertEqual(output, '/home//home/user') - output = ssh._expand_authorized_keys_path('/srv/%h/aaa/%u%%', 'user', + output = ssh._expand_authorized_keys_path('/srv/%h/aaa/%u%%', 'user', '/home/user') self.assertEqual(output, '/srv//home/user/aaa/user%') From 8766209ff78f7121b62cfc9c77f9c9ca4e464d82 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Fri, 15 May 2015 11:08:14 -0600 Subject: [PATCH 3/4] fix ssh AuthorizedKeysFile path processing --- salt/modules/ssh.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/salt/modules/ssh.py b/salt/modules/ssh.py index 1e4a9aae27..ecc7d462dd 100644 --- a/salt/modules/ssh.py +++ b/salt/modules/ssh.py @@ -82,25 +82,29 @@ def _expand_authorized_keys_path(path, user, home): ''' Expand the AuthorizedKeysFile expression. Defined in man sshd_config(5) ''' - converted_object = [] + converted_path = '' had_escape = False for char in path: if had_escape: had_escape = False if char == '%': - converted_object.append('%') + converted_path += '%' elif char == 'u': - converted_object.append(user) + converted_path += user elif char == 'h': - converted_object.append(home) + converted_path += home else: - raise CommandExecutionError('Unknown token character ' + char) + error = 'AuthorizedKeysFile path: unknown token character "%{0}"'.format(char) + raise CommandExecutionError(error) continue - if char == '%': + elif char == '%': had_escape = True + else: + converted_path += char if had_escape: - raise CommandExecutionError("Last character can't be scape character") - return "".join(converted_object) + error = "AuthorizedKeysFile path: Last character can't be escape character" + raise CommandExecutionError(error) + return converted_path def _get_config_file(user, config): From 87e000d05355541e07895d7ea37402105a65c903 Mon Sep 17 00:00:00 2001 From: Justin Findlay Date: Fri, 15 May 2015 11:11:29 -0600 Subject: [PATCH 4/4] fix ssh module unit tests --- tests/unit/modules/ssh_test.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/tests/unit/modules/ssh_test.py b/tests/unit/modules/ssh_test.py index ee80a7dff1..c2f1e2e7a7 100644 --- a/tests/unit/modules/ssh_test.py +++ b/tests/unit/modules/ssh_test.py @@ -4,22 +4,27 @@ from __future__ import absolute_import # Import Salt Testing Libs -from salttesting import TestCase +from salttesting import skipIf, TestCase from salttesting.helpers import ensure_in_syspath +from salttesting.mock import ( + NO_MOCK, + NO_MOCK_REASON +) # Import Salt Libs ensure_in_syspath('../../') from salt.modules import ssh +from salt.exceptions import CommandExecutionError -class SSHAuthKeyPathTestCase(TestCase): +@skipIf(NO_MOCK, NO_MOCK_REASON) +class SSHAuthKeyTestCase(TestCase): ''' - TestCase for salt.modules.ssh module's ssh AuthorizedKeysFile path - expansion + TestCase for salt.modules.ssh ''' def test_expand_user_token(self): ''' - Test if the %u token is correctly expanded + Test if the %u, %h, and %% tokens are correctly expanded ''' output = ssh._expand_authorized_keys_path('/home/%u', 'user', '/home/user') @@ -32,3 +37,16 @@ class SSHAuthKeyPathTestCase(TestCase): output = ssh._expand_authorized_keys_path('/srv/%h/aaa/%u%%', 'user', '/home/user') self.assertEqual(output, '/srv//home/user/aaa/user%') + + user = 'dude' + home = '/home/dude' + path = '/home/dude%' + self.assertRaises(CommandExecutionError, ssh._expand_authorized_keys_path, path, user, home) + + path = '/home/%dude' + self.assertRaises(CommandExecutionError, ssh._expand_authorized_keys_path, path, user, home) + + +if __name__ == '__main__': + from integration import run_tests + run_tests(SSHAuthKeyTestCase, needs_daemon=False)