Ejemplo n.º 1
0
def make_or_verify_dir(directory, mode=0o755, uid=0, strict=False):
    """Make sure directory exists with proper permissions.

    :param str directory: Path to a directory.
    :param int mode: Directory mode.
    :param int uid: Directory owner.
    :param bool strict: require directory to be owned by current user

    :raises .errors.Error: if a directory already exists,
        but has wrong permissions or owner

    :raises OSError: if invalid or inaccessible file names and
        paths, or other arguments that have the correct type,
        but are not accepted by the operating system.

    """
    try:
        os.makedirs(directory, mode)
    except OSError as exception:
        if exception.errno == errno.EEXIST:
            if strict and not check_permissions(directory, mode, uid):
                raise errors.Error(
                    "%s exists, but it should be owned by user %d with"
                    "permissions %s" % (directory, uid, oct(mode)))
        else:
            raise
Ejemplo n.º 2
0
def make_or_verify_dir(directory, mode=0o755, uid=0, strict=False):
    """Make sure directory exists with proper permissions.

    :param str directory: Path to a directory.
    :param int mode: Directory mode.
    :param int uid: Directory owner.
    :param bool strict: require directory to be owned by current user

    :raises .errors.Error: if a directory already exists,
        but has wrong permissions or owner

    :raises OSError: if invalid or inaccessible file names and
        paths, or other arguments that have the correct type,
        but are not accepted by the operating system.

    """
    try:
        os.makedirs(directory, mode)
    except OSError as exception:
        if exception.errno == errno.EEXIST:
            if strict and not check_permissions(directory, mode, uid):
                raise errors.Error(
                    "%s exists, but it should be owned by user %d with"
                    "permissions %s" % (directory, uid, oct(mode)))
        else:
            raise
Ejemplo n.º 3
0
    def test_view_config_changes_bad_backups_dir(self):
        # There shouldn't be any "in progress directories when this is called
        # It must just be clean checkpoints
        os.makedirs(os.path.join(self.config.backup_dir, "in_progress"))

        self.assertRaises(errors.ReverterError,
                          self.reverter.view_config_changes)
Ejemplo n.º 4
0
    def test_view_config_changes_bad_backups_dir(self):
        # There shouldn't be any "in progress directories when this is called
        # It must just be clean checkpoints
        os.makedirs(os.path.join(self.config.backup_dir, "in_progress"))

        self.assertRaises(
            errors.ReverterError, self.reverter.view_config_changes)
Ejemplo n.º 5
0
    def setUp(self):
        super(RenewHookTest, self).setUp()
        self.config.renew_hook = "foo"

        os.makedirs(self.config.renewal_deploy_hooks_dir)
        self.dir_hook = os.path.join(self.config.renewal_deploy_hooks_dir,
                                     "bar")
        create_hook(self.dir_hook)
Ejemplo n.º 6
0
    def setUp(self):
        super(RenewHookTest, self).setUp()
        self.config.renew_hook = "foo"

        os.makedirs(self.config.renewal_deploy_hooks_dir)
        self.dir_hook = os.path.join(self.config.renewal_deploy_hooks_dir,
                                     "bar")
        create_hook(self.dir_hook)
Ejemplo n.º 7
0
    def setUp(self):
        super(PreHookTest, self).setUp()
        self.config.pre_hook = "foo"

        os.makedirs(self.config.renewal_pre_hooks_dir)
        self.dir_hook = os.path.join(self.config.renewal_pre_hooks_dir, "bar")
        create_hook(self.dir_hook)

        # Reset this value as it may have been modified by past tests
        self._reset_pre_hook_already()
Ejemplo n.º 8
0
    def _set_up_challenges(self):
        if not os.path.isdir(self.challenge_dir):
            os.makedirs(self.challenge_dir)
            os.chmod(self.challenge_dir, 0o755)

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

        return responses
Ejemplo n.º 9
0
    def _set_up_challenges(self):
        if not os.path.isdir(self.challenge_dir):
            os.makedirs(self.challenge_dir)
            os.chmod(self.challenge_dir, 0o755)

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

        return responses
Ejemplo n.º 10
0
    def setUp(self):
        super(PostHookTest, self).setUp()

        self.config.post_hook = "bar"
        os.makedirs(self.config.renewal_post_hooks_dir)
        self.dir_hook = os.path.join(self.config.renewal_post_hooks_dir, "foo")
        create_hook(self.dir_hook)

        # Reset this value as it may have been modified by past tests
        self._reset_post_hook_eventually()
