08c715
From 3b68aff3b7b1dc567ef6721a269c2d4e054b729f Mon Sep 17 00:00:00 2001
08c715
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
08c715
Date: Mon, 9 Aug 2021 23:41:44 +0200
08c715
Subject: [PATCH] Stop copying ssh system keys and check folder permissions
08c715
 (#956)
08c715
08c715
RH-Author: Emanuele Giuseppe Esposito <eesposit@redhat.com>
08c715
RH-MergeRequest: 28: Stop copying ssh system keys and check folder permissions (#956)
08c715
RH-Commit: [1/1] 7cada613be82f2f525ee56b86ef9f71edf40d2ef (eesposit/cloud-init)
08c715
RH-Bugzilla: 1862967
08c715
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
08c715
RH-Acked-by: Eduardo Otubo <otubo@redhat.com>
08c715
08c715
TESTED: By me and QA
08c715
BREW: 38818284
08c715
08c715
This is a continuation of previous MR 25 and upstream PR #937.
08c715
There were still issues when using non-standard file paths like
08c715
/etc/ssh/userkeys/%u or /etc/ssh/authorized_keys, and the choice
08c715
of storing the keys of all authorized_keys files into a single
08c715
one was not ideal. This fix modifies cloudinit to support
08c715
all different cases of authorized_keys file locations, and
08c715
picks a user-specific file where to copy the new keys that
08c715
complies with ssh permissions.
08c715
08c715
commit 00dbaf1e9ab0e59d81662f0f3561897bef499a3f
08c715
Author: Emanuele Giuseppe Esposito <eesposit@redhat.com>
08c715
Date:   Mon Aug 9 16:49:56 2021 +0200
08c715
08c715
    Stop copying ssh system keys and check folder permissions (#956)
08c715
08c715
    In /etc/ssh/sshd_config, it is possible to define a custom
08c715
    authorized_keys file that will contain the keys allowed to access the
08c715
    machine via the AuthorizedKeysFile option. Cloudinit is able to add
08c715
    user-specific keys to the existing ones, but we need to be careful on
08c715
    which of the authorized_keys files listed to pick.
08c715
    Chosing a file that is shared by all user will cause security
08c715
    issues, because the owner of that key can then access also other users.
08c715
08c715
    We therefore pick an authorized_keys file only if it satisfies the
08c715
    following conditions:
08c715
    1. it is not a "global" file, ie it must be defined in
08c715
       AuthorizedKeysFile with %u, %h or be in  /home/<user>. This avoids
08c715
       security issues.
08c715
    2. it must comply with ssh permission requirements, otherwise the ssh
08c715
       agent won't use that file.
08c715
08c715
    If it doesn't meet either of those conditions, write to
08c715
    ~/.ssh/authorized_keys
08c715
08c715
    We also need to consider the case when the chosen authorized_keys file
08c715
    does not exist. In this case, the existing behavior of cloud-init is
08c715
    to create the new file. We therefore need to be sure that the file
08c715
    complies with ssh permissions too, by setting:
08c715
    - the actual file to permission 600, and owned by the user
08c715
    - the directories in the path that do not exist must be root owned and
08c715
      with permission 755.
08c715
08c715
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
08c715
---
08c715
 cloudinit/ssh_util.py           | 133 ++++-
08c715
 cloudinit/util.py               |  51 +-
08c715
 tests/unittests/test_sshutil.py | 952 +++++++++++++++++++++++++-------
08c715
 3 files changed, 920 insertions(+), 216 deletions(-)
08c715
08c715
diff --git a/cloudinit/ssh_util.py b/cloudinit/ssh_util.py
08c715
index 89057262..b8a3c8f7 100644
08c715
--- a/cloudinit/ssh_util.py
08c715
+++ b/cloudinit/ssh_util.py
08c715
@@ -249,6 +249,113 @@ def render_authorizedkeysfile_paths(value, homedir, username):
08c715
     return rendered
08c715
 
08c715
 
08c715
+# Inspired from safe_path() in openssh source code (misc.c).
08c715
+def check_permissions(username, current_path, full_path, is_file, strictmodes):
08c715
+    """Check if the file/folder in @current_path has the right permissions.
08c715
+
08c715
+    We need to check that:
08c715
+    1. If StrictMode is enabled, the owner is either root or the user
08c715
+    2. the user can access the file/folder, otherwise ssh won't use it
08c715
+    3. If StrictMode is enabled, no write permission is given to group
08c715
+       and world users (022)
08c715
+    """
08c715
+
08c715
+    # group/world can only execute the folder (access)
08c715
+    minimal_permissions = 0o711
08c715
+    if is_file:
08c715
+        # group/world can only read the file
08c715
+        minimal_permissions = 0o644
08c715
+
08c715
+    # 1. owner must be either root or the user itself
08c715
+    owner = util.get_owner(current_path)
08c715
+    if strictmodes and owner != username and owner != "root":
08c715
+        LOG.debug("Path %s in %s must be own by user %s or"
08c715
+                  " by root, but instead is own by %s. Ignoring key.",
08c715
+                  current_path, full_path, username, owner)
08c715
+        return False
08c715
+
08c715
+    parent_permission = util.get_permissions(current_path)
08c715
+    # 2. the user can access the file/folder, otherwise ssh won't use it
08c715
+    if owner == username:
08c715
+        # need only the owner permissions
08c715
+        minimal_permissions &= 0o700
08c715
+    else:
08c715
+        group_owner = util.get_group(current_path)
08c715
+        user_groups = util.get_user_groups(username)
08c715
+
08c715
+        if group_owner in user_groups:
08c715
+            # need only the group permissions
08c715
+            minimal_permissions &= 0o070
08c715
+        else:
08c715
+            # need only the world permissions
08c715
+            minimal_permissions &= 0o007
08c715
+
08c715
+    if parent_permission & minimal_permissions == 0:
08c715
+        LOG.debug("Path %s in %s must be accessible by user %s,"
08c715
+                  " check its permissions",
08c715
+                  current_path, full_path, username)
08c715
+        return False
08c715
+
08c715
+    # 3. no write permission (w) is given to group and world users (022)
08c715
+    # Group and world user can still have +rx.
08c715
+    if strictmodes and parent_permission & 0o022 != 0:
08c715
+        LOG.debug("Path %s in %s must not give write"
08c715
+                  "permission to group or world users. Ignoring key.",
08c715
+                  current_path, full_path)
08c715
+        return False
08c715
+
08c715
+    return True
08c715
+
08c715
+
08c715
+def check_create_path(username, filename, strictmodes):
08c715
+    user_pwent = users_ssh_info(username)[1]
08c715
+    root_pwent = users_ssh_info("root")[1]
08c715
+    try:
08c715
+        # check the directories first
08c715
+        directories = filename.split("/")[1:-1]
08c715
+
08c715
+        # scan in order, from root to file name
08c715
+        parent_folder = ""
08c715
+        # this is to comply also with unit tests, and
08c715
+        # strange home directories
08c715
+        home_folder = os.path.dirname(user_pwent.pw_dir)
08c715
+        for directory in directories:
08c715
+            parent_folder += "/" + directory
08c715
+            if home_folder.startswith(parent_folder):
08c715
+                continue
08c715
+
08c715
+            if not os.path.isdir(parent_folder):
08c715
+                # directory does not exist, and permission so far are good:
08c715
+                # create the directory, and make it accessible by everyone
08c715
+                # but owned by root, as it might be used by many users.
08c715
+                with util.SeLinuxGuard(parent_folder):
08c715
+                    os.makedirs(parent_folder, mode=0o755, exist_ok=True)
08c715
+                    util.chownbyid(parent_folder, root_pwent.pw_uid,
08c715
+                                   root_pwent.pw_gid)
08c715
+
08c715
+            permissions = check_permissions(username, parent_folder,
08c715
+                                            filename, False, strictmodes)
08c715
+            if not permissions:
08c715
+                return False
08c715
+
08c715
+        # check the file
08c715
+        if not os.path.exists(filename):
08c715
+            # if file does not exist: we need to create it, since the
08c715
+            # folders at this point exist and have right permissions
08c715
+            util.write_file(filename, '', mode=0o600, ensure_dir_exists=True)
08c715
+            util.chownbyid(filename, user_pwent.pw_uid, user_pwent.pw_gid)
08c715
+
08c715
+        permissions = check_permissions(username, filename,
08c715
+                                        filename, True, strictmodes)
08c715
+        if not permissions:
08c715
+            return False
08c715
+    except (IOError, OSError) as e:
08c715
+        util.logexc(LOG, str(e))
08c715
+        return False
08c715
+
08c715
+    return True
08c715
+
08c715
+
08c715
 def extract_authorized_keys(username, sshd_cfg_file=DEF_SSHD_CFG):
08c715
     (ssh_dir, pw_ent) = users_ssh_info(username)
08c715
     default_authorizedkeys_file = os.path.join(ssh_dir, 'authorized_keys')
08c715
@@ -259,6 +366,7 @@ def extract_authorized_keys(username, sshd_cfg_file=DEF_SSHD_CFG):
08c715
             ssh_cfg = parse_ssh_config_map(sshd_cfg_file)
08c715
             key_paths = ssh_cfg.get("authorizedkeysfile",
08c715
                                     "%h/.ssh/authorized_keys")
08c715
+            strictmodes = ssh_cfg.get("strictmodes", "yes")
08c715
             auth_key_fns = render_authorizedkeysfile_paths(
08c715
                 key_paths, pw_ent.pw_dir, username)
08c715
 
08c715
@@ -269,31 +377,31 @@ def extract_authorized_keys(username, sshd_cfg_file=DEF_SSHD_CFG):
08c715
                         "config from %r, using 'AuthorizedKeysFile' file "
08c715
                         "%r instead", DEF_SSHD_CFG, auth_key_fns[0])
08c715
 
08c715
-    # check if one of the keys is the user's one
08c715
+    # check if one of the keys is the user's one and has the right permissions
08c715
     for key_path, auth_key_fn in zip(key_paths.split(), auth_key_fns):
08c715
         if any([
08c715
             '%u' in key_path,
08c715
             '%h' in key_path,
08c715
             auth_key_fn.startswith('{}/'.format(pw_ent.pw_dir))
08c715
         ]):
08c715
-            user_authorizedkeys_file = auth_key_fn
08c715
+            permissions_ok = check_create_path(username, auth_key_fn,
08c715
+                                               strictmodes == "yes")
08c715
+            if permissions_ok:
08c715
+                user_authorizedkeys_file = auth_key_fn
08c715
+                break
08c715
 
08c715
     if user_authorizedkeys_file != default_authorizedkeys_file:
08c715
         LOG.debug(
08c715
             "AuthorizedKeysFile has an user-specific authorized_keys, "
08c715
             "using %s", user_authorizedkeys_file)
08c715
 
08c715
-    # always store all the keys in the user's private file
08c715
-    return (user_authorizedkeys_file, parse_authorized_keys(auth_key_fns))
08c715
+    return (
08c715
+        user_authorizedkeys_file,
08c715
+        parse_authorized_keys([user_authorizedkeys_file])
08c715
+    )
08c715
 
08c715
 
08c715
 def setup_user_keys(keys, username, options=None):
08c715
-    # Make sure the users .ssh dir is setup accordingly
08c715
-    (ssh_dir, pwent) = users_ssh_info(username)
08c715
-    if not os.path.isdir(ssh_dir):
08c715
-        util.ensure_dir(ssh_dir, mode=0o700)
08c715
-        util.chownbyid(ssh_dir, pwent.pw_uid, pwent.pw_gid)
08c715
-
08c715
     # Turn the 'update' keys given into actual entries
08c715
     parser = AuthKeyLineParser()
08c715
     key_entries = []
08c715
@@ -302,11 +410,10 @@ def setup_user_keys(keys, username, options=None):
08c715
 
08c715
     # Extract the old and make the new
08c715
     (auth_key_fn, auth_key_entries) = extract_authorized_keys(username)
08c715
+    ssh_dir = os.path.dirname(auth_key_fn)
08c715
     with util.SeLinuxGuard(ssh_dir, recursive=True):
08c715
         content = update_authorized_keys(auth_key_entries, key_entries)
08c715
-        util.ensure_dir(os.path.dirname(auth_key_fn), mode=0o700)
08c715
-        util.write_file(auth_key_fn, content, mode=0o600)
08c715
-        util.chownbyid(auth_key_fn, pwent.pw_uid, pwent.pw_gid)
08c715
+        util.write_file(auth_key_fn, content, preserve_mode=True)
08c715
 
08c715
 
08c715
 class SshdConfigLine(object):
08c715
diff --git a/cloudinit/util.py b/cloudinit/util.py
08c715
index 4e0a72db..343976ad 100644
08c715
--- a/cloudinit/util.py
08c715
+++ b/cloudinit/util.py
08c715
@@ -35,6 +35,7 @@ from base64 import b64decode, b64encode
08c715
 from errno import ENOENT
08c715
 from functools import lru_cache
08c715
 from urllib import parse
08c715
+from typing import List
08c715
 
08c715
 from cloudinit import importer
08c715
 from cloudinit import log as logging
08c715
@@ -1830,6 +1831,53 @@ def chmod(path, mode):
08c715
             os.chmod(path, real_mode)
08c715
 
08c715
 
08c715
+def get_permissions(path: str) -> int:
08c715
+    """
08c715
+    Returns the octal permissions of the file/folder pointed by the path,
08c715
+    encoded as an int.
08c715
+
08c715
+    @param path: The full path of the file/folder.
08c715
+    """
08c715
+
08c715
+    return stat.S_IMODE(os.stat(path).st_mode)
08c715
+
08c715
+
08c715
+def get_owner(path: str) -> str:
08c715
+    """
08c715
+    Returns the owner of the file/folder pointed by the path.
08c715
+
08c715
+    @param path: The full path of the file/folder.
08c715
+    """
08c715
+    st = os.stat(path)
08c715
+    return pwd.getpwuid(st.st_uid).pw_name
08c715
+
08c715
+
08c715
+def get_group(path: str) -> str:
08c715
+    """
08c715
+    Returns the group of the file/folder pointed by the path.
08c715
+
08c715
+    @param path: The full path of the file/folder.
08c715
+    """
08c715
+    st = os.stat(path)
08c715
+    return grp.getgrgid(st.st_gid).gr_name
08c715
+
08c715
+
08c715
+def get_user_groups(username: str) -> List[str]:
08c715
+    """
08c715
+    Returns a list of all groups to which the user belongs
08c715
+
08c715
+    @param username: the user we want to check
08c715
+    """
08c715
+    groups = []
08c715
+    for group in grp.getgrall():
08c715
+        if username in group.gr_mem:
08c715
+            groups.append(group.gr_name)
08c715
+
08c715
+    gid = pwd.getpwnam(username).pw_gid
08c715
+    groups.append(grp.getgrgid(gid).gr_name)
08c715
+    return groups
08c715
+
08c715
+
08c715
 def write_file(
08c715
     filename,
08c715
     content,
08c715
@@ -1856,8 +1904,7 @@ def write_file(
08c715
 
08c715
     if preserve_mode:
08c715
         try:
08c715
-            file_stat = os.stat(filename)
08c715
-            mode = stat.S_IMODE(file_stat.st_mode)
08c715
+            mode = get_permissions(filename)
08c715
         except OSError:
08c715
             pass
08c715
 
08c715
diff --git a/tests/unittests/test_sshutil.py b/tests/unittests/test_sshutil.py
08c715
index bcb8044f..a66788bf 100644
08c715
--- a/tests/unittests/test_sshutil.py
08c715
+++ b/tests/unittests/test_sshutil.py
08c715
@@ -1,6 +1,9 @@
08c715
 # This file is part of cloud-init. See LICENSE file for license information.
08c715
 
08c715
+import os
08c715
+
08c715
 from collections import namedtuple
08c715
+from functools import partial
08c715
 from unittest.mock import patch
08c715
 
08c715
 from cloudinit import ssh_util
08c715
@@ -8,13 +11,48 @@ from cloudinit.tests import helpers as test_helpers
08c715
 from cloudinit import util
08c715
 
08c715
 # https://stackoverflow.com/questions/11351032/
08c715
-FakePwEnt = namedtuple(
08c715
-    'FakePwEnt',
08c715
-    ['pw_dir', 'pw_gecos', 'pw_name', 'pw_passwd', 'pw_shell', 'pwd_uid'])
08c715
+FakePwEnt = namedtuple('FakePwEnt', [
08c715
+    'pw_name',
08c715
+    'pw_passwd',
08c715
+    'pw_uid',
08c715
+    'pw_gid',
08c715
+    'pw_gecos',
08c715
+    'pw_dir',
08c715
+    'pw_shell',
08c715
+])
08c715
 FakePwEnt.__new__.__defaults__ = tuple(
08c715
     "UNSET_%s" % n for n in FakePwEnt._fields)
08c715
 
08c715
 
08c715
+def mock_get_owner(updated_permissions, value):
08c715
+    try:
08c715
+        return updated_permissions[value][0]
08c715
+    except ValueError:
08c715
+        return util.get_owner(value)
08c715
+
08c715
+
08c715
+def mock_get_group(updated_permissions, value):
08c715
+    try:
08c715
+        return updated_permissions[value][1]
08c715
+    except ValueError:
08c715
+        return util.get_group(value)
08c715
+
08c715
+
08c715
+def mock_get_user_groups(username):
08c715
+    return username
08c715
+
08c715
+
08c715
+def mock_get_permissions(updated_permissions, value):
08c715
+    try:
08c715
+        return updated_permissions[value][2]
08c715
+    except ValueError:
08c715
+        return util.get_permissions(value)
08c715
+
08c715
+
08c715
+def mock_getpwnam(users, username):
08c715
+    return users[username]
08c715
+
08c715
+
08c715
 # Do not use these public keys, most of them are fetched from
08c715
 # the testdata for OpenSSH, and their private keys are available
08c715
 # https://github.com/openssh/openssh-portable/tree/master/regress/unittests/sshkey/testdata
08c715
@@ -552,12 +590,30 @@ class TestBasicAuthorizedKeyParse(test_helpers.CiTestCase):
08c715
             ssh_util.render_authorizedkeysfile_paths(
08c715
                 "/opt/%u/keys", "/home/bobby", "bobby"))
08c715
 
08c715
+    def test_user_file(self):
08c715
+        self.assertEqual(
08c715
+            ["/opt/bobby"],
08c715
+            ssh_util.render_authorizedkeysfile_paths(
08c715
+                "/opt/%u", "/home/bobby", "bobby"))
08c715
+
08c715
+    def test_user_file2(self):
08c715
+        self.assertEqual(
08c715
+            ["/opt/bobby/bobby"],
08c715
+            ssh_util.render_authorizedkeysfile_paths(
08c715
+                "/opt/%u/%u", "/home/bobby", "bobby"))
08c715
+
08c715
     def test_multiple(self):
08c715
         self.assertEqual(
08c715
             ["/keys/path1", "/keys/path2"],
08c715
             ssh_util.render_authorizedkeysfile_paths(
08c715
                 "/keys/path1 /keys/path2", "/home/bobby", "bobby"))
08c715
 
08c715
+    def test_multiple2(self):
08c715
+        self.assertEqual(
08c715
+            ["/keys/path1", "/keys/bobby"],
08c715
+            ssh_util.render_authorizedkeysfile_paths(
08c715
+                "/keys/path1 /keys/%u", "/home/bobby", "bobby"))
08c715
+
08c715
     def test_relative(self):
08c715
         self.assertEqual(
08c715
             ["/home/bobby/.secret/keys"],
08c715
@@ -581,269 +637,763 @@ class TestBasicAuthorizedKeyParse(test_helpers.CiTestCase):
08c715
 
08c715
 class TestMultipleSshAuthorizedKeysFile(test_helpers.CiTestCase):
08c715
 
08c715
-    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
-    def test_multiple_authorizedkeys_file_order1(self, m_getpwnam):
08c715
-        fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
08c715
-        m_getpwnam.return_value = fpw
08c715
-        user_ssh_folder = "%s/.ssh" % fpw.pw_dir
08c715
-
08c715
-        # /tmp/home2/bobby/.ssh/authorized_keys = rsa
08c715
-        authorized_keys = self.tmp_path('authorized_keys', dir=user_ssh_folder)
08c715
-        util.write_file(authorized_keys, VALID_CONTENT['rsa'])
08c715
-
08c715
-        # /tmp/home2/bobby/.ssh/user_keys = dsa
08c715
-        user_keys = self.tmp_path('user_keys', dir=user_ssh_folder)
08c715
-        util.write_file(user_keys, VALID_CONTENT['dsa'])
08c715
-
08c715
-        # /tmp/sshd_config
08c715
+    def create_fake_users(self, names, mock_permissions,
08c715
+                          m_get_group, m_get_owner, m_get_permissions,
08c715
+                          m_getpwnam, users):
08c715
+        homes = []
08c715
+
08c715
+        root = '/tmp/root'
08c715
+        fpw = FakePwEnt(pw_name="root", pw_dir=root)
08c715
+        users["root"] = fpw
08c715
+
08c715
+        for name in names:
08c715
+            home = '/tmp/home/' + name
08c715
+            fpw = FakePwEnt(pw_name=name, pw_dir=home)
08c715
+            users[name] = fpw
08c715
+            homes.append(home)
08c715
+
08c715
+        m_get_permissions.side_effect = partial(
08c715
+            mock_get_permissions, mock_permissions)
08c715
+        m_get_owner.side_effect = partial(mock_get_owner, mock_permissions)
08c715
+        m_get_group.side_effect = partial(mock_get_group, mock_permissions)
08c715
+        m_getpwnam.side_effect = partial(mock_getpwnam, users)
08c715
+        return homes
08c715
+
08c715
+    def create_user_authorized_file(self, home, filename, content_key, keys):
08c715
+        user_ssh_folder = "%s/.ssh" % home
08c715
+        # /tmp/home/<user>/.ssh/authorized_keys = content_key
08c715
+        authorized_keys = self.tmp_path(filename, dir=user_ssh_folder)
08c715
+        util.write_file(authorized_keys, VALID_CONTENT[content_key])
08c715
+        keys[authorized_keys] = content_key
08c715
+        return authorized_keys
08c715
+
08c715
+    def create_global_authorized_file(self, filename, content_key, keys):
08c715
+        authorized_keys = self.tmp_path(filename, dir='/tmp')
08c715
+        util.write_file(authorized_keys, VALID_CONTENT[content_key])
08c715
+        keys[authorized_keys] = content_key
08c715
+        return authorized_keys
08c715
+
08c715
+    def create_sshd_config(self, authorized_keys_files):
08c715
         sshd_config = self.tmp_path('sshd_config', dir="/tmp")
08c715
         util.write_file(
08c715
             sshd_config,
08c715
-            "AuthorizedKeysFile %s %s" % (authorized_keys, user_keys)
08c715
+            "AuthorizedKeysFile " + authorized_keys_files
08c715
         )
08c715
+        return sshd_config
08c715
 
08c715
+    def execute_and_check(self, user, sshd_config, solution, keys,
08c715
+                          delete_keys=True):
08c715
         (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
08c715
-            fpw.pw_name, sshd_config)
08c715
+            user, sshd_config)
08c715
         content = ssh_util.update_authorized_keys(auth_key_entries, [])
08c715
 
08c715
-        self.assertEqual(user_keys, auth_key_fn)
08c715
-        self.assertTrue(VALID_CONTENT['rsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['dsa'] in content)
08c715
+        self.assertEqual(auth_key_fn, solution)
08c715
+        for path, key in keys.items():
08c715
+            if path == solution:
08c715
+                self.assertTrue(VALID_CONTENT[key] in content)
08c715
+            else:
08c715
+                self.assertFalse(VALID_CONTENT[key] in content)
08c715
+
08c715
+        if delete_keys and os.path.isdir("/tmp/home/"):
08c715
+            util.delete_dir_contents("/tmp/home/")
08c715
 
08c715
     @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
-    def test_multiple_authorizedkeys_file_order2(self, m_getpwnam):
08c715
-        fpw = FakePwEnt(pw_name='suzie', pw_dir='/tmp/home/suzie')
08c715
-        m_getpwnam.return_value = fpw
08c715
-        user_ssh_folder = "%s/.ssh" % fpw.pw_dir
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_single_user_two_local_files(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam
08c715
+    ):
08c715
+        user_bobby = 'bobby'
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/user_keys': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+        }
08c715
+
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby], mock_permissions, m_get_group, m_get_owner,
08c715
+            m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        home = homes[0]
08c715
 
08c715
-        # /tmp/home/suzie/.ssh/authorized_keys = rsa
08c715
-        authorized_keys = self.tmp_path('authorized_keys', dir=user_ssh_folder)
08c715
-        util.write_file(authorized_keys, VALID_CONTENT['rsa'])
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home, 'authorized_keys', 'rsa', keys
08c715
+        )
08c715
 
08c715
-        # /tmp/home/suzie/.ssh/user_keys = dsa
08c715
-        user_keys = self.tmp_path('user_keys', dir=user_ssh_folder)
08c715
-        util.write_file(user_keys, VALID_CONTENT['dsa'])
08c715
+        # /tmp/home/bobby/.ssh/user_keys = dsa
08c715
+        user_keys = self.create_user_authorized_file(
08c715
+            home, 'user_keys', 'dsa', keys
08c715
+        )
08c715
 
08c715
         # /tmp/sshd_config
08c715
-        sshd_config = self.tmp_path('sshd_config', dir="/tmp")
08c715
-        util.write_file(
08c715
-            sshd_config,
08c715
-            "AuthorizedKeysFile %s %s" % (user_keys, authorized_keys)
08c715
+        options = "%s %s" % (authorized_keys, user_keys)
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        self.execute_and_check(user_bobby, sshd_config, authorized_keys, keys)
08c715
+
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_single_user_two_local_files_inverted(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam
08c715
+    ):
08c715
+        user_bobby = 'bobby'
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/user_keys': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+        }
08c715
+
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby], mock_permissions, m_get_group, m_get_owner,
08c715
+            m_get_permissions, m_getpwnam, users
08c715
         )
08c715
+        home = homes[0]
08c715
 
08c715
-        (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
08c715
-            fpw.pw_name, sshd_config)
08c715
-        content = ssh_util.update_authorized_keys(auth_key_entries, [])
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home, 'authorized_keys', 'rsa', keys
08c715
+        )
08c715
 
08c715
-        self.assertEqual(authorized_keys, auth_key_fn)
08c715
-        self.assertTrue(VALID_CONTENT['rsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['dsa'] in content)
08c715
+        # /tmp/home/bobby/.ssh/user_keys = dsa
08c715
+        user_keys = self.create_user_authorized_file(
08c715
+            home, 'user_keys', 'dsa', keys
08c715
+        )
08c715
 
08c715
-    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
-    def test_multiple_authorizedkeys_file_local_global(self, m_getpwnam):
08c715
-        fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
08c715
-        m_getpwnam.return_value = fpw
08c715
-        user_ssh_folder = "%s/.ssh" % fpw.pw_dir
08c715
+        # /tmp/sshd_config
08c715
+        options = "%s %s" % (user_keys, authorized_keys)
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
 
08c715
-        # /tmp/home2/bobby/.ssh/authorized_keys = rsa
08c715
-        authorized_keys = self.tmp_path('authorized_keys', dir=user_ssh_folder)
08c715
-        util.write_file(authorized_keys, VALID_CONTENT['rsa'])
08c715
+        self.execute_and_check(user_bobby, sshd_config, user_keys, keys)
08c715
 
08c715
-        # /tmp/home2/bobby/.ssh/user_keys = dsa
08c715
-        user_keys = self.tmp_path('user_keys', dir=user_ssh_folder)
08c715
-        util.write_file(user_keys, VALID_CONTENT['dsa'])
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_single_user_local_global_files(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam
08c715
+    ):
08c715
+        user_bobby = 'bobby'
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/user_keys': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+        }
08c715
+
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby], mock_permissions, m_get_group, m_get_owner,
08c715
+            m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        home = homes[0]
08c715
 
08c715
-        # /tmp/etc/ssh/authorized_keys = ecdsa
08c715
-        authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys',
08c715
-                                               dir="/tmp")
08c715
-        util.write_file(authorized_keys_global, VALID_CONTENT['ecdsa'])
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home, 'authorized_keys', 'rsa', keys
08c715
+        )
08c715
 
