Exemple #1
0
 def test_save_successor_maintains_group_mode(self, mock_rv):
     # Mock relevant_values() to claim that all values are relevant here
     # (to avoid instantiating parser)
     mock_rv.side_effect = lambda x: x
     for kind in ALL_FOUR:
         self._write_out_kind(kind, 1)
     self.test_rc.update_all_links_to(1)
     self.assertTrue(
         filesystem.check_mode(self.test_rc.version("privkey", 1), 0o600))
     filesystem.chmod(self.test_rc.version("privkey", 1), 0o444)
     # If no new key, permissions should be the same (we didn't write any keys)
     self.test_rc.save_successor(1, b"newcert", None, b"new chain",
                                 self.config)
     self.assertTrue(
         filesystem.check_mode(self.test_rc.version("privkey", 2), 0o444))
     # If new key, permissions should be kept as 644
     self.test_rc.save_successor(2, b"newcert", b"new_privkey",
                                 b"new chain", self.config)
     self.assertTrue(
         filesystem.check_mode(self.test_rc.version("privkey", 3), 0o644))
     # If permissions reverted, next renewal will also revert permissions of new key
     filesystem.chmod(self.test_rc.version("privkey", 3), 0o400)
     self.test_rc.save_successor(3, b"newcert", b"new_privkey",
                                 b"new chain", self.config)
     self.assertTrue(
         filesystem.check_mode(self.test_rc.version("privkey", 4), 0o600))
Exemple #2
0
    def test_user_admin_dacl_consistency(self):
        # Set ownership of target to authenticated user
        authenticated_user, _, _ = win32security.LookupAccountName(
            "", win32api.GetUserName())
        security_owner = _get_security_owner(self.probe_path)
        _set_owner(self.probe_path, security_owner, authenticated_user)

        filesystem.chmod(self.probe_path, 0o700)

        security_dacl = _get_security_dacl(self.probe_path)
        # We expect three ACE: one for admins, one for system, and one for the user
        self.assertEqual(
            security_dacl.GetSecurityDescriptorDacl().GetAceCount(), 3)

        # Set ownership of target to Administrators user group
        admin_user = win32security.ConvertStringSidToSid(ADMINS_SID)
        security_owner = _get_security_owner(self.probe_path)
        _set_owner(self.probe_path, security_owner, admin_user)

        filesystem.chmod(self.probe_path, 0o700)

        security_dacl = _get_security_dacl(self.probe_path)
        # We expect only two ACE: one for admins, one for system,
        # since the user is also the admins group
        self.assertEqual(
            security_dacl.GetSecurityDescriptorDacl().GetAceCount(), 2)
    def setUp(self):
        from certbot_dns_acmedns.dns_acmedns import Authenticator

        super(AuthenticatorTest, self).setUp()

        self.reg_file = os.path.join(self.tempdir, 'acmedns-registration.json')
        with open(self.reg_file, 'w') as fp:
            json.dump(ACMEDNS_REGISTRATION, fp)
        filesystem.chmod(self.reg_file, 0o600)

        path = os.path.join(self.tempdir, 'certbot-acmedns-credentials.ini')

        dns_test_common.write(
            {
                "acmedns_api_url": ACMEDNS_URL,
                "acmedns_registration_file": self.reg_file
            }, path)

        self.config = mock.MagicMock(
            acmedns_credentials=path,
            acmedns_propagation_seconds=0)  # don't wait during tests

        self.auth = Authenticator(self.config, "acmedns")

        self.mock_client = mock.MagicMock()
        # _get_acmedns_client | pylint: disable=protected-access
        self.auth._get_acmedns_client = mock.MagicMock(
            return_value=self.mock_client)
