Example #1
0
    def setUp(self):
        super().setUp()

        self.workdir = os.path.join(self.tempdir, 'workdir')
        filesystem.mkdir(self.workdir, mode=0o700)

        logging.disable(logging.CRITICAL)
Example #2
0
    def setUp(self):
        super(InstallerTest, self).setUp()
        filesystem.mkdir(self.config.config_dir)
        from certbot.plugins.common import Installer

        self.installer = Installer(config=self.config, name="Installer")
        self.reverter = self.installer.reverter
Example #3
0
    def setUp(self):
        super().setUp()
        filesystem.mkdir(self.config.config_dir)
        from certbot.tests.util import DummyInstaller

        self.installer = DummyInstaller(config=self.config, name="Installer")
        self.reverter = self.installer.reverter
Example #4
0
def set_up_dirs():
    """Set up directories for tests.

    A temporary directory is created to contain the config, log, work,
    and nginx directories. A sample renewal configuration is created in
    the config directory and a basic Nginx config is placed in the Nginx
    directory. The temporary directory containing all of these
    directories is deleted when the program exits.

    :return value: config, log, work, and nginx directories
    :rtype: `tuple` of `str`

    """
    temp_dir = tempfile.mkdtemp()
    logger.debug('Created temporary directory: %s', temp_dir)
    atexit.register(functools.partial(shutil.rmtree, temp_dir))

    config_dir = os.path.join(temp_dir, 'config')
    logs_dir = os.path.join(temp_dir, 'logs')
    work_dir = os.path.join(temp_dir, 'work')
    nginx_dir = os.path.join(temp_dir, 'nginx')

    for directory in (
            config_dir,
            logs_dir,
            work_dir,
            nginx_dir,
    ):
        filesystem.mkdir(directory)

    test_util.make_lineage(config_dir, 'sample-renewal.conf')
    set_up_nginx_dir(nginx_dir)

    return config_dir, logs_dir, work_dir, nginx_dir
Example #5
0
    def setUp(self):
        super(MakeOrVerifyDirTest, self).setUp()

        self.path = os.path.join(self.tempdir, "foo")
        filesystem.mkdir(self.path, 0o600)

        self.uid = misc.os_geteuid()
Example #6
0
 def setUp(self):
     super(PluginStorageTest, self).setUp()
     self.plugin_cls = common.Installer
     filesystem.mkdir(self.config.config_dir)
     with mock.patch("certbot.reverter.util"):
         self.plugin = self.plugin_cls(config=self.config,
                                       name="mockplugin")
Example #7
0
    def test_dry_run_flag(self):
        config_dir = tempfile.mkdtemp()
        short_args = '--dry-run --config-dir {0}'.format(config_dir).split()
        self.assertRaises(errors.Error, self.parse, short_args)

        self._assert_dry_run_flag_worked(self.parse(short_args + ['auth']),
                                         False)
        self._assert_dry_run_flag_worked(self.parse(short_args + ['certonly']),
                                         False)
        self._assert_dry_run_flag_worked(self.parse(short_args + ['renew']),
                                         False)

        account_dir = os.path.join(config_dir, constants.ACCOUNTS_DIR)
        filesystem.mkdir(account_dir)
        filesystem.mkdir(os.path.join(account_dir, 'fake_account_dir'))

        self._assert_dry_run_flag_worked(self.parse(short_args + ['auth']),
                                         True)
        self._assert_dry_run_flag_worked(self.parse(short_args + ['renew']),
                                         True)
        short_args += ['certonly']
        self._assert_dry_run_flag_worked(self.parse(short_args), True)

        short_args += '--server example.com'.split()
        conflicts = ['--dry-run']
        self._check_server_conflict_message(short_args, '--dry-run')

        short_args += ['--staging']
        conflicts += ['--staging']
        self._check_server_conflict_message(short_args, conflicts)