08c715
-        # /tmp/sshd_config
08c715
-        sshd_config = self.tmp_path('sshd_config', dir="/tmp")
08c715
-        util.write_file(
08c715
-            sshd_config,
08c715
-            "AuthorizedKeysFile %s %s %s" % (authorized_keys_global,
08c715
-                                             user_keys, authorized_keys)
08c715
+        # /tmp/home/bobby/.ssh/user_keys = dsa
08c715
+        user_keys = self.create_user_authorized_file(
08c715
+            home, 'user_keys', 'dsa', keys
08c715
         )
08c715
 
08c715
-        (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
08c715
-            fpw.pw_name, sshd_config)
08c715
-        content = ssh_util.update_authorized_keys(auth_key_entries, [])
08c715
+        authorized_keys_global = self.create_global_authorized_file(
08c715
+            'etc/ssh/authorized_keys', 'ecdsa', keys
08c715
+        )
08c715
 
08c715
-        self.assertEqual(authorized_keys, auth_key_fn)
08c715
-        self.assertTrue(VALID_CONTENT['rsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['ecdsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['dsa'] in content)
08c715
+        options = "%s %s %s" % (authorized_keys_global, user_keys,
08c715
+                                authorized_keys)
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
 
08c715
-    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
-    def test_multiple_authorizedkeys_file_local_global2(self, m_getpwnam):
08c715
-        fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
08c715
-        m_getpwnam.return_value = fpw
08c715
-        user_ssh_folder = "%s/.ssh" % fpw.pw_dir
08c715
+        self.execute_and_check(user_bobby, sshd_config, user_keys, keys)
08c715
 
08c715
-        # /tmp/home2/bobby/.ssh/authorized_keys2 = rsa
08c715
-        authorized_keys = self.tmp_path('authorized_keys2',
08c715
-                                        dir=user_ssh_folder)
08c715
-        util.write_file(authorized_keys, VALID_CONTENT['rsa'])
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_single_user_local_global_files_inverted(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam
08c715
+    ):
08c715
+        user_bobby = 'bobby'
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/user_keys3': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys2': ('bobby', 'bobby', 0o600),
08c715
+        }
08c715
+
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby], mock_permissions, m_get_group, m_get_owner,
08c715
+            m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        home = homes[0]
08c715
 
