def _find_duplicative_certs(config, domains): """Find existing certs that duplicate the request.""" identical_names_cert, subset_names_cert = None, None cli_config = configuration.RenewerConfiguration(config) configs_dir = cli_config.renewal_configs_dir # Verify the directory is there le_util.make_or_verify_dir(configs_dir, mode=0o755, uid=os.geteuid()) for renewal_file in renewal.renewal_conf_files(cli_config): try: candidate_lineage = storage.RenewableCert(renewal_file, cli_config) except (errors.CertStorageError, IOError): logger.warning("Renewal conf file %s is broken. Skipping.", renewal_file) logger.debug("Traceback was:\n%s", traceback.format_exc()) continue # TODO: Handle these differently depending on whether they are # expired or still valid? candidate_names = set(candidate_lineage.names()) if candidate_names == set(domains): identical_names_cert = candidate_lineage elif candidate_names.issubset(set(domains)): # This logic finds and returns the largest subset-names cert # in the case where there are several available. if subset_names_cert is None: subset_names_cert = candidate_lineage elif len(candidate_names) > len(subset_names_cert.names()): subset_names_cert = candidate_lineage return identical_names_cert, subset_names_cert
def _find_duplicative_certs(config, domains): """Find existing certs that duplicate the request.""" identical_names_cert, subset_names_cert = None, None cli_config = configuration.RenewerConfiguration(config) configs_dir = cli_config.renewal_configs_dir # Verify the directory is there le_util.make_or_verify_dir(configs_dir, mode=0o755, uid=os.geteuid()) for renewal_file in os.listdir(configs_dir): try: full_path = os.path.join(configs_dir, renewal_file) candidate_lineage = storage.RenewableCert(full_path, cli_config) except (CertStorageError, IOError): logger.warning( "Renewal configuration file %s is broken. " "Skipping.", full_path) continue # TODO: Handle these differently depending on whether they are # expired or still valid? candidate_names = set(candidate_lineage.names()) if candidate_names == set(domains): identical_names_cert = candidate_lineage elif candidate_names.issubset(set(domains)): subset_names_cert = candidate_lineage return identical_names_cert, subset_names_cert
def _find_duplicative_certs(domains, config, renew_config): """Find existing certs that duplicate the request.""" identical_names_cert, subset_names_cert = None, None configs_dir = renew_config.renewal_configs_dir cli_config = configuration.RenewerConfiguration(config) for renewal_file in os.listdir(configs_dir): try: full_path = os.path.join(configs_dir, renewal_file) rc_config = configobj.ConfigObj(renew_config.renewer_config_file) rc_config.merge(configobj.ConfigObj(full_path)) rc_config.filename = full_path candidate_lineage = storage.RenewableCert(rc_config, config_opts=None, cli_config=cli_config) except (configobj.ConfigObjError, errors.CertStorageError, IOError): logger.warning( "Renewal configuration file %s is broken. " "Skipping.", full_path) continue # TODO: Handle these differently depending on whether they are # expired or still valid? candidate_names = set(candidate_lineage.names()) if candidate_names == set(domains): identical_names_cert = candidate_lineage elif candidate_names.issubset(set(domains)): subset_names_cert = candidate_lineage return identical_names_cert, subset_names_cert
def setUp(self): from letsencrypt import storage self.tempdir = tempfile.mkdtemp() self.cli_config = configuration.RenewerConfiguration( namespace=mock.MagicMock( config_dir=self.tempdir, work_dir=self.tempdir, logs_dir=self.tempdir, )) # TODO: maybe provide RenewerConfiguration.make_dirs? # TODO: main() should create those dirs, c.f. #902 os.makedirs(os.path.join(self.tempdir, "live", "example.org")) os.makedirs(os.path.join(self.tempdir, "archive", "example.org")) os.makedirs(os.path.join(self.tempdir, "renewal")) config = configobj.ConfigObj() for kind in ALL_FOUR: config[kind] = os.path.join(self.tempdir, "live", "example.org", kind + ".pem") config.filename = os.path.join(self.tempdir, "renewal", "example.org.conf") config.write() self.config = config self.defaults = configobj.ConfigObj() self.test_rc = storage.RenewableCert(config.filename, self.cli_config)
def main(cli_args=sys.argv[1:]): """Main function for autorenewer script.""" # TODO: Distinguish automated invocation from manual invocation, # perhaps by looking at sys.argv[0] and inhibiting automated # invocations if /etc/letsencrypt/renewal.conf defaults have # turned it off. (The boolean parameter should probably be # called renewer_enabled.) # TODO: When we have a more elaborate renewer command line, we will # presumably also be able to specify a config file on the # command line, which, if provided, should take precedence over # te default config files zope.component.provideUtility(display_util.FileDisplay(sys.stdout)) args = _create_parser().parse_args(cli_args) uid = os.geteuid() le_util.make_or_verify_dir(args.logs_dir, 0o700, uid) cli.setup_logging(args, _cli_log_handler, logfile='renewer.log') cli_config = configuration.RenewerConfiguration(args) # Ensure that all of the needed folders have been created before continuing le_util.make_or_verify_dir(cli_config.work_dir, constants.CONFIG_DIRS_MODE, uid) for renewal_file in os.listdir(cli_config.renewal_configs_dir): print "Processing", renewal_file try: # TODO: Before trying to initialize the RenewableCert object, # we could check here whether the combination of the config # and the rc_config together disables all autorenewal and # autodeployment applicable to this cert. In that case, we # can simply continue and don't need to instantiate a # RenewableCert object for this cert at all, which could # dramatically improve performance for large deployments # where autorenewal is widely turned off. cert = storage.RenewableCert(renewal_file, cli_config) except errors.CertStorageError: # This indicates an invalid renewal configuration file, such # as one missing a required parameter (in the future, perhaps # also one that is internally inconsistent or is missing a # required parameter). As a TODO, maybe we should warn the # user about the existence of an invalid or corrupt renewal # config rather than simply ignoring it. continue if cert.should_autorenew(): # Note: not cert.current_version() because the basis for # the renewal is the latest version, even if it hasn't been # deployed yet! old_version = cert.latest_common_version() renew(cert, old_version) notify.notify("Autorenewed a cert!!!", "root", "It worked!") # TODO: explain what happened if cert.should_autodeploy(): cert.update_all_links_to(cert.latest_common_version()) # TODO: restart web server (invoke IInstaller.restart() method) notify.notify("Autodeployed a cert!!!", "root", "It worked!")
def _reconstitute(config, full_path): """Try to instantiate a RenewableCert, updating config with relevant items. This is specifically for use in renewal and enforces several checks and policies to ensure that we can try to proceed with the renwal request. The config argument is modified by including relevant options read from the renewal configuration file. :param configuration.NamespaceConfig config: configuration for the current lineage :param str full_path: Absolute path to the configuration file that defines this lineage :returns: the RenewableCert object or None if a fatal error occurred :rtype: `storage.RenewableCert` or NoneType """ try: renewal_candidate = storage.RenewableCert( full_path, configuration.RenewerConfiguration(config)) except (errors.CertStorageError, IOError): logger.warning("Renewal configuration file %s is broken. Skipping.", full_path) logger.debug("Traceback was:\n%s", traceback.format_exc()) return None if "renewalparams" not in renewal_candidate.configuration: logger.warning( "Renewal configuration file %s lacks " "renewalparams. Skipping.", full_path) return None renewalparams = renewal_candidate.configuration["renewalparams"] if "authenticator" not in renewalparams: logger.warning( "Renewal configuration file %s does not specify " "an authenticator. Skipping.", full_path) return None # Now restore specific values along with their data types, if # those elements are present. try: _restore_required_config_elements(config, renewalparams) _restore_plugin_configs(config, renewalparams) except (ValueError, errors.Error) as error: logger.warning( "An error occurred while parsing %s. The error was %s. " "Skipping the file.", full_path, error.message) logger.debug("Traceback was:\n%s", traceback.format_exc()) return None try: for d in renewal_candidate.names(): cli.process_domain(config, d) except errors.ConfigurationError as error: logger.warning( "Renewal configuration file %s references a cert " "that contains an invalid domain name. The problem " "was: %s. Skipping.", full_path, error) return None return renewal_candidate
def test_ancient_webroot_renewal_conf(self, mock_set_by_cli): mock_set_by_cli.return_value = False rc_path = self._make_test_renewal_conf('sample-renewal-ancient.conf') args = mock.MagicMock(account=None, email=None, webroot_path=None) config = configuration.NamespaceConfig(args) lineage = storage.RenewableCert( rc_path, configuration.RenewerConfiguration(config)) renewalparams = lineage.configuration["renewalparams"] # pylint: disable=protected-access renewal._restore_webroot_config(config, renewalparams) self.assertEqual(config.webroot_path, ["/var/www/"])
def main(config=None): """Main function for autorenewer script.""" # TODO: Distinguish automated invocation from manual invocation, # perhaps by looking at sys.argv[0] and inhibiting automated # invocations if /etc/letsencrypt/renewal.conf defaults have # turned it off. (The boolean parameter should probably be # called renewer_enabled.) config = storage.config_with_defaults(config) # Now attempt to read the renewer config file and augment or replace # the renewer defaults with any options contained in that file. If # renewer_config_file is undefined or if the file is nonexistent or # empty, this .merge() will have no effect. TODO: when we have a more # elaborate renewer command line, we will presumably also be able to # specify a config file on the command line, which, if provided, should # take precedence over this one. config.merge(configobj.ConfigObj(config.get("renewer_config_file", ""))) for i in os.listdir(config["renewal_configs_dir"]): print "Processing", i if not i.endswith(".conf"): continue rc_config = configobj.ConfigObj( os.path.join(config["renewal_configs_dir"], i)) try: # TODO: Before trying to initialize the RenewableCert object, # we could check here whether the combination of the config # and the rc_config together disables all autorenewal and # autodeployment applicable to this cert. In that case, we # can simply continue and don't need to instantiate a # RenewableCert object for this cert at all, which could # dramatically improve performance for large deployments # where autorenewal is widely turned off. cert = storage.RenewableCert(rc_config) except ValueError: # This indicates an invalid renewal configuration file, such # as one missing a required parameter (in the future, perhaps # also one that is internally inconsistent or is missing a # required parameter). As a TODO, maybe we should warn the # user about the existence of an invalid or corrupt renewal # config rather than simply ignoring it. continue if cert.should_autodeploy(): cert.update_all_links_to(cert.latest_common_version()) # TODO: restart web server (invoke IInstaller.restart() method) notify.notify("Autodeployed a cert!!!", "root", "It worked!") # TODO: explain what happened if cert.should_autorenew(): # Note: not cert.current_version() because the basis for # the renewal is the latest version, even if it hasn't been # deployed yet! old_version = cert.latest_common_version() renew(cert, old_version) notify.notify("Autorenewed a cert!!!", "root", "It worked!")
def setUp(self): from letsencrypt import storage self.tempdir = tempfile.mkdtemp() os.makedirs(os.path.join(self.tempdir, "live", "example.org")) os.makedirs(os.path.join(self.tempdir, "archive", "example.org")) os.makedirs(os.path.join(self.tempdir, "configs")) defaults = configobj.ConfigObj() defaults["live_dir"] = os.path.join(self.tempdir, "live") defaults["archive_dir"] = os.path.join(self.tempdir, "archive") defaults["renewal_configs_dir"] = os.path.join(self.tempdir, "configs") config = configobj.ConfigObj() for kind in ALL_FOUR: config[kind] = os.path.join(self.tempdir, "live", "example.org", kind + ".pem") config.filename = os.path.join(self.tempdir, "configs", "example.org.conf") self.defaults = defaults # for main() test self.test_rc = storage.RenewableCert(config, defaults)
def setUp(self): from letsencrypt import storage self.tempdir = tempfile.mkdtemp() self.cli_config = configuration.RenewerConfiguration( namespace=mock.MagicMock(config_dir=self.tempdir)) # TODO: maybe provide RenewerConfiguration.make_dirs? os.makedirs(os.path.join(self.tempdir, "live", "example.org")) os.makedirs(os.path.join(self.tempdir, "archive", "example.org")) os.makedirs(os.path.join(self.tempdir, "configs")) config = configobj.ConfigObj() for kind in ALL_FOUR: config[kind] = os.path.join(self.tempdir, "live", "example.org", kind + ".pem") config.filename = os.path.join(self.tempdir, "configs", "example.org.conf") self.defaults = configobj.ConfigObj() self.test_rc = storage.RenewableCert(config, self.defaults, self.cli_config)
def setUp(self): from letsencrypt import storage self.tempdir = tempfile.mkdtemp() self.cli_config = configuration.RenewerConfiguration( namespace=mock.MagicMock( config_dir=self.tempdir, work_dir=self.tempdir, logs_dir=self.tempdir, )) # TODO: maybe provide RenewerConfiguration.make_dirs? # TODO: main() should create those dirs, c.f. #902 os.makedirs(os.path.join(self.tempdir, "live", "example.org")) os.makedirs(os.path.join(self.tempdir, "archive", "example.org")) os.makedirs(os.path.join(self.tempdir, "renewal")) config = configobj.ConfigObj() for kind in ALL_FOUR: config[kind] = os.path.join(self.tempdir, "live", "example.org", kind + ".pem") config.filename = os.path.join(self.tempdir, "renewal", "example.org.conf") config.write() self.config = config # 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. junk = open(os.path.join(self.tempdir, "renewal", "IGNORE.THIS"), "w") junk.write("This file should be ignored!") junk.close() self.defaults = configobj.ConfigObj() with mock.patch( "letsencrypt.storage.RenewableCert._check_symlinks") as check: check.return_value = True self.test_rc = storage.RenewableCert(config.filename, self.cli_config)