Example #8
0
    def setUp(self):
        super().setUp()
        get_utility_patch = test_util.patch_get_utility()
        self.mock_get_utility = get_utility_patch.start()
        self.addCleanup(get_utility_patch.stop)

        self.http_achall = acme_util.HTTP01_A
        self.dns_achall = acme_util.DNS01_A
        self.dns_achall_2 = acme_util.DNS01_A_2
        self.achalls = [self.http_achall, self.dns_achall, self.dns_achall_2]
        for d in ["config_dir", "work_dir", "in_progress"]:
            filesystem.mkdir(os.path.join(self.tempdir, d))
            # "backup_dir" and "temp_checkpoint_dir" get created in
            # certbot.util.make_or_verify_dir() during the Reverter
            # initialization.
        self.config = mock.MagicMock(
            http01_port=0,
            manual_auth_hook=None,
            manual_cleanup_hook=None,
            noninteractive_mode=False,
            validate_hooks=False,
            config_dir=os.path.join(self.tempdir, "config_dir"),
            work_dir=os.path.join(self.tempdir, "work_dir"),
            backup_dir=os.path.join(self.tempdir, "backup_dir"),
            temp_checkpoint_dir=os.path.join(self.tempdir,
                                             "temp_checkpoint_dir"),
            in_progress_dir=os.path.join(self.tempdir, "in_progess"))

        from certbot._internal.plugins.manual import Authenticator
        self.auth = Authenticator(self.config, name='manual')
Example #9
0
    def test_perform_cleanup_existing_dirs(self):
        filesystem.mkdir(self.partial_root_challenge_path)
        self.auth.prepare()
        self.auth.perform([self.achall])
        self.auth.cleanup([self.achall])

        # Ensure we don't "clean up" directories that previously existed
        self.assertFalse(os.path.exists(self.validation_path))
        self.assertFalse(os.path.exists(self.root_challenge_path))
Example #10
0
    def _create_challenge_dirs(self):
        path_map = self.conf("map")
        if not path_map:
            raise errors.PluginError(
                "Missing parts of webroot configuration; please set either "
                "--webroot-path and --domains, or --webroot-map. Run with "
                " --help webroot for examples.")
        for name, path in path_map.items():
            self.full_roots[name] = os.path.join(path, os.path.normcase(
                challenges.HTTP01.URI_ROOT_PATH))
            logger.debug("Creating root challenges validation dir at %s",
                         self.full_roots[name])

            # Change the permissions to be writable (GH #1389)
            # Umask is used instead of chmod to ensure the client can also
            # run as non-root (GH #1795)
            old_umask = filesystem.umask(0o022)
            try:
                # We ignore the last prefix in the next iteration,
                # as it does not correspond to a folder path ('/' or 'C:')
                for prefix in sorted(util.get_prefixes(self.full_roots[name])[:-1], key=len):
                    if os.path.isdir(prefix):
                        # Don't try to create directory if it already exists, as some filesystems
                        # won't reliably raise EEXIST or EISDIR if directory exists.
                        continue
                    try:
                        # Set owner as parent directory if possible, apply mode for Linux/Windows.
                        # For Linux, this is coupled with the "umask" call above because
                        # os.mkdir's "mode" parameter may not always work:
                        # https://docs.python.org/3/library/os.html#os.mkdir
                        filesystem.mkdir(prefix, 0o755)
                        self._created_dirs.append(prefix)
                        try:
                            filesystem.copy_ownership_and_apply_mode(
                                path, prefix, 0o755, copy_user=True, copy_group=True)
                        except (OSError, AttributeError) as exception:
                            logger.warning("Unable to change owner and uid of webroot directory")
                            logger.debug("Error was: %s", exception)
                    except OSError as exception:
                        raise errors.PluginError(
                            "Couldn't create root for {0} http-01 "
                            "challenge responses: {1}".format(name, exception))
            finally:
                filesystem.umask(old_umask)

            # On Windows, generate a local web.config file that allows IIS to serve expose
            # challenge files despite the fact they do not have a file extension.
            if not filesystem.POSIX_MODE:
                web_config_path = os.path.join(self.full_roots[name], "web.config")
                if os.path.exists(web_config_path):
                    logger.info("A web.config file has not been created in "
                                "%s because another one already exists.", self.full_roots[name])
                    continue
                logger.info("Creating a web.config file in %s to allow IIS "
                            "to serve challenge files.", self.full_roots[name])
                with safe_open(web_config_path, mode="w", chmod=0o644) as web_config:
                    web_config.write(_WEB_CONFIG_CONTENT)