Exemple #4
0
    def test_write_renewal_config(self):
        # Mostly tested by the process of creating and updating lineages,
        # but we can test that this successfully creates files, removes
        # unneeded items, and preserves comments.
        temp = os.path.join(self.config.config_dir, "sample-file")
        temp2 = os.path.join(self.config.config_dir, "sample-file.new")
        with open(temp, "w") as f:
            f.write("[renewalparams]\nuseful = value # A useful value\n"
                    "useless = value # Not needed\n")
        filesystem.chmod(temp, 0o640)
        target = {}
        for x in ALL_FOUR:
            target[x] = "somewhere"
        archive_dir = "the_archive"
        relevant_data = {"useful": "new_value"}

        from certbot._internal import storage
        storage.write_renewal_config(temp, temp2, archive_dir, target,
                                     relevant_data)

        with open(temp2, "r") as f:
            content = f.read()
        # useful value was updated
        self.assertTrue("useful = new_value" in content)
        # associated comment was preserved
        self.assertTrue("A useful value" in content)
        # useless value was deleted
        self.assertTrue("useless" not in content)
        # check version was stored
        self.assertTrue("version = {0}".format(certbot.__version__) in content)
        # ensure permissions are copied
        self.assertEqual(stat.S_IMODE(os.lstat(temp).st_mode),
                         stat.S_IMODE(os.lstat(temp2).st_mode))
Exemple #5
0
 def test_wrong_mode(self):
     filesystem.chmod(self.tempdir, 0o400)
     try:
         self.assertFalse(self._call(0o600))
     finally:
         # Without proper write permissions, Windows is unable to delete a folder,
         # even with admin permissions. Write access must be explicitly set first.
         filesystem.chmod(self.tempdir, 0o700)
Exemple #6
0
def create_hook(file_path):
    """Creates an executable file at the specified path.

    :param str file_path: path to create the file at

    """
    open(file_path, "w").close()
    filesystem.chmod(file_path, os.stat(file_path).st_mode | stat.S_IXUSR)
Exemple #7
0
    def test_group_permissions_noop(self):
        filesystem.chmod(self.probe_path, 0o700)
        ref_dacl_probe = _get_security_dacl(self.probe_path).GetSecurityDescriptorDacl()

        filesystem.chmod(self.probe_path, 0o740)
        cur_dacl_probe = _get_security_dacl(self.probe_path).GetSecurityDescriptorDacl()

        self.assertTrue(filesystem._compare_dacls(ref_dacl_probe, cur_dacl_probe))  # pylint: disable=protected-access
Exemple #8
0
 def handle_rw_files(_, path, __):
     """Handle read-only files, that will fail to be removed on Windows."""
     filesystem.chmod(path, stat.S_IWRITE)
     try:
         os.remove(path)
     except (IOError, OSError):
         # TODO: remote the try/except once all logic from windows file permissions is merged
         if os.name != 'nt':
             raise
Exemple #9
0
    def _set_up_challenges(self):
        if not os.path.isdir(self.challenge_dir):
            os.makedirs(self.challenge_dir)
            filesystem.chmod(self.challenge_dir, 0o755)

        responses = []
        for achall in self.achalls:
            responses.append(self._set_up_challenge(achall))

        return responses
Exemple #10
0
def write_renewal_config(o_filename, n_filename, archive_dir, target,
                         relevant_data):
    """Writes a renewal config file with the specified name and values.

    :param str o_filename: Absolute path to the previous version of config file
    :param str n_filename: Absolute path to the new destination of config file
    :param str archive_dir: Absolute path to the archive directory
    :param dict target: Maps ALL_FOUR to their symlink paths
    :param dict relevant_data: Renewal configuration options to save

    :returns: Configuration object for the new config file
    :rtype: configobj.ConfigObj

    """
    config = configobj.ConfigObj(o_filename,
                                 encoding='utf-8',
                                 default_encoding='utf-8')
    config["version"] = certbot.__version__
    config["archive_dir"] = archive_dir
    for kind in ALL_FOUR:
        config[kind] = target[kind]

    if "renewalparams" not in config:
        config["renewalparams"] = {}
        config.comments["renewalparams"] = [
            "", "Options used in "
            "the renewal process"
        ]

    config["renewalparams"].update(relevant_data)

    for k in config["renewalparams"]:
        if k not in relevant_data:
            del config["renewalparams"][k]

    if "renew_before_expiry" not in config:
        default_interval = constants.RENEWER_DEFAULTS["renew_before_expiry"]
        config.initial_comment = ["renew_before_expiry = " + default_interval]

    # TODO: add human-readable comments explaining other available
    #       parameters
    logger.debug("Writing new config %s.", n_filename)

    # Ensure that the file exists
    with open(n_filename, 'a'):
        pass

    # Copy permissions from the old version of the file, if it exists.
    if os.path.exists(o_filename):
        current_permissions = stat.S_IMODE(os.lstat(o_filename).st_mode)
        filesystem.chmod(n_filename, current_permissions)

    with open(n_filename, "wb") as f:
        config.write(outfile=f)
    return config