08c715
-        # /tmp/home2/bobby/.ssh/user_keys3 = dsa
08c715
-        user_keys = self.tmp_path('user_keys3', dir=user_ssh_folder)
08c715
-        util.write_file(user_keys, VALID_CONTENT['dsa'])
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home, 'authorized_keys2', 'rsa', keys
08c715
+        )
08c715
 
08c715
-        # /tmp/etc/ssh/authorized_keys = ecdsa
08c715
-        authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys',
08c715
-                                               dir="/tmp")
08c715
-        util.write_file(authorized_keys_global, VALID_CONTENT['ecdsa'])
08c715
+        # /tmp/home/bobby/.ssh/user_keys = dsa
08c715
+        user_keys = self.create_user_authorized_file(
08c715
+            home, 'user_keys3', 'dsa', keys
08c715
+        )
08c715
 
08c715
-        # /tmp/sshd_config
08c715
-        sshd_config = self.tmp_path('sshd_config', dir="/tmp")
08c715
-        util.write_file(
08c715
-            sshd_config,
08c715
-            "AuthorizedKeysFile %s %s %s" % (authorized_keys_global,
08c715
-                                             authorized_keys, user_keys)
08c715
+        authorized_keys_global = self.create_global_authorized_file(
08c715
+            'etc/ssh/authorized_keys', 'ecdsa', keys
08c715
         )
08c715
 
08c715
-        (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
08c715
-            fpw.pw_name, sshd_config)
08c715
-        content = ssh_util.update_authorized_keys(auth_key_entries, [])
08c715
+        options = "%s %s %s" % (authorized_keys_global, authorized_keys,
08c715
+                                user_keys)
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
 
08c715
-        self.assertEqual(user_keys, auth_key_fn)
08c715
-        self.assertTrue(VALID_CONTENT['rsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['ecdsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['dsa'] in content)
08c715
+        self.execute_and_check(user_bobby, sshd_config, authorized_keys, keys)
08c715
 
08c715
     @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
-    def test_multiple_authorizedkeys_file_global(self, m_getpwnam):
08c715
-        fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
08c715
-        m_getpwnam.return_value = fpw
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_single_user_global_file(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam
08c715
+    ):
08c715
+        user_bobby = 'bobby'
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+        }
08c715
+
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby], mock_permissions, m_get_group, m_get_owner,
08c715
+            m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        home = homes[0]
08c715
 