Example #11
0
    def setUp(self):
        super(InitSaveKeyTest, self).setUp()

        self.workdir = os.path.join(self.tempdir, 'workdir')
        filesystem.mkdir(self.workdir, mode=0o700)

        logging.disable(logging.CRITICAL)
        zope.component.provideUtility(mock.Mock(strict_permissions=True),
                                      interfaces.IConfig)
Example #12
0
    def test_new_lineage(self, mock_rv):
        """Test for new_lineage() class method."""
        # Mock relevant_values to say everything is relevant here (so we
        # don't have to mock the parser to help it decide!)
        mock_rv.side_effect = lambda x: x

        from certbot import storage
        result = storage.RenewableCert.new_lineage("the-lineage.com", b"cert",
                                                   b"privkey", b"chain",
                                                   self.config)
        # This consistency check tests most relevant properties about the
        # newly created cert lineage.
        # pylint: disable=protected-access
        self.assertTrue(result._consistent())
        self.assertTrue(
            os.path.exists(
                os.path.join(self.config.renewal_configs_dir,
                             "the-lineage.com.conf")))
        self.assertTrue(
            os.path.exists(os.path.join(self.config.live_dir, "README")))
        self.assertTrue(
            os.path.exists(
                os.path.join(self.config.live_dir, "the-lineage.com",
                             "README")))
        self.assertTrue(
            misc.compare_file_modes(os.stat(result.key_path).st_mode, 0o600))
        with open(result.fullchain, "rb") as f:
            self.assertEqual(f.read(), b"cert" + b"chain")
        # Let's do it again and make sure it makes a different lineage
        result = storage.RenewableCert.new_lineage("the-lineage.com", b"cert2",
                                                   b"privkey2", b"chain2",
                                                   self.config)
        self.assertTrue(
            os.path.exists(
                os.path.join(self.config.renewal_configs_dir,
                             "the-lineage.com-0001.conf")))
        self.assertTrue(
            os.path.exists(
                os.path.join(self.config.live_dir, "the-lineage.com-0001",
                             "README")))
        # Now trigger the detection of already existing files
        filesystem.mkdir(
            os.path.join(self.config.live_dir, "the-lineage.com-0002"))
        self.assertRaises(errors.CertStorageError,
                          storage.RenewableCert.new_lineage, "the-lineage.com",
                          b"cert3", b"privkey3", b"chain3", self.config)
        filesystem.mkdir(
            os.path.join(self.config.default_archive_dir, "other-example.com"))
        self.assertRaises(errors.CertStorageError,
                          storage.RenewableCert.new_lineage,
                          "other-example.com", b"cert4", b"privkey4",
                          b"chain4", self.config)
        # Make sure it can accept renewal parameters
        result = storage.RenewableCert.new_lineage("the-lineage.com", b"cert2",
                                                   b"privkey2", b"chain2",
                                                   self.config)
Example #13
0
    def test_mkdir_correct_permissions(self):
        path = os.path.join(self.tempdir, 'dir')

        filesystem.mkdir(path, 0o700)

        everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)

        dacl = _get_security_dacl(path).GetSecurityDescriptorDacl()
        self.assertFalse([dacl.GetAce(index) for index in range(0, dacl.GetAceCount())
                          if dacl.GetAce(index)[2] == everybody])
Example #14
0
    def test_cleanup_leftovers(self):
        self.auth.prepare()
        self.auth.perform([self.achall])

        leftover_path = os.path.join(self.root_challenge_path, 'leftover')
        filesystem.mkdir(leftover_path)

        self.auth.cleanup([self.achall])
        self.assertFalse(os.path.exists(self.validation_path))
        self.assertTrue(os.path.exists(self.root_challenge_path))

        os.rmdir(leftover_path)