Exemple #11
0
    def _set_up_challenge(self, achall):
        response, validation = achall.response_and_validation()

        name = os.path.join(self.challenge_dir, achall.chall.encode("token"))

        self.configurator.reverter.register_file_creation(True, name)
        with open(name, 'wb') as f:
            f.write(validation.encode())
        filesystem.chmod(name, 0o644)

        return response
Exemple #12
0
    def test_compute_private_key_mode(self):
        filesystem.chmod(self.probe_path, 0o777)
        new_mode = filesystem.compute_private_key_mode(self.probe_path, 0o600)

        if POSIX_MODE:
            # On Linux RWX permissions for group and R permission for world
            # are persisted from the existing moe
            self.assertEqual(new_mode, 0o674)
        else:
            # On Windows no permission is persisted
            self.assertEqual(new_mode, 0o600)
Exemple #13
0
 def _write_out_kind(self, kind, ver, value=None):
     link = getattr(self.test_rc, kind)
     if os.path.lexists(link):
         os.unlink(link)
     os.symlink(
         os.path.join(os.path.pardir, os.path.pardir, "archive",
                      "example.org", "{0}{1}.pem".format(kind, ver)), link)
     with open(link, "wb") as f:
         f.write(kind.encode('ascii') if value is None else value)
     if kind == "privkey":
         filesystem.chmod(link, 0o600)
Exemple #14
0
    def test_symlink_loop_mitigation(self):
        link1_path = os.path.join(self.tempdir, 'link1')
        link2_path = os.path.join(self.tempdir, 'link2')
        link3_path = os.path.join(self.tempdir, 'link3')
        os.symlink(link1_path, link2_path)
        os.symlink(link2_path, link3_path)
        os.symlink(link3_path, link1_path)

        with self.assertRaises(RuntimeError) as error:
            filesystem.chmod(link1_path, 0o755)
        self.assertTrue('link1 is a loop!' in str(error.exception))
Exemple #15
0
 def test_perform_reraises_other_errors(self):
     self.auth.full_path = os.path.join(self.path, "null")
     permission_canary = os.path.join(self.path, "rnd")
     with open(permission_canary, "w") as f:
         f.write("thingimy")
     filesystem.chmod(self.path, 0o000)
     try:
         open(permission_canary, "r")
         print("Warning, running tests as root skips permissions tests...")
     except IOError:
         # ok, permissions work, test away...
         self.assertRaises(errors.PluginError, self.auth.perform, [])
     filesystem.chmod(self.path, 0o700)
Exemple #16
0
    def test_world_permission(self):
        everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)

        filesystem.chmod(self.probe_path, 0o700)
        dacl = _get_security_dacl(self.probe_path).GetSecurityDescriptorDacl()

        self.assertFalse([dacl.GetAce(index) for index in range(0, dacl.GetAceCount())
                          if dacl.GetAce(index)[2] == everybody])

        filesystem.chmod(self.probe_path, 0o704)
        dacl = _get_security_dacl(self.probe_path).GetSecurityDescriptorDacl()

        self.assertTrue([dacl.GetAce(index) for index in range(0, dacl.GetAceCount())
                         if dacl.GetAce(index)[2] == everybody])