08c715
         # /tmp/etc/ssh/authorized_keys = rsa
08c715
-        authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys',
08c715
-                                               dir="/tmp")
08c715
-        util.write_file(authorized_keys_global, VALID_CONTENT['rsa'])
08c715
+        authorized_keys_global = self.create_global_authorized_file(
08c715
+            'etc/ssh/authorized_keys', 'rsa', keys
08c715
+        )
08c715
 
08c715
-        # /tmp/sshd_config
08c715
-        sshd_config = self.tmp_path('sshd_config')
08c715
-        util.write_file(
08c715
-            sshd_config,
08c715
-            "AuthorizedKeysFile %s" % (authorized_keys_global)
08c715
+        options = "%s" % authorized_keys_global
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        default = "%s/.ssh/authorized_keys" % home
08c715
+        self.execute_and_check(user_bobby, sshd_config, default, keys)
08c715
+
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_two_users_local_file_standard(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam
08c715
+    ):
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/suzie': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh/authorized_keys': ('suzie', 'suzie', 0o600),
08c715
+        }
08c715
+
08c715
+        user_bobby = 'bobby'
08c715
+        user_suzie = 'suzie'
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby, user_suzie], mock_permissions, m_get_group,
08c715
+            m_get_owner, m_get_permissions, m_getpwnam, users
08c715
         )