Example #15
0
    def _create_challenge_dirs(self):
        path_map = self.conf("map")
        if not path_map:
            raise errors.PluginError(
                "Missing parts of webroot configuration; please set either "
                "--webroot-path and --domains, or --webroot-map. Run with "
                " --help webroot for examples.")
        for name, path in path_map.items():
            self.full_roots[name] = os.path.join(
                path, challenges.HTTP01.URI_ROOT_PATH)
            logger.debug("Creating root challenges validation dir at %s",
                         self.full_roots[name])

            # Change the permissions to be writable (GH #1389)
            # Umask is used instead of chmod to ensure the client can also
            # run as non-root (GH #1795)
            old_umask = os.umask(0o022)
            try:
                # We ignore the last prefix in the next iteration,
                # as it does not correspond to a folder path ('/' or 'C:')
                for prefix in sorted(util.get_prefixes(
                        self.full_roots[name])[:-1],
                                     key=len):
                    try:
                        # Set owner as parent directory if possible, apply mode for Linux/Windows.
                        # For Linux, this is coupled with the "umask" call above because
                        # os.mkdir's "mode" parameter may not always work:
                        # https://docs.python.org/3/library/os.html#os.mkdir
                        filesystem.mkdir(prefix, 0o755)
                        self._created_dirs.append(prefix)
                        try:
                            filesystem.copy_ownership_and_apply_mode(
                                path,
                                prefix,
                                0o755,
                                copy_user=True,
                                copy_group=True)
                        except (OSError, AttributeError) as exception:
                            logger.info(
                                "Unable to change owner and uid of webroot directory"
                            )
                            logger.debug("Error was: %s", exception)
                    except OSError as exception:
                        if exception.errno not in (errno.EEXIST, errno.EISDIR):
                            raise errors.PluginError(
                                "Couldn't create root for {0} http-01 "
                                "challenge responses: {1}".format(
                                    name, exception))
            finally:
                os.umask(old_umask)
Example #16
0
    def test_perform_cleanup_multiple_challenges(self):
        bingo_achall = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.HTTP01(token=b"bingo"), "pending"),
            domain="thing.com", account_key=KEY)

        bingo_validation_path = "YmluZ28"
        filesystem.mkdir(self.partial_root_challenge_path)
        self.auth.prepare()
        self.auth.perform([bingo_achall, self.achall])

        self.auth.cleanup([self.achall])
        self.assertFalse(os.path.exists(bingo_validation_path))
        self.assertTrue(os.path.exists(self.root_challenge_path))
        self.auth.cleanup([bingo_achall])
        self.assertFalse(os.path.exists(self.validation_path))
        self.assertFalse(os.path.exists(self.root_challenge_path))
Example #17
0
    def test_dry_run_flag(self):
        config_dir = tempfile.mkdtemp()
        short_args = '--dry-run --config-dir {0}'.format(config_dir).split()
        self.assertRaises(errors.Error, self.parse, short_args)

        self._assert_dry_run_flag_worked(self.parse(short_args + ['auth']),
                                         False)
        self._assert_dry_run_flag_worked(self.parse(short_args + ['certonly']),
                                         False)
        self._assert_dry_run_flag_worked(self.parse(short_args + ['renew']),
                                         False)

        account_dir = os.path.join(config_dir, constants.ACCOUNTS_DIR)
        filesystem.mkdir(account_dir)
        filesystem.mkdir(os.path.join(account_dir, 'fake_account_dir'))

        self._assert_dry_run_flag_worked(self.parse(short_args + ['auth']),
                                         True)
        self._assert_dry_run_flag_worked(self.parse(short_args + ['renew']),
                                         True)
        self._assert_dry_run_flag_worked(self.parse(short_args + ['certonly']),
                                         True)

        short_args += ['certonly']

        # `--dry-run --server example.com` should emit example.com
        self.assertEqual(
            self.parse(short_args + ['--server', 'example.com']).server,
            'example.com')

        # `--dry-run --server STAGING_URI` should emit STAGING_URI
        self.assertEqual(
            self.parse(short_args +
                       ['--server', constants.STAGING_URI]).server,
            constants.STAGING_URI)

        # `--dry-run --server LIVE` should emit STAGING_URI
        self.assertEqual(
            self.parse(short_args +
                       ['--server', cli.flag_default("server")]).server,
            constants.STAGING_URI)

        # `--dry-run --server example.com --staging` should emit an error
        conflicts = ['--staging']
        self._check_server_conflict_message(
            short_args + ['--server', 'example.com', '--staging'], conflicts)