Exemple #17
0
    def test_symlink_resolution(self):
        link_path = os.path.join(self.tempdir, 'link')
        os.symlink(self.probe_path, link_path)

        ref_dacl_probe = _get_security_dacl(self.probe_path).GetSecurityDescriptorDacl()
        ref_dacl_link = _get_security_dacl(link_path).GetSecurityDescriptorDacl()

        filesystem.chmod(link_path, 0o700)

        # Assert the real file is impacted, not the link.
        cur_dacl_probe = _get_security_dacl(self.probe_path).GetSecurityDescriptorDacl()
        cur_dacl_link = _get_security_dacl(link_path).GetSecurityDescriptorDacl()
        self.assertFalse(filesystem._compare_dacls(ref_dacl_probe, cur_dacl_probe))  # pylint: disable=protected-access
        self.assertTrue(filesystem._compare_dacls(ref_dacl_link, cur_dacl_link))  # pylint: disable=protected-access
Exemple #18
0
def write(values, path):
    """Write the specified values to a config file.

    :param dict values: A map of values to write.
    :param str path: Where to write the values.
    """

    config = configobj.ConfigObj()

    for key in values:
        config[key] = values[key]

    with open(path, "wb") as f:
        config.write(outfile=f)

    filesystem.chmod(path, 0o600)
Exemple #19
0
    def test_copy_ownership_and_mode_windows(self):
        src = self.probe_path
        dst = _create_probe(self.tempdir, name='dst')

        filesystem.chmod(src, 0o700)
        self.assertTrue(filesystem.check_mode(src, 0o700))
        self.assertTrue(filesystem.check_mode(dst, 0o744))

        # Checking an actual change of owner is tricky during a unit test, since we do not know
        # if any user exists beside the current one. So we mock _copy_win_ownership. It's behavior
        # have been checked theoretically with test_copy_ownership_and_apply_mode_windows.
        with mock.patch('certbot.compat.filesystem._copy_win_ownership') as mock_copy_owner:
            filesystem.copy_ownership_and_mode(src, dst)

        mock_copy_owner.assert_called_once_with(src, dst)
        self.assertTrue(filesystem.check_mode(dst, 0o700))
Exemple #20
0
    def _test_flag(self, everyone_mode, windows_flag):
        # Note that flag is tested against `everyone`, not `user`, because practically these unit
        # tests are executed with admin privilege, so current user is effectively the admins group,
        # and so will always have all rights.
        filesystem.chmod(self.probe_path, 0o700 | everyone_mode)
        dacl = _get_security_dacl(self.probe_path).GetSecurityDescriptorDacl()
        everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)

        acls_everybody = [dacl.GetAce(index) for index in range(0, dacl.GetAceCount())
                          if dacl.GetAce(index)[2] == everybody]

        self.assertEqual(len(acls_everybody), 1)

        acls_everybody = acls_everybody[0]

        self.assertEqual(acls_everybody[1], windows_flag)
    def setUp(self):
        from certbot_dns_acmedns.dns_acmedns import _AcmeDNSClient

        self.fake_client = mock.MagicMock()

        self.ACMEDNS_REGISTRATION_FILE = tempfile.NamedTemporaryFile()
        with open(self.ACMEDNS_REGISTRATION_FILE.name, 'w') as fp:
            json.dump(ACMEDNS_REGISTRATION, fp)

        filesystem.chmod(self.ACMEDNS_REGISTRATION_FILE.name, 0o600)

        self.acmedns_client = _AcmeDNSClient(
            api_url=ACMEDNS_URL,
            credentials_file=self.ACMEDNS_REGISTRATION_FILE.name,
            ttl=self.TTL)

        self.acmedns_client.client = self.fake_client
Exemple #22
0
    def test_admin_permissions(self):
        system = win32security.ConvertStringSidToSid(SYSTEM_SID)
        admins = win32security.ConvertStringSidToSid(ADMINS_SID)

        filesystem.chmod(self.probe_path, 0o400)
        dacl = _get_security_dacl(self.probe_path).GetSecurityDescriptorDacl()

        system_aces = [dacl.GetAce(index) for index in range(0, dacl.GetAceCount())
                       if dacl.GetAce(index)[2] == system]
        admin_aces = [dacl.GetAce(index) for index in range(0, dacl.GetAceCount())
                      if dacl.GetAce(index)[2] == admins]

        self.assertEqual(len(system_aces), 1)
        self.assertEqual(len(admin_aces), 1)

        self.assertEqual(system_aces[0][1], ntsecuritycon.FILE_ALL_ACCESS)
        self.assertEqual(admin_aces[0][1], ntsecuritycon.FILE_ALL_ACCESS)