08c715
+        home_bobby = homes[0]
08c715
+        home_suzie = homes[1]
08c715
 
08c715
-        (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
08c715
-            fpw.pw_name, sshd_config)
08c715
-        content = ssh_util.update_authorized_keys(auth_key_entries, [])
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home_bobby, 'authorized_keys', 'rsa', keys
08c715
+        )
08c715
 
08c715
-        self.assertEqual("%s/.ssh/authorized_keys" % fpw.pw_dir, auth_key_fn)
08c715
-        self.assertTrue(VALID_CONTENT['rsa'] in content)
08c715
+        # /tmp/home/suzie/.ssh/authorized_keys = rsa
08c715
+        authorized_keys2 = self.create_user_authorized_file(
08c715
+            home_suzie, 'authorized_keys', 'ssh-xmss@openssh.com', keys
08c715
+        )
08c715
+
08c715
+        options = ".ssh/authorized_keys"
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        self.execute_and_check(
08c715
+            user_bobby, sshd_config, authorized_keys, keys, delete_keys=False
08c715
+        )
08c715
+        self.execute_and_check(user_suzie, sshd_config, authorized_keys2, keys)
08c715
 
08c715
     @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
-    def test_multiple_authorizedkeys_file_multiuser(self, m_getpwnam):
08c715
-        fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home2/bobby')
08c715
-        m_getpwnam.return_value = fpw
08c715
-        user_ssh_folder = "%s/.ssh" % fpw.pw_dir
08c715
-        # /tmp/home2/bobby/.ssh/authorized_keys2 = rsa
08c715
-        authorized_keys = self.tmp_path('authorized_keys2',
08c715
-                                        dir=user_ssh_folder)
08c715
-        util.write_file(authorized_keys, VALID_CONTENT['rsa'])
08c715
-        # /tmp/home2/bobby/.ssh/user_keys3 = dsa
08c715
-        user_keys = self.tmp_path('user_keys3', dir=user_ssh_folder)
08c715
-        util.write_file(user_keys, VALID_CONTENT['dsa'])
08c715
-
08c715
-        fpw2 = FakePwEnt(pw_name='suzie', pw_dir='/tmp/home/suzie')
08c715
-        user_ssh_folder = "%s/.ssh" % fpw2.pw_dir
08c715
-        # /tmp/home/suzie/.ssh/authorized_keys2 = ssh-xmss@openssh.com
08c715
-        authorized_keys2 = self.tmp_path('authorized_keys2',
08c715
-                                         dir=user_ssh_folder)
08c715
-        util.write_file(authorized_keys2,
08c715
-                        VALID_CONTENT['ssh-xmss@openssh.com'])
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_two_users_local_file_custom(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam
08c715
+    ):
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys2': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/suzie': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh/authorized_keys2': ('suzie', 'suzie', 0o600),
08c715
+        }
08c715
+
08c715
+        user_bobby = 'bobby'
08c715
+        user_suzie = 'suzie'
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby, user_suzie], mock_permissions, m_get_group,
08c715
+            m_get_owner, m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        home_bobby = homes[0]
08c715
+        home_suzie = homes[1]
08c715
 