Ejemplo n.º 11
0
    def setUp(self):
        super(PreHookTest, self).setUp()
        self.config.pre_hook = "foo"

        os.makedirs(self.config.renewal_pre_hooks_dir)
        self.dir_hook = os.path.join(self.config.renewal_pre_hooks_dir, "bar")
        create_hook(self.dir_hook)

        # Reset this value as it may have been modified by past tests
        self._reset_pre_hook_already()
Ejemplo n.º 12
0
    def setUp(self):
        super(PostHookTest, self).setUp()

        self.config.post_hook = "bar"
        os.makedirs(self.config.renewal_post_hooks_dir)
        self.dir_hook = os.path.join(self.config.renewal_post_hooks_dir, "foo")
        create_hook(self.dir_hook)

        # Reset this value as it may have been modified by past tests
        self._reset_post_hook_eventually()
Ejemplo n.º 13
0
    def test_certificates_no_files(self, mock_utility, mock_logger):
        empty_tempdir = tempfile.mkdtemp()
        empty_config = configuration.NamespaceConfig(
            mock.MagicMock(config_dir=os.path.join(empty_tempdir, "config"),
                           work_dir=os.path.join(empty_tempdir, "work"),
                           logs_dir=os.path.join(empty_tempdir, "logs"),
                           quiet=False))

        os.makedirs(empty_config.renewal_configs_dir)
        self._certificates(empty_config)
        self.assertFalse(mock_logger.warning.called)  #pylint: disable=no-member
        self.assertTrue(mock_utility.called)
        shutil.rmtree(empty_tempdir)
Ejemplo n.º 14
0
    def test_certificates_no_files(self, mock_utility, mock_logger):
        empty_tempdir = tempfile.mkdtemp()
        empty_config = configuration.NamespaceConfig(mock.MagicMock(
            config_dir=os.path.join(empty_tempdir, "config"),
            work_dir=os.path.join(empty_tempdir, "work"),
            logs_dir=os.path.join(empty_tempdir, "logs"),
            quiet=False
        ))

        os.makedirs(empty_config.renewal_configs_dir)
        self._certificates(empty_config)
        self.assertFalse(mock_logger.warning.called) #pylint: disable=no-member
        self.assertTrue(mock_utility.called)
        shutil.rmtree(empty_tempdir)
Ejemplo n.º 15
0
    def setUp(self):
        super(BaseCertManagerTest, self).setUp()

        self.config.quiet = False
        os.makedirs(self.config.renewal_configs_dir)

        self.domains = {
            "example.org": None,
            "other.com": os.path.join(self.config.config_dir, "specialarchive")
        }
        self.config_files = dict((domain, self._set_up_config(domain, self.domains[domain]))
            for domain in self.domains)

        # We also create a file that isn't a renewal config in the same
        # location to test that logic that reads in all-and-only renewal
        # configs will ignore it and NOT attempt to parse it.
        with open(os.path.join(self.config.renewal_configs_dir, "IGNORE.THIS"), "w") as junk:
            junk.write("This file should be ignored!")
Ejemplo n.º 16
0
def make_lineage(config_dir, testfile):
    """Creates a lineage defined by testfile.

    This creates the archive, live, and renewal directories if
    necessary and creates a simple lineage.

    :param str config_dir: path to the configuration directory
    :param str testfile: configuration file to base the lineage on

    :returns: path to the renewal conf file for the created lineage
    :rtype: str

    """
    lineage_name = testfile[:-len('.conf')]

    conf_dir = os.path.join(config_dir, constants.RENEWAL_CONFIGS_DIR)
    archive_dir = os.path.join(config_dir, constants.ARCHIVE_DIR, lineage_name)
    live_dir = os.path.join(config_dir, constants.LIVE_DIR, lineage_name)

    for directory in (
            archive_dir,
            conf_dir,
            live_dir,
    ):
        if not os.path.exists(directory):
            os.makedirs(directory)

    sample_archive = vector_path('sample-archive')
    for kind in os.listdir(sample_archive):
        shutil.copyfile(os.path.join(sample_archive, kind),
                        os.path.join(archive_dir, kind))

    for kind in storage.ALL_FOUR:
        os.symlink(os.path.join(archive_dir, '{0}1.pem'.format(kind)),
                   os.path.join(live_dir, '{0}.pem'.format(kind)))

    conf_path = os.path.join(config_dir, conf_dir, testfile)
    with open(vector_path(testfile)) as src:
        with open(conf_path, 'w') as dst:
            dst.writelines(
                line.replace('MAGICDIR', config_dir) for line in src)

    return conf_path