Exemple #23
0
    def test_save_certificate(self, mock_parser):
        # pylint: disable=too-many-locals
        certs = ["cert_512.pem", "cert-san_512.pem"]
        tmp_path = tempfile.mkdtemp()
        filesystem.chmod(tmp_path, 0o755)  # TODO: really??

        cert_pem = test_util.load_vector(certs[0])
        chain_pem = (test_util.load_vector(certs[0]) +
                     test_util.load_vector(certs[1]))
        candidate_cert_path = os.path.join(tmp_path, "certs", "cert_512.pem")
        candidate_chain_path = os.path.join(tmp_path, "chains", "chain.pem")
        candidate_fullchain_path = os.path.join(tmp_path, "chains",
                                                "fullchain.pem")
        mock_parser.verb = "certonly"
        mock_parser.args = [
            "--cert-path", candidate_cert_path, "--chain-path",
            candidate_chain_path, "--fullchain-path", candidate_fullchain_path
        ]

        cert_path, chain_path, fullchain_path = self.client.save_certificate(
            cert_pem, chain_pem, candidate_cert_path, candidate_chain_path,
            candidate_fullchain_path)

        self.assertEqual(os.path.dirname(cert_path),
                         os.path.dirname(candidate_cert_path))
        self.assertEqual(os.path.dirname(chain_path),
                         os.path.dirname(candidate_chain_path))
        self.assertEqual(os.path.dirname(fullchain_path),
                         os.path.dirname(candidate_fullchain_path))

        with open(cert_path, "rb") as cert_file:
            cert_contents = cert_file.read()
        self.assertEqual(cert_contents, test_util.load_vector(certs[0]))

        with open(chain_path, "rb") as chain_file:
            chain_contents = chain_file.read()
        self.assertEqual(
            chain_contents,
            test_util.load_vector(certs[0]) + test_util.load_vector(certs[1]))

        shutil.rmtree(tmp_path)
Exemple #24
0
def dir_setup(test_dir, pkg):  # pragma: no cover
    """Setup the directories necessary for the configurator."""
    def expanded_tempdir(prefix):
        """Return the real path of a temp directory with the specified prefix

        Some plugins rely on real paths of symlinks for working correctly. For
        example, certbot-apache uses real paths of configuration files to tell
        a virtual host from another. On systems where TMP itself is a symbolic
        link, (ex: OS X) such plugins will be confused. This function prevents
        such a case.
        """
        return filesystem.realpath(tempfile.mkdtemp(prefix))

    temp_dir = expanded_tempdir("temp")
    config_dir = expanded_tempdir("config")
    work_dir = expanded_tempdir("work")

    filesystem.chmod(temp_dir, constants.CONFIG_DIRS_MODE)
    filesystem.chmod(config_dir, constants.CONFIG_DIRS_MODE)
    filesystem.chmod(work_dir, constants.CONFIG_DIRS_MODE)

    test_configs = pkg_resources.resource_filename(
        pkg, os.path.join("testdata", test_dir))

    shutil.copytree(
        test_configs, os.path.join(temp_dir, test_dir), symlinks=True)

    return temp_dir, config_dir, work_dir
Exemple #25
0
    def test_check_min_permissions(self):
        filesystem.chmod(self.probe_path, 0o744)
        self.assertTrue(filesystem.has_min_permissions(self.probe_path, 0o744))

        filesystem.chmod(self.probe_path, 0o700)
        self.assertFalse(filesystem.has_min_permissions(self.probe_path, 0o744))

        filesystem.chmod(self.probe_path, 0o741)
        self.assertFalse(filesystem.has_min_permissions(self.probe_path, 0o744))
Exemple #26
0
    def test_is_world_reachable(self):
        filesystem.chmod(self.probe_path, 0o744)
        self.assertTrue(filesystem.has_world_permissions(self.probe_path))

        filesystem.chmod(self.probe_path, 0o700)
        self.assertFalse(filesystem.has_world_permissions(self.probe_path))