08c715
-        # /tmp/etc/ssh/authorized_keys = ecdsa
08c715
-        authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys2',
08c715
-                                               dir="/tmp")
08c715
-        util.write_file(authorized_keys_global, VALID_CONTENT['ecdsa'])
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys2 = rsa
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home_bobby, 'authorized_keys2', 'rsa', keys
08c715
+        )
08c715
 
08c715
-        # /tmp/sshd_config
08c715
-        sshd_config = self.tmp_path('sshd_config', dir="/tmp")
08c715
-        util.write_file(
08c715
-            sshd_config,
08c715
-            "AuthorizedKeysFile %s %%h/.ssh/authorized_keys2 %s" %
08c715
-            (authorized_keys_global, user_keys)
08c715
+        # /tmp/home/suzie/.ssh/authorized_keys2 = rsa
08c715
+        authorized_keys2 = self.create_user_authorized_file(
08c715
+            home_suzie, 'authorized_keys2', 'ssh-xmss@openssh.com', keys
08c715
         )
08c715
 
08c715
-        # process first user
08c715
-        (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
08c715
-            fpw.pw_name, sshd_config)
08c715
-        content = ssh_util.update_authorized_keys(auth_key_entries, [])
08c715
+        options = ".ssh/authorized_keys2"
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        self.execute_and_check(
08c715
+            user_bobby, sshd_config, authorized_keys, keys, delete_keys=False
08c715
+        )
08c715
+        self.execute_and_check(user_suzie, sshd_config, authorized_keys2, keys)
08c715
 
08c715
-        self.assertEqual(user_keys, auth_key_fn)
08c715
-        self.assertTrue(VALID_CONTENT['rsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['ecdsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['dsa'] in content)
08c715
-        self.assertFalse(VALID_CONTENT['ssh-xmss@openssh.com'] in content)
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_two_users_local_global_files(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam
08c715
+    ):
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys2': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/bobby/.ssh/user_keys3': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/suzie': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh/authorized_keys2': ('suzie', 'suzie', 0o600),
08c715
+            '/tmp/home/suzie/.ssh/user_keys3': ('suzie', 'suzie', 0o600),
08c715
+        }
08c715
+
08c715
+        user_bobby = 'bobby'
08c715
+        user_suzie = 'suzie'
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby, user_suzie], mock_permissions, m_get_group,
08c715
+            m_get_owner, m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        home_bobby = homes[0]
08c715
+        home_suzie = homes[1]
08c715
 