Ejemplo n.º 17
0
def make_lineage(config_dir, testfile):
    """Creates a lineage defined by testfile.

    This creates the archive, live, and renewal directories if
    necessary and creates a simple lineage.

    :param str config_dir: path to the configuration directory
    :param str testfile: configuration file to base the lineage on

    :returns: path to the renewal conf file for the created lineage
    :rtype: str

    """
    lineage_name = testfile[:-len('.conf')]

    conf_dir = os.path.join(
        config_dir, constants.RENEWAL_CONFIGS_DIR)
    archive_dir = os.path.join(
        config_dir, constants.ARCHIVE_DIR, lineage_name)
    live_dir = os.path.join(
        config_dir, constants.LIVE_DIR, lineage_name)

    for directory in (archive_dir, conf_dir, live_dir,):
        if not os.path.exists(directory):
            os.makedirs(directory)

    sample_archive = vector_path('sample-archive')
    for kind in os.listdir(sample_archive):
        shutil.copyfile(os.path.join(sample_archive, kind),
                        os.path.join(archive_dir, kind))

    for kind in storage.ALL_FOUR:
        os.symlink(os.path.join(archive_dir, '{0}1.pem'.format(kind)),
                   os.path.join(live_dir, '{0}.pem'.format(kind)))

    conf_path = os.path.join(config_dir, conf_dir, testfile)
    with open(vector_path(testfile)) as src:
        with open(conf_path, 'w') as dst:
            dst.writelines(
                line.replace('MAGICDIR', config_dir) for line in src)

    return conf_path
Ejemplo n.º 18
0
    def setUp(self):
        super(BaseCertManagerTest, self).setUp()

        self.config.quiet = False
        os.makedirs(self.config.renewal_configs_dir)

        self.domains = {
            "example.org": None,
            "other.com": os.path.join(self.config.config_dir, "specialarchive")
        }
        self.config_files = dict(
            (domain, self._set_up_config(domain, self.domains[domain]))
            for domain in self.domains)

        # We also create a file that isn't a renewal config in the same
        # location to test that logic that reads in all-and-only renewal
        # configs will ignore it and NOT attempt to parse it.
        with open(os.path.join(self.config.renewal_configs_dir, "IGNORE.THIS"),
                  "w") as junk:
            junk.write("This file should be ignored!")
Ejemplo n.º 19
0
    def setUp(self):
        super(ChooseAccountTest, self).setUp()

        zope.component.provideUtility(
            display_util.FileDisplay(sys.stdout, False))

        self.account_keys_dir = os.path.join(self.tempdir, "keys")
        os.makedirs(self.account_keys_dir, 0o700)

        self.config = mock.MagicMock(accounts_dir=self.tempdir,
                                     account_keys_dir=self.account_keys_dir,
                                     server="certbot-demo.org")
        self.key = KEY

        self.acc1 = account.Account(
            messages.RegistrationResource(
                uri=None,
                body=messages.Registration.from_data(email="*****@*****.**")),
            self.key)
        self.acc2 = account.Account(
            messages.RegistrationResource(uri=None,
                                          body=messages.Registration.from_data(
                                              email="*****@*****.**",
                                              phone="phone")), self.key)
Ejemplo n.º 20
0
    def setUp(self):
        from certbot import storage

        super(BaseRenewableCertTest, self).setUp()

        # TODO: maybe provide NamespaceConfig.make_dirs?
        # TODO: main() should create those dirs, c.f. #902
        os.makedirs(os.path.join(self.config.config_dir, "live",
                                 "example.org"))
        archive_path = os.path.join(self.config.config_dir, "archive",
                                    "example.org")
        os.makedirs(archive_path)
        os.makedirs(os.path.join(self.config.config_dir, "renewal"))

        config_file = configobj.ConfigObj()
        for kind in ALL_FOUR:
            kind_path = os.path.join(self.config.config_dir, "live",
                                     "example.org", kind + ".pem")
            config_file[kind] = kind_path
        with open(
                os.path.join(self.config.config_dir, "live", "example.org",
                             "README"), 'a'):
            pass
        config_file["archive"] = archive_path
        config_file.filename = os.path.join(self.config.config_dir, "renewal",
                                            "example.org.conf")
        config_file.write()
        self.config_file = config_file

        # We also create a file that isn't a renewal config in the same
        # location to test that logic that reads in all-and-only renewal
        # configs will ignore it and NOT attempt to parse it.
        with open(
                os.path.join(self.config.config_dir, "renewal", "IGNORE.THIS"),
                "w") as junk:
            junk.write("This file should be ignored!")

        self.defaults = configobj.ConfigObj()

        with mock.patch(
                "certbot.storage.RenewableCert._check_symlinks") as check:
            check.return_value = True
            self.test_rc = storage.RenewableCert(config_file.filename,
                                                 self.config)