Example #18
0
    def test_it(self, mock_register, mock_logger):
        subdir = os.path.join(self.tempdir, 'subdir')
        filesystem.mkdir(subdir)
        self._call(self.tempdir)
        self._call(subdir)
        self._call(subdir)

        self.assertEqual(mock_register.call_count, 1)
        registered_func = mock_register.call_args[0][0]

        from certbot import util
        # Despite lock_dir_until_exit has been called twice to subdir, its lock should have been
        # added only once. So we expect to have two lock references: for self.tempdir and subdir
        self.assertEqual(len(util._LOCKS), 2)  # pylint: disable=protected-access
        registered_func()  # Exception should not be raised
        # Logically, logger.debug, that would be invoked in case of unlock failure,
        # should never been called.
        self.assertEqual(mock_logger.debug.call_count, 0)
Example #19
0
    def setUp(self):
        super().setUp()

        # directories must end with os.sep for completer to
        # search inside the directory for possible completions
        if self.tempdir[-1] != os.sep:
            self.tempdir += os.sep

        self.paths: List[str] = []
        # create some files and directories in temp_dir
        for c in string.ascii_lowercase:
            path = os.path.join(self.tempdir, c)
            self.paths.append(path)
            if ord(c) % 2:
                filesystem.mkdir(path)
            else:
                with open(path, 'w'):
                    pass
Example #20
0
 def setUp(self):
     from certbot.plugins.webroot import Authenticator
     # On Linux directories created by tempfile.mkdtemp inherit their permissions from their
     # parent directory. So the actual permissions are inconsistent over various tests env.
     # To circumvent this, a dedicated sub-workspace is created under the workspace, using
     # filesystem.mkdir to get consistent permissions.
     self.workspace = tempfile.mkdtemp()
     self.path = os.path.join(self.workspace, 'webroot')
     filesystem.mkdir(self.path)
     self.partial_root_challenge_path = os.path.join(
         self.path, ".well-known")
     self.root_challenge_path = os.path.join(self.path, ".well-known",
                                             "acme-challenge")
     self.validation_path = os.path.join(
         self.root_challenge_path,
         "ZXZhR3hmQURzNnBTUmIyTEF2OUlaZjE3RHQzanV4R0orUEN0OTJ3citvQQ")
     self.config = mock.MagicMock(webroot_path=self.path,
                                  webroot_map={"thing.com": self.path})
     self.auth = Authenticator(self.config, "webroot")
Example #21
0
    def test_umask_on_dir(self):
        previous_umask = filesystem.umask(0o022)

        try:
            dir1 = os.path.join(self.tempdir, 'probe1')
            filesystem.mkdir(dir1)
            self.assertTrue(filesystem.check_mode(dir1, 0o755))

            filesystem.umask(0o077)

            dir2 = os.path.join(self.tempdir, 'dir2')
            filesystem.mkdir(dir2)
            self.assertTrue(filesystem.check_mode(dir2, 0o700))

            dir3 = os.path.join(self.tempdir, 'dir3')
            filesystem.mkdir(dir3, mode=0o777)
            self.assertTrue(filesystem.check_mode(dir3, 0o700))
        finally:
            filesystem.umask(previous_umask)