08c715
-        m_getpwnam.return_value = fpw2
08c715
-        # process second user
08c715
-        (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
08c715
-            fpw2.pw_name, sshd_config)
08c715
-        content = ssh_util.update_authorized_keys(auth_key_entries, [])
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys2 = rsa
08c715
+        self.create_user_authorized_file(
08c715
+            home_bobby, 'authorized_keys2', 'rsa', keys
08c715
+        )
08c715
+        # /tmp/home/bobby/.ssh/user_keys3 = dsa
08c715
+        user_keys = self.create_user_authorized_file(
08c715
+            home_bobby, 'user_keys3', 'dsa', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/home/suzie/.ssh/authorized_keys2 = rsa
08c715
+        authorized_keys2 = self.create_user_authorized_file(
08c715
+            home_suzie, 'authorized_keys2', 'ssh-xmss@openssh.com', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/etc/ssh/authorized_keys = ecdsa
08c715
+        authorized_keys_global = self.create_global_authorized_file(
08c715
+            'etc/ssh/authorized_keys2', 'ecdsa', keys
08c715
+        )
08c715
+
08c715
+        options = "%s %s %%h/.ssh/authorized_keys2" % \
08c715
+            (authorized_keys_global, user_keys)
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
 
08c715
-        self.assertEqual(authorized_keys2, auth_key_fn)
08c715
-        self.assertTrue(VALID_CONTENT['ssh-xmss@openssh.com'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['ecdsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['dsa'] in content)
08c715
-        self.assertFalse(VALID_CONTENT['rsa'] in content)
08c715
+        self.execute_and_check(
08c715
+            user_bobby, sshd_config, user_keys, keys, delete_keys=False
08c715
+        )
08c715
+        self.execute_and_check(user_suzie, sshd_config, authorized_keys2, keys)
08c715
 
08c715
+    @patch("cloudinit.util.get_user_groups")
08c715
     @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
-    def test_multiple_authorizedkeys_file_multiuser2(self, m_getpwnam):
08c715
-        fpw = FakePwEnt(pw_name='bobby', pw_dir='/tmp/home/bobby')
08c715
-        m_getpwnam.return_value = fpw
08c715
-        user_ssh_folder = "%s/.ssh" % fpw.pw_dir
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_two_users_local_global_files_badguy(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam,
08c715
+        m_get_user_groups
08c715
+    ):
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys2': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/bobby/.ssh/user_keys3': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/home/badguy': ('root', 'root', 0o755),
08c715
+            '/tmp/home/badguy/home': ('root', 'root', 0o755),
08c715
+            '/tmp/home/badguy/home/bobby': ('root', 'root', 0o655),
08c715
+        }
08c715
+
08c715
+        user_bobby = 'bobby'
08c715
+        user_badguy = 'badguy'
08c715
+        home_bobby, *_ = self.create_fake_users(
08c715
+            [user_bobby, user_badguy], mock_permissions, m_get_group,
08c715
+            m_get_owner, m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        m_get_user_groups.side_effect = mock_get_user_groups
08c715
+
08c715
         # /tmp/home/bobby/.ssh/authorized_keys2 = rsa
08c715
-        authorized_keys = self.tmp_path('authorized_keys2',
08c715
-                                        dir=user_ssh_folder)
08c715
-        util.write_file(authorized_keys, VALID_CONTENT['rsa'])
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home_bobby, 'authorized_keys2', 'rsa', keys
08c715
+        )
08c715
         # /tmp/home/bobby/.ssh/user_keys3 = dsa
08c715
-        user_keys = self.tmp_path('user_keys3', dir=user_ssh_folder)
08c715
-        util.write_file(user_keys, VALID_CONTENT['dsa'])
08c715
+        user_keys = self.create_user_authorized_file(
08c715
+            home_bobby, 'user_keys3', 'dsa', keys
08c715
+        )
08c715
 
08c715
-        fpw2 = FakePwEnt(pw_name='badguy', pw_dir='/tmp/home/badguy')
08c715
-        user_ssh_folder = "%s/.ssh" % fpw2.pw_dir
08c715
         # /tmp/home/badguy/home/bobby = ""
08c715
         authorized_keys2 = self.tmp_path('home/bobby', dir="/tmp/home/badguy")
08c715
+        util.write_file(authorized_keys2, '')
08c715
 
08c715
         # /tmp/etc/ssh/authorized_keys = ecdsa
08c715
-        authorized_keys_global = self.tmp_path('etc/ssh/authorized_keys2',
08c715
-                                               dir="/tmp")
08c715
-        util.write_file(authorized_keys_global, VALID_CONTENT['ecdsa'])
08c715
+        authorized_keys_global = self.create_global_authorized_file(
08c715
+            'etc/ssh/authorized_keys2', 'ecdsa', keys
08c715
+        )
08c715
 
08c715
         # /tmp/sshd_config
08c715
-        sshd_config = self.tmp_path('sshd_config', dir="/tmp")
08c715
-        util.write_file(
08c715
-            sshd_config,
08c715
-            "AuthorizedKeysFile %s %%h/.ssh/authorized_keys2 %s %s" %
08c715
-            (authorized_keys_global, user_keys, authorized_keys2)
08c715
+        options = "%s %%h/.ssh/authorized_keys2 %s %s" % \
08c715
+            (authorized_keys2, authorized_keys_global, user_keys)
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        self.execute_and_check(
08c715
+            user_bobby, sshd_config, authorized_keys, keys, delete_keys=False
08c715
+        )
08c715
+        self.execute_and_check(
08c715
+            user_badguy, sshd_config, authorized_keys2, keys
08c715
         )
08c715
 
08c715
-        # process first user
08c715
-        (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
08c715
-            fpw.pw_name, sshd_config)
08c715
-        content = ssh_util.update_authorized_keys(auth_key_entries, [])
08c715
+    @patch("cloudinit.util.get_user_groups")
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_two_users_unaccessible_file(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam,
08c715
+        m_get_user_groups
08c715
+    ):
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+
08c715
+            '/tmp/etc': ('root', 'root', 0o755),
08c715
+            '/tmp/etc/ssh': ('root', 'root', 0o755),
08c715
+            '/tmp/etc/ssh/userkeys': ('root', 'root', 0o700),
08c715
+            '/tmp/etc/ssh/userkeys/bobby': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/etc/ssh/userkeys/badguy': ('badguy', 'badguy', 0o600),
08c715
+
08c715
+            '/tmp/home/badguy': ('badguy', 'badguy', 0o700),
08c715
+            '/tmp/home/badguy/.ssh': ('badguy', 'badguy', 0o700),
08c715
+            '/tmp/home/badguy/.ssh/authorized_keys':
08c715
+                ('badguy', 'badguy', 0o600),
08c715
+        }
08c715
+
08c715
+        user_bobby = 'bobby'
08c715
+        user_badguy = 'badguy'
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby, user_badguy], mock_permissions, m_get_group,
08c715
+            m_get_owner, m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        m_get_user_groups.side_effect = mock_get_user_groups
08c715
+        home_bobby = homes[0]
08c715
+        home_badguy = homes[1]
08c715
 
08c715
-        self.assertEqual(user_keys, auth_key_fn)
08c715
-        self.assertTrue(VALID_CONTENT['rsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['ecdsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['dsa'] in content)
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home_bobby, 'authorized_keys', 'rsa', keys
08c715
+        )
08c715
+        # /tmp/etc/ssh/userkeys/bobby = dsa
08c715
+        # assume here that we can bypass userkeys, despite permissions
08c715
+        self.create_global_authorized_file(
08c715
+            'etc/ssh/userkeys/bobby', 'dsa', keys
08c715
+        )
08c715
 
08c715
-        m_getpwnam.return_value = fpw2
08c715
-        # process second user
08c715
-        (auth_key_fn, auth_key_entries) = ssh_util.extract_authorized_keys(
08c715
-            fpw2.pw_name, sshd_config)
08c715
-        content = ssh_util.update_authorized_keys(auth_key_entries, [])
08c715
+        # /tmp/home/badguy/.ssh/authorized_keys = ssh-xmss@openssh.com
08c715
+        authorized_keys2 = self.create_user_authorized_file(
08c715
+            home_badguy, 'authorized_keys', 'ssh-xmss@openssh.com', keys
08c715
+        )
08c715
 
08c715
-        # badguy should not take the key from the other user!
08c715
-        self.assertEqual(authorized_keys2, auth_key_fn)
08c715
-        self.assertTrue(VALID_CONTENT['ecdsa'] in content)
08c715
-        self.assertTrue(VALID_CONTENT['dsa'] in content)
08c715
-        self.assertFalse(VALID_CONTENT['rsa'] in content)
08c715
+        # /tmp/etc/ssh/userkeys/badguy = ecdsa
08c715
+        self.create_global_authorized_file(
08c715
+            'etc/ssh/userkeys/badguy', 'ecdsa', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/sshd_config
08c715
+        options = "/tmp/etc/ssh/userkeys/%u .ssh/authorized_keys"
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        self.execute_and_check(
08c715
+            user_bobby, sshd_config, authorized_keys, keys, delete_keys=False
08c715
+        )
08c715
+        self.execute_and_check(
08c715
+            user_badguy, sshd_config, authorized_keys2, keys
08c715
+        )
08c715
+
08c715
+    @patch("cloudinit.util.get_user_groups")
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_two_users_accessible_file(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam,
08c715
+        m_get_user_groups
08c715
+    ):
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+
08c715
+            '/tmp/etc': ('root', 'root', 0o755),
08c715
+            '/tmp/etc/ssh': ('root', 'root', 0o755),
08c715
+            '/tmp/etc/ssh/userkeys': ('root', 'root', 0o755),
08c715
+            '/tmp/etc/ssh/userkeys/bobby': ('bobby', 'bobby', 0o600),
08c715
+            '/tmp/etc/ssh/userkeys/badguy': ('badguy', 'badguy', 0o600),
08c715
+
08c715
+            '/tmp/home/badguy': ('badguy', 'badguy', 0o700),
08c715
+            '/tmp/home/badguy/.ssh': ('badguy', 'badguy', 0o700),
08c715
+            '/tmp/home/badguy/.ssh/authorized_keys':
08c715
+                ('badguy', 'badguy', 0o600),
08c715
+        }
08c715
+
08c715
+        user_bobby = 'bobby'
08c715
+        user_badguy = 'badguy'
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby, user_badguy], mock_permissions, m_get_group,
08c715
+            m_get_owner, m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        m_get_user_groups.side_effect = mock_get_user_groups
08c715
+        home_bobby = homes[0]
08c715
+        home_badguy = homes[1]
08c715
+
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        self.create_user_authorized_file(
08c715
+            home_bobby, 'authorized_keys', 'rsa', keys
08c715
+        )
08c715
+        # /tmp/etc/ssh/userkeys/bobby = dsa
08c715
+        # assume here that we can bypass userkeys, despite permissions
08c715
+        authorized_keys = self.create_global_authorized_file(
08c715
+            'etc/ssh/userkeys/bobby', 'dsa', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/home/badguy/.ssh/authorized_keys = ssh-xmss@openssh.com
08c715
+        self.create_user_authorized_file(
08c715
+            home_badguy, 'authorized_keys', 'ssh-xmss@openssh.com', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/etc/ssh/userkeys/badguy = ecdsa
08c715
+        authorized_keys2 = self.create_global_authorized_file(
08c715
+            'etc/ssh/userkeys/badguy', 'ecdsa', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/sshd_config
08c715
+        options = "/tmp/etc/ssh/userkeys/%u .ssh/authorized_keys"
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        self.execute_and_check(
08c715
+            user_bobby, sshd_config, authorized_keys, keys, delete_keys=False
08c715
+        )
08c715
+        self.execute_and_check(
08c715
+            user_badguy, sshd_config, authorized_keys2, keys
08c715
+        )
08c715
+
08c715
+    @patch("cloudinit.util.get_user_groups")
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_two_users_hardcoded_single_user_file(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam,
08c715
+        m_get_user_groups
08c715
+    ):
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+
08c715
+            '/tmp/home/suzie': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh/authorized_keys': ('suzie', 'suzie', 0o600),
08c715
+        }
08c715
+
08c715
+        user_bobby = 'bobby'
08c715
+        user_suzie = 'suzie'
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby, user_suzie], mock_permissions, m_get_group,
08c715
+            m_get_owner, m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        home_bobby = homes[0]
08c715
+        home_suzie = homes[1]
08c715
+        m_get_user_groups.side_effect = mock_get_user_groups
08c715
+
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home_bobby, 'authorized_keys', 'rsa', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/home/suzie/.ssh/authorized_keys = ssh-xmss@openssh.com
08c715
+        self.create_user_authorized_file(
08c715
+            home_suzie, 'authorized_keys', 'ssh-xmss@openssh.com', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/sshd_config
08c715
+        options = "%s" % (authorized_keys)
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        self.execute_and_check(
08c715
+            user_bobby, sshd_config, authorized_keys, keys, delete_keys=False
08c715
+        )
08c715
+        default = "%s/.ssh/authorized_keys" % home_suzie
08c715
+        self.execute_and_check(user_suzie, sshd_config, default, keys)
08c715
+
08c715
+    @patch("cloudinit.util.get_user_groups")
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_two_users_hardcoded_single_user_file_inverted(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam,
08c715
+        m_get_user_groups
08c715
+    ):
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+
08c715
+            '/tmp/home/suzie': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh/authorized_keys': ('suzie', 'suzie', 0o600),
08c715
+        }
08c715
+
08c715
+        user_bobby = 'bobby'
08c715
+        user_suzie = 'suzie'
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby, user_suzie], mock_permissions, m_get_group,
08c715
+            m_get_owner, m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        home_bobby = homes[0]
08c715
+        home_suzie = homes[1]
08c715
+        m_get_user_groups.side_effect = mock_get_user_groups
08c715
+
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        self.create_user_authorized_file(
08c715
+            home_bobby, 'authorized_keys', 'rsa', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/home/suzie/.ssh/authorized_keys = ssh-xmss@openssh.com
08c715
+        authorized_keys2 = self.create_user_authorized_file(
08c715
+            home_suzie, 'authorized_keys', 'ssh-xmss@openssh.com', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/sshd_config
08c715
+        options = "%s" % (authorized_keys2)
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        default = "%s/.ssh/authorized_keys" % home_bobby
08c715
+        self.execute_and_check(
08c715
+            user_bobby, sshd_config, default, keys, delete_keys=False
08c715
+        )
08c715
+        self.execute_and_check(user_suzie, sshd_config, authorized_keys2, keys)
08c715
+
08c715
+    @patch("cloudinit.util.get_user_groups")
08c715
+    @patch("cloudinit.ssh_util.pwd.getpwnam")
08c715
+    @patch("cloudinit.util.get_permissions")
08c715
+    @patch("cloudinit.util.get_owner")
08c715
+    @patch("cloudinit.util.get_group")
08c715
+    def test_two_users_hardcoded_user_files(
08c715
+        self, m_get_group, m_get_owner, m_get_permissions, m_getpwnam,
08c715
+        m_get_user_groups
08c715
+    ):
08c715
+        keys = {}
08c715
+        users = {}
08c715
+        mock_permissions = {
08c715
+            '/tmp/home/bobby': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh': ('bobby', 'bobby', 0o700),
08c715
+            '/tmp/home/bobby/.ssh/authorized_keys': ('bobby', 'bobby', 0o600),
08c715
+
08c715
+            '/tmp/home/suzie': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh': ('suzie', 'suzie', 0o700),
08c715
+            '/tmp/home/suzie/.ssh/authorized_keys': ('suzie', 'suzie', 0o600),
08c715
+        }
08c715
+
08c715
+        user_bobby = 'bobby'
08c715
+        user_suzie = 'suzie'
08c715
+        homes = self.create_fake_users(
08c715
+            [user_bobby, user_suzie], mock_permissions, m_get_group,
08c715
+            m_get_owner, m_get_permissions, m_getpwnam, users
08c715
+        )
08c715
+        home_bobby = homes[0]
08c715
+        home_suzie = homes[1]
08c715
+        m_get_user_groups.side_effect = mock_get_user_groups
08c715
+
08c715
+        # /tmp/home/bobby/.ssh/authorized_keys = rsa
08c715
+        authorized_keys = self.create_user_authorized_file(
08c715
+            home_bobby, 'authorized_keys', 'rsa', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/home/suzie/.ssh/authorized_keys = ssh-xmss@openssh.com
08c715
+        authorized_keys2 = self.create_user_authorized_file(
08c715
+            home_suzie, 'authorized_keys', 'ssh-xmss@openssh.com', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/etc/ssh/authorized_keys = ecdsa
08c715
+        authorized_keys_global = self.create_global_authorized_file(
08c715
+            'etc/ssh/authorized_keys', 'ecdsa', keys
08c715
+        )
08c715
+
08c715
+        # /tmp/sshd_config
08c715
+        options = "%s %s %s" % \
08c715
+            (authorized_keys_global, authorized_keys, authorized_keys2)
08c715
+        sshd_config = self.create_sshd_config(options)
08c715
+
08c715
+        self.execute_and_check(
08c715
+            user_bobby, sshd_config, authorized_keys, keys, delete_keys=False
08c715
+        )
08c715
+        self.execute_and_check(user_suzie, sshd_config, authorized_keys2, keys)
08c715
 
08c715
 # vi: ts=4 expandtab
08c715
-- 
08c715
2.27.0
08c715