Ejemplo n.º 21
0
    def _set_up_config(self, domain, custom_archive):
        # TODO: maybe provide NamespaceConfig.make_dirs?
        # TODO: main() should create those dirs, c.f. #902
        os.makedirs(os.path.join(self.config.live_dir, domain))
        config_file = configobj.ConfigObj()

        if custom_archive is not None:
            os.makedirs(custom_archive)
            config_file["archive_dir"] = custom_archive
        else:
            os.makedirs(os.path.join(self.config.default_archive_dir, domain))

        for kind in ALL_FOUR:
            config_file[kind] = os.path.join(self.config.live_dir, domain,
                                        kind + ".pem")

        config_file.filename = os.path.join(self.config.renewal_configs_dir,
                                       domain + ".conf")
        config_file.write()
        return config_file
Ejemplo n.º 22
0
    def _set_up_config(self, domain, custom_archive):
        # TODO: maybe provide NamespaceConfig.make_dirs?
        # TODO: main() should create those dirs, c.f. #902
        os.makedirs(os.path.join(self.config.live_dir, domain))
        config_file = configobj.ConfigObj()

        if custom_archive is not None:
            os.makedirs(custom_archive)
            config_file["archive_dir"] = custom_archive
        else:
            os.makedirs(os.path.join(self.config.default_archive_dir, domain))

        for kind in ALL_FOUR:
            config_file[kind] = os.path.join(self.config.live_dir, domain,
                                             kind + ".pem")

        config_file.filename = os.path.join(self.config.renewal_configs_dir,
                                            domain + ".conf")
        config_file.write()
        return config_file
Ejemplo n.º 23
0
    def setUp(self):
        from certbot import storage

        super(BaseRenewableCertTest, self).setUp()

        # TODO: maybe provide NamespaceConfig.make_dirs?
        # TODO: main() should create those dirs, c.f. #902
        os.makedirs(os.path.join(self.config.config_dir, "live", "example.org"))
        archive_path = os.path.join(self.config.config_dir, "archive", "example.org")
        os.makedirs(archive_path)
        os.makedirs(os.path.join(self.config.config_dir, "renewal"))

        config_file = configobj.ConfigObj()
        for kind in ALL_FOUR:
            kind_path = os.path.join(self.config.config_dir, "live", "example.org",
                                        kind + ".pem")
            config_file[kind] = kind_path
        with open(os.path.join(self.config.config_dir, "live", "example.org",
                                        "README"), 'a'):
            pass
        config_file["archive"] = archive_path
        config_file.filename = os.path.join(self.config.config_dir, "renewal",
                                       "example.org.conf")
        config_file.write()
        self.config_file = config_file

        # We also create a file that isn't a renewal config in the same
        # location to test that logic that reads in all-and-only renewal
        # configs will ignore it and NOT attempt to parse it.
        with open(os.path.join(self.config.config_dir, "renewal", "IGNORE.THIS"), "w") as junk:
            junk.write("This file should be ignored!")

        self.defaults = configobj.ConfigObj()

        with mock.patch("certbot.storage.RenewableCert._check_symlinks") as check:
            check.return_value = True
            self.test_rc = storage.RenewableCert(config_file.filename, self.config)
Ejemplo n.º 24
0
    def new_lineage(cls, lineagename, cert, privkey, chain, cli_config):
        # pylint: disable=too-many-locals
        """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):
                os.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)
        os.mkdir(archive)
        os.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 = dict([(kind, os.path.join(live_dir, kind + ".pem"))
                       for kind in ALL_FOUR])
        archive_target = dict([(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)
Ejemplo n.º 25
0
    def new_lineage(cls, lineagename, cert, privkey, chain, cli_config):
        # pylint: disable=too-many-locals
        """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):
                os.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)
        os.mkdir(archive)
        os.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 = dict([(kind, os.path.join(live_dir, kind + ".pem"))
                       for kind in ALL_FOUR])
        archive_target = dict([(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)