Example #22
0
    def new_lineage(cls, lineagename, cert, privkey, chain, cli_config):
        """Create a new certificate lineage.

        Attempts to create a certificate lineage -- enrolled for
        potential future renewal -- with the (suggested) lineage name
        lineagename, and the associated cert, privkey, and chain (the
        associated fullchain will be created automatically). Optional
        configurator and renewalparams record the configuration that was
        originally used to obtain this cert, so that it can be reused
        later during automated renewal.

        Returns a new RenewableCert object referring to the created
        lineage. (The actual lineage name, as well as all the relevant
        file paths, will be available within this object.)

        :param str lineagename: the suggested name for this lineage
            (normally the current cert's first subject DNS name)
        :param str cert: the initial certificate version in PEM format
        :param str privkey: the private key in PEM format
        :param str chain: the certificate chain in PEM format
        :param .NamespaceConfig cli_config: parsed command line
            arguments

        :returns: the newly-created RenewalCert object
        :rtype: :class:`storage.renewableCert`

        """

        # Examine the configuration and find the new lineage's name
        for i in (cli_config.renewal_configs_dir,
                  cli_config.default_archive_dir, cli_config.live_dir):
            if not os.path.exists(i):
                filesystem.makedirs(i, 0o700)
                logger.debug("Creating directory %s.", i)
        config_file, config_filename = util.unique_lineage_name(
            cli_config.renewal_configs_dir, lineagename)
        base_readme_path = os.path.join(cli_config.live_dir, README)
        if not os.path.exists(base_readme_path):
            _write_live_readme_to(base_readme_path, is_base_dir=True)

        # Determine where on disk everything will go
        # lineagename will now potentially be modified based on which
        # renewal configuration file could actually be created
        lineagename = lineagename_for_filename(config_filename)
        archive = full_archive_path(None, cli_config, lineagename)
        live_dir = _full_live_path(cli_config, lineagename)
        if os.path.exists(archive):
            config_file.close()
            raise errors.CertStorageError("archive directory exists for " +
                                          lineagename)
        if os.path.exists(live_dir):
            config_file.close()
            raise errors.CertStorageError("live directory exists for " +
                                          lineagename)
        filesystem.mkdir(archive)
        filesystem.mkdir(live_dir)
        logger.debug("Archive directory %s and live "
                     "directory %s created.", archive, live_dir)

        # Put the data into the appropriate files on disk
        target = {
            kind: os.path.join(live_dir, kind + ".pem")
            for kind in ALL_FOUR
        }
        archive_target = {
            kind: os.path.join(archive, kind + "1.pem")
            for kind in ALL_FOUR
        }
        for kind in ALL_FOUR:
            os.symlink(_relpath_from_file(archive_target[kind], target[kind]),
                       target[kind])
        with open(target["cert"], "wb") as f:
            logger.debug("Writing certificate to %s.", target["cert"])
            f.write(cert)
        with util.safe_open(archive_target["privkey"],
                            "wb",
                            chmod=BASE_PRIVKEY_MODE) as f:
            logger.debug("Writing private key to %s.", target["privkey"])
            f.write(privkey)
            # XXX: Let's make sure to get the file permissions right here
        with open(target["chain"], "wb") as f:
            logger.debug("Writing chain to %s.", target["chain"])
            f.write(chain)
        with open(target["fullchain"], "wb") as f:
            # assumes that OpenSSL.crypto.dump_certificate includes
            # ending newline character
            logger.debug("Writing full chain to %s.", target["fullchain"])
            f.write(cert + chain)

        # Write a README file to the live directory
        readme_path = os.path.join(live_dir, README)
        _write_live_readme_to(readme_path)

        # Document what we've done in a new renewal config file
        config_file.close()

        # Save only the config items that are relevant to renewal
        values = relevant_values(vars(cli_config.namespace))

        new_config = write_renewal_config(config_filename, config_filename,
                                          archive, target, values)
        return cls(new_config.filename, cli_config)
Example #23
0
    def setUp(self):
        super().setUp()

        self.path = os.path.join(self.tempdir, "foo")
        filesystem.mkdir(self.path, 0o600)
Example #24
0
 def setUp(self):
     super().setUp()
     self.plugin_cls = test_util.DummyInstaller
     filesystem.mkdir(self.config.config_dir)
     with mock.patch("certbot.reverter.util"):
         self.plugin = self.plugin_cls(config=self.config, name="mockplugin")