Exemple #27
0
    def save_successor(self, prior_version, new_cert, new_privkey, new_chain,
                       cli_config):
        """Save new cert and chain as a successor of a prior version.

        Returns the new version number that was created.

        .. note:: this function does NOT update links to deploy this
                  version

        :param int prior_version: the old version to which this version
            is regarded as a successor (used to choose a privkey, if the
            key has not changed, but otherwise this information is not
            permanently recorded anywhere)
        :param bytes new_cert: the new certificate, in PEM format
        :param bytes new_privkey: the new private key, in PEM format,
            or ``None``, if the private key has not changed
        :param bytes new_chain: the new chain, in PEM format
        :param .NamespaceConfig cli_config: parsed command line
            arguments

        :returns: the new version number that was created
        :rtype: int

        """
        # XXX: assumes official archive location rather than examining links
        # XXX: consider using os.open for availability of os.O_EXCL
        # XXX: ensure file permissions are correct; also create directories
        #      if needed (ensuring their permissions are correct)
        # Figure out what the new version is and hence where to save things

        self.cli_config = cli_config
        target_version = self.next_free_version()
        target = dict([(kind,
                        os.path.join(self.archive_dir,
                                     "{0}{1}.pem".format(kind,
                                                         target_version)))
                       for kind in ALL_FOUR])

        old_privkey = os.path.join(self.archive_dir,
                                   "privkey{0}.pem".format(prior_version))

        # Distinguish the cases where the privkey has changed and where it
        # has not changed (in the latter case, making an appropriate symlink
        # to an earlier privkey version)
        if new_privkey is None:
            # The behavior below keeps the prior key by creating a new
            # symlink to the old key or the target of the old key symlink.
            if os.path.islink(old_privkey):
                old_privkey = os.readlink(old_privkey)
            else:
                old_privkey = "privkey{0}.pem".format(prior_version)
            logger.debug("Writing symlink to old private key, %s.",
                         old_privkey)
            os.symlink(old_privkey, target["privkey"])
        else:
            with util.safe_open(target["privkey"],
                                "wb",
                                chmod=BASE_PRIVKEY_MODE) as f:
                logger.debug("Writing new private key to %s.",
                             target["privkey"])
                f.write(new_privkey)
            # Preserve gid and (mode & 074) from previous privkey in this lineage.
            old_mode = stat.S_IMODE(os.stat(old_privkey).st_mode) & \
                (stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | \
                 stat.S_IROTH)
            mode = BASE_PRIVKEY_MODE | old_mode
            os.chown(target["privkey"], -1, os.stat(old_privkey).st_gid)
            filesystem.chmod(target["privkey"], mode)

        # Save everything else
        with open(target["cert"], "wb") as f:
            logger.debug("Writing certificate to %s.", target["cert"])
            f.write(new_cert)
        with open(target["chain"], "wb") as f:
            logger.debug("Writing chain to %s.", target["chain"])
            f.write(new_chain)
        with open(target["fullchain"], "wb") as f:
            logger.debug("Writing full chain to %s.", target["fullchain"])
            f.write(new_cert + new_chain)

        symlinks = dict((kind, self.configuration[kind]) for kind in ALL_FOUR)
        # Update renewal config file
        self.configfile = update_configuration(self.lineagename,
                                               self.archive_dir, symlinks,
                                               cli_config)
        self.configuration = config_with_defaults(self.configfile)

        return target_version
Exemple #28
0
    def test_check_mode(self):
        self.assertTrue(filesystem.check_mode(self.probe_path, 0o744))

        filesystem.chmod(self.probe_path, 0o700)
        self.assertFalse(filesystem.check_mode(self.probe_path, 0o744))
Exemple #29
0
def _create_probe(tempdir):
    filesystem.chmod(tempdir, 0o744)
    probe_path = os.path.join(tempdir, 'probe')
    util.safe_open(probe_path, 'w', chmod=0o744).close()
    return probe_path
Exemple #30
0
 def test_ok_mode(self):
     filesystem.chmod(self.tempdir, 0o600)
     self.assertTrue(self._call(0o600))