Example #1
0
def run(args, config, plugins):
    """Obtain a certificate and install."""
    if args.configurator is not None and (args.installer is not None
                                          or args.authenticator is not None):
        return ("Either --configurator or --authenticator/--installer"
                "pair, but not both, is allowed")

    if args.authenticator is not None or args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
        authenticator = display_ops.pick_authenticator(config,
                                                       args.authenticator,
                                                       plugins)
    else:
        # TODO: this assume that user doesn't want to pick authenticator
        #       and installer separately...
        authenticator = installer = display_ops.pick_configurator(
            config, args.configurator, plugins)

    if installer is None or authenticator is None:
        return "Configurator could not be determined"

    domains = _find_domains(args, installer)
    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)
    lineage = le_client.obtain_and_enroll_certificate(domains, authenticator,
                                                      installer, plugins)
    if not lineage:
        return "Certificate could not be obtained"
    le_client.deploy_certificate(domains, lineage.privkey, lineage.cert,
                                 lineage.chain)
    le_client.enhance_config(domains, args.redirect)
Example #2
0
def run(args, config, plugins):
    """Obtain a certificate and install."""
    if args.configurator is not None and (args.installer is not None or
                                          args.authenticator is not None):
        return ("Either --configurator or --authenticator/--installer"
                "pair, but not both, is allowed")

    if args.authenticator is not None or args.installer is not None:
        installer = display_ops.pick_installer(
            config, args.installer, plugins)
        authenticator = display_ops.pick_authenticator(
            config, args.authenticator, plugins)
    else:
        # TODO: this assumes that user doesn't want to pick authenticator
        #       and installer separately...
        authenticator = installer = display_ops.pick_configurator(
            config, args.configurator, plugins)

    if installer is None or authenticator is None:
        return "Configurator could not be determined"

    domains = _find_domains(args, installer)
    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)
    lineage = le_client.obtain_and_enroll_certificate(
        domains, authenticator, installer, plugins)
    if not lineage:
        return "Certificate could not be obtained"
    le_client.deploy_certificate(
        domains, lineage.privkey, lineage.cert, lineage.chain)
    le_client.enhance_config(domains, args.redirect)
Example #3
0
def auth(args, config, plugins):
    """Authenticate & obtain cert, but do not install it."""
    # XXX: Update for renewer / RenewableCert

    if args.domains is not None and args.csr is not None:
        # TODO: --csr could have a priority, when --domains is
        # supplied, check if CSR matches given domains?
        return "--domains and --csr are mutually exclusive"

    authenticator = display_ops.pick_authenticator(config, args.authenticator,
                                                   plugins)
    if authenticator is None:
        return "Authenticator could not be determined"

    if args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
    else:
        installer = None

    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)

    if args.csr is not None:
        certr, chain = le_client.obtain_certificate_from_csr(
            le_util.CSR(file=args.csr[0], data=args.csr[1], form="der"))
        le_client.save_certificate(certr, chain, args.cert_path,
                                   args.chain_path)
    else:
        domains = _find_domains(args, installer)
        if not le_client.obtain_and_enroll_certificate(domains, authenticator,
                                                       installer, plugins):
            return "Certificate could not be obtained"
Example #4
0
def run(args, config, plugins):
    """Obtain a certificate and install."""
    acc = _account_init(args, config)
    if acc is None:
        return None

    if args.configurator is not None and (args.installer is not None or args.authenticator is not None):
        return "Either --configurator or --authenticator/--installer" "pair, but not both, is allowed"

    if args.authenticator is not None or args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
        authenticator = display_ops.pick_authenticator(config, args.authenticator, plugins)
    else:
        # TODO: this assume that user doesn't want to pick authenticator
        #       and installer separately...
        authenticator = installer = display_ops.pick_configurator(config, args.configurator, plugins)

    if installer is None or authenticator is None:
        return "Configurator could not be determined"

    acme, doms = _common_run(args, config, acc, authenticator, installer)
    # TODO: Handle errors from _common_run?
    lineage = acme.obtain_and_enroll_certificate(doms, authenticator, installer, plugins)
    if not lineage:
        return "Certificate could not be obtained"
    acme.deploy_certificate(doms, lineage.privkey, lineage.cert, lineage.chain)
    acme.enhance_config(doms, args.redirect)
Example #5
0
def auth(args, config, plugins):
    """Authenticate & obtain cert, but do not install it."""

    if args.domains is not None and args.csr is not None:
        # TODO: --csr could have a priority, when --domains is
        # supplied, check if CSR matches given domains?
        return "--domains and --csr are mutually exclusive"

    authenticator = display_ops.pick_authenticator(config, args.authenticator,
                                                   plugins)
    if authenticator is None:
        return "Authenticator could not be determined"

    if args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
    else:
        installer = None

    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)

    # This is a special case; cert and chain are simply saved
    if args.csr is not None:
        certr, chain = le_client.obtain_certificate_from_csr(
            le_util.CSR(file=args.csr[0], data=args.csr[1], form="der"))
        le_client.save_certificate(certr, chain, args.cert_path,
                                   args.chain_path)
        _report_new_cert(args.cert_path)
    else:
        domains = _find_domains(args, installer)
        _auth_from_domains(le_client, config, domains, plugins)
Example #6
0
def auth(args, config, plugins):
    """Authenticate & obtain cert, but do not install it."""
    # XXX: Update for renewer / RenewableCert

    if args.domains is not None and args.csr is not None:
        # TODO: --csr could have a priority, when --domains is
        # supplied, check if CSR matches given domains?
        return "--domains and --csr are mutually exclusive"

    authenticator = display_ops.pick_authenticator(
        config, args.authenticator, plugins)
    if authenticator is None:
        return "Authenticator could not be determined"

    if args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
    else:
        installer = None

    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)

    if args.csr is not None:
        certr, chain = le_client.obtain_certificate_from_csr(le_util.CSR(
            file=args.csr[0], data=args.csr[1], form="der"))
        le_client.save_certificate(
            certr, chain, args.cert_path, args.chain_path)
    else:
        domains = _find_domains(args, installer)
        if not le_client.obtain_and_enroll_certificate(
                domains, authenticator, installer, plugins):
            return "Certificate could not be obtained"
Example #7
0
def auth(args, config, plugins):
    """Authenticate & obtain cert, but do not install it."""

    if args.domains is not None and args.csr is not None:
        # TODO: --csr could have a priority, when --domains is
        # supplied, check if CSR matches given domains?
        return "--domains and --csr are mutually exclusive"

    authenticator = display_ops.pick_authenticator(
        config, args.authenticator, plugins)
    if authenticator is None:
        return "Authenticator could not be determined"

    if args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
    else:
        installer = None

    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)

    # This is a special case; cert and chain are simply saved
    if args.csr is not None:
        certr, chain = le_client.obtain_certificate_from_csr(le_util.CSR(
            file=args.csr[0], data=args.csr[1], form="der"))
        le_client.save_certificate(
            certr, chain, args.cert_path, args.chain_path)
        _report_new_cert(args.cert_path)
    else:
        domains = _find_domains(args, installer)
        _auth_from_domains(le_client, config, domains, plugins)
Example #8
0
def choose_configurator_plugins(args, config, plugins, verb):  # pylint: disable=too-many-branches
    """
    Figure out which configurator we're going to use

    :raises error.PluginSelectionError if there was a problem
    """

    # Which plugins do we need?
    need_inst = need_auth = (verb == "run")
    if verb == "certonly":
        need_auth = True
    if verb == "install":
        need_inst = True
        if args.authenticator:
            logger.warn("Specifying an authenticator doesn't make sense in install mode")

    # Which plugins did the user request?
    req_inst = req_auth = args.configurator
    req_inst = set_configurator(req_inst, args.installer)
    req_auth = set_configurator(req_auth, args.authenticator)
    if args.nginx:
        req_inst = set_configurator(req_inst, "nginx")
        req_auth = set_configurator(req_auth, "nginx")
    if args.apache:
        req_inst = set_configurator(req_inst, "apache")
        req_auth = set_configurator(req_auth, "apache")
    if args.standalone:
        req_auth = set_configurator(req_auth, "standalone")
    logger.debug("Requested authenticator %s and installer %s", req_auth, req_inst)

    # Try to meet the user's request and/or ask them to pick plugins
    authenticator = installer = None
    if verb == "run" and req_auth == req_inst:
        # Unless the user has explicitly asked for different auth/install,
        # only consider offering a single choice
        authenticator = installer = display_ops.pick_configurator(config, req_inst, plugins)
    else:
        if need_inst or req_inst:
            installer = display_ops.pick_installer(config, req_inst, plugins)
        if need_auth:
            authenticator = display_ops.pick_authenticator(config, req_auth, plugins)
    logger.debug("Selected authenticator %s and installer %s", authenticator, installer)

    # StandaloneAuthenticator needs certain required ports to be available
    if isinstance(authenticator, StandaloneAuthenticator):
        # If a port is already in use, this will throw an MisconfigurationError
        authenticator.check_required_ports()

    # Report on any failures
    if need_inst and not installer:
        diagnose_configurator_problem("installer", req_inst, plugins)
    if need_auth and not authenticator:
        diagnose_configurator_problem("authenticator", req_auth, plugins)

    record_chosen_plugins(config, plugins, authenticator, installer)
    return installer, authenticator
Example #9
0
def choose_configurator_plugins(args, config, plugins, verb):
    """
    Figure out which configurator we're going to use

    :raises error.PluginSelectionError if there was a problem
    """

    # Which plugins do we need?
    need_inst = need_auth = (verb == "run")
    if verb == "auth":
        need_auth = True
    if verb == "install":
        need_inst = True
        if args.authenticator:
            logger.warn(
                "Specifying an authenticator doesn't make sense in install mode"
            )

    # Which plugins did the user request?
    req_inst = req_auth = args.configurator
    req_inst = set_configurator(req_inst, args.installer)
    req_auth = set_configurator(req_auth, args.authenticator)
    if args.nginx:
        req_inst = set_configurator(req_inst, "nginx")
        req_auth = set_configurator(req_auth, "nginx")
    if args.apache:
        req_inst = set_configurator(req_inst, "apache")
        req_auth = set_configurator(req_auth, "apache")
    if args.standalone:
        req_auth = set_configurator(req_auth, "standalone")
    logger.debug("Requested authenticator %s and installer %s", req_auth,
                 req_inst)

    # Try to meet the user's request and/or ask them to pick plugins
    authenticator = installer = None
    if verb == "run" and req_auth == req_inst:
        # Unless the user has explicitly asked for different auth/install,
        # only consider offering a single choice
        authenticator = installer = display_ops.pick_configurator(
            config, req_inst, plugins)
    else:
        if need_inst or req_inst:
            installer = display_ops.pick_installer(config, req_inst, plugins)
        if need_auth:
            authenticator = display_ops.pick_authenticator(
                config, req_auth, plugins)
    logger.debug("Selected authenticator %s and installer %s", authenticator,
                 installer)

    if need_inst and not installer:
        diagnose_configurator_problem("installer", req_inst, plugins)
    if need_auth and not authenticator:
        diagnose_configurator_problem("authenticator", req_auth, plugins)

    return installer, authenticator
Example #10
0
def choose_configurator_plugins(args, config, plugins, verb):
    """
    Figure out which configurator we're going to use

    :raises error.PluginSelectionError if there was a problem
    """

    # Which plugins do we need?
    need_inst = need_auth = (verb == "run")
    if verb == "certonly":
        need_auth = True
    if verb == "install":
        need_inst = True
        if args.authenticator:
            logger.warn("Specifying an authenticator doesn't make sense in install mode")

    # Which plugins did the user request?
    req_inst = req_auth = args.configurator
    req_inst = set_configurator(req_inst, args.installer)
    req_auth = set_configurator(req_auth, args.authenticator)
    if args.nginx:
        req_inst = set_configurator(req_inst, "nginx")
        req_auth = set_configurator(req_auth, "nginx")
    if args.apache:
        req_inst = set_configurator(req_inst, "apache")
        req_auth = set_configurator(req_auth, "apache")
    if args.standalone:
        req_auth = set_configurator(req_auth, "standalone")
    logger.debug("Requested authenticator %s and installer %s", req_auth, req_inst)

    # Try to meet the user's request and/or ask them to pick plugins
    authenticator = installer = None
    if verb == "run" and req_auth == req_inst:
        # Unless the user has explicitly asked for different auth/install,
        # only consider offering a single choice
        authenticator = installer = display_ops.pick_configurator(config, req_inst, plugins)
    else:
        if need_inst or req_inst:
            installer = display_ops.pick_installer(config, req_inst, plugins)
        if need_auth:
            authenticator = display_ops.pick_authenticator(config, req_auth, plugins)
    logger.debug("Selected authenticator %s and installer %s", authenticator, installer)

    if need_inst and not installer:
        diagnose_configurator_problem("installer", req_inst, plugins)
    if need_auth and not authenticator:
        diagnose_configurator_problem("authenticator", req_auth, plugins)

    return installer, authenticator
Example #11
0
def auth(args, config, plugins):
    """Obtain a certificate (no install)."""
    acc = _account_init(args, config)
    if acc is None:
        return None

    authenticator = display_ops.pick_authenticator(
        config, args.authenticator, plugins)
    if authenticator is None:
        return "Authenticator could not be determined"

    if args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
    else:
        installer = None

    acme, doms = _common_run(
        args, config, acc, authenticator=authenticator, installer=installer)
    acme.obtain_certificate(doms)
Example #12
0
def auth(args, config, plugins):
    """Obtain a certificate (no install)."""
    # XXX: Update for renewer / RenewableCert
    acc = _account_init(args, config)
    if acc is None:
        return None

    authenticator = display_ops.pick_authenticator(config, args.authenticator, plugins)
    if authenticator is None:
        return "Authenticator could not be determined"

    if args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
    else:
        installer = None

    # TODO: Handle errors from _common_run?
    acme, doms = _common_run(args, config, acc, authenticator=authenticator, installer=installer)
    if not acme.obtain_and_enroll_certificate(doms, authenticator, installer, plugins):
        return "Certificate could not be obtained"
Example #13
0
def run(args, config, plugins):  # pylint: disable=too-many-branches,too-many-locals
    """Obtain a certificate and install."""
    # Begin authenticator and installer setup
    if args.configurator is not None and (args.installer is not None or
                                          args.authenticator is not None):
        return ("Either --configurator or --authenticator/--installer"
                "pair, but not both, is allowed")

    if args.authenticator is not None or args.installer is not None:
        installer = display_ops.pick_installer(
            config, args.installer, plugins)
        authenticator = display_ops.pick_authenticator(
            config, args.authenticator, plugins)
    else:
        # TODO: this assumes that user doesn't want to pick authenticator
        #       and installer separately...
        authenticator = installer = display_ops.pick_configurator(
            config, args.configurator, plugins)

    if installer is None or authenticator is None:
        return "Configurator could not be determined"
    # End authenticator and installer setup

    domains = _find_domains(args, installer)

    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)

    lineage = _auth_from_domains(le_client, config, domains, plugins)

    le_client.deploy_certificate(
        domains, lineage.privkey, lineage.cert,
        lineage.chain, lineage.fullchain)
    le_client.enhance_config(domains, args.redirect)

    if len(lineage.available_versions("cert")) == 1:
        display_ops.success_installation(domains)
    else:
        display_ops.success_renewal(domains)
Example #14
0
def run(args, config, plugins):  # pylint: disable=too-many-branches,too-many-locals
    """Obtain a certificate and install."""
    # Begin authenticator and installer setup
    if args.configurator is not None and (args.installer is not None or
                                          args.authenticator is not None):
        return ("Either --configurator or --authenticator/--installer"
                "pair, but not both, is allowed")

    if args.authenticator is not None or args.installer is not None:
        installer = display_ops.pick_installer(
            config, args.installer, plugins)
        authenticator = display_ops.pick_authenticator(
            config, args.authenticator, plugins)
    else:
        # TODO: this assumes that user doesn't want to pick authenticator
        #       and installer separately...
        authenticator = installer = display_ops.pick_configurator(
            config, args.configurator, plugins)

    if installer is None or authenticator is None:
        return "Configurator could not be determined"
    # End authenticator and installer setup

    domains = _find_domains(args, installer)

    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)

    lineage = _auth_from_domains(le_client, config, domains, plugins)

    # TODO: We also need to pass the fullchain (for Nginx)
    le_client.deploy_certificate(
        domains, lineage.privkey, lineage.cert, lineage.chain)
    le_client.enhance_config(domains, args.redirect)

    if len(lineage.available_versions("cert")) == 1:
        display_ops.success_installation(domains)
    else:
        display_ops.success_renewal(domains)
Example #15
0
def auth(args, config, plugins):
    """Obtain a certificate (no install)."""
    # XXX: Update for renewer / RenewableCert
    acc = _account_init(args, config)
    if acc is None:
        return None

    authenticator = display_ops.pick_authenticator(
        config, args.authenticator, plugins)
    if authenticator is None:
        return "Authenticator could not be determined"

    if args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
    else:
        installer = None

    # TODO: Handle errors from _common_run?
    acme, doms = _common_run(
        args, config, acc, authenticator=authenticator, installer=installer)
    if not acme.obtain_and_enroll_certificate(doms, authenticator, installer,
                                              plugins):
        return "Certificate could not be obtained"
Example #16
0
def run(args, config, plugins):  # pylint: disable=too-many-branches,too-many-locals
    """Obtain a certificate and install."""
    if args.configurator is not None and (args.installer is not None
                                          or args.authenticator is not None):
        return ("Either --configurator or --authenticator/--installer"
                "pair, but not both, is allowed")

    if args.authenticator is not None or args.installer is not None:
        installer = display_ops.pick_installer(config, args.installer, plugins)
        authenticator = display_ops.pick_authenticator(config,
                                                       args.authenticator,
                                                       plugins)
    else:
        # TODO: this assumes that user doesn't want to pick authenticator
        #       and installer separately...
        authenticator = installer = display_ops.pick_configurator(
            config, args.configurator, plugins)

    if installer is None or authenticator is None:
        return "Configurator could not be determined"

    domains = _find_domains(args, installer)

    treat_as_renewal = False

    # Considering the possibility that the requested certificate is
    # related to an existing certificate.  (config.duplicate, which
    # is set with --duplicate, skips all of this logic and forces any
    # kind of certificate to be obtained with treat_as_renewal = False.)
    if not config.duplicate:
        identical_names_cert, subset_names_cert = _find_duplicative_certs(
            domains, config, configuration.RenewerConfiguration(config))
        # I am not sure whether that correctly reads the systemwide
        # configuration file.
        question = None
        if identical_names_cert is not None:
            question = (
                "You have an existing certificate that contains exactly the "
                "same domains you requested (ref: {0})\n\nDo you want to "
                "renew and replace this certificate with a newly-issued one?"
            ).format(identical_names_cert.configfile.filename)
        elif subset_names_cert is not None:
            question = (
                "You have an existing certificate that contains a portion of "
                "the domains you requested (ref: {0})\n\nIt contains these "
                "names: {1}\n\nYou requested these names for the new "
                "certificate: {2}.\n\nDo you want to replace this existing "
                "certificate with the new certificate?").format(
                    subset_names_cert.configfile.filename,
                    ", ".join(subset_names_cert.names()), ", ".join(domains))
        if question is None:
            # We aren't in a duplicative-names situation at all, so we don't
            # have to tell or ask the user anything about this.
            pass
        elif zope.component.getUtility(interfaces.IDisplay).yesno(
                question, "Replace", "Cancel"):
            treat_as_renewal = True
        else:
            reporter_util = zope.component.getUtility(interfaces.IReporter)
            reporter_util.add_message(
                "To obtain a new certificate that {0} an existing certificate "
                "in its domain-name coverage, you must use the --duplicate "
                "option.\n\nFor example:\n\n{1} --duplicate {2}".format(
                    "duplicates" if identical_names_cert is not None else
                    "overlaps with", sys.argv[0], " ".join(sys.argv[1:])),
                reporter_util.HIGH_PRIORITY)
            return 1

    # Attempting to obtain the certificate
    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)
    if treat_as_renewal:
        lineage = identical_names_cert if identical_names_cert is not None else subset_names_cert
        # TODO: Use existing privkey instead of generating a new one
        new_certr, new_chain, new_key, _ = le_client.obtain_certificate(
            domains)
        # TODO: Check whether it worked!
        lineage.save_successor(
            lineage.latest_common_version(),
            OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM,
                                            new_certr.body), new_key.pem,
            crypto_util.dump_pyopenssl_chain(new_chain))

        lineage.update_all_links_to(lineage.latest_common_version())
        # TODO: Check return value of save_successor
        # TODO: Also update lineage renewal config with any relevant
        #       configuration values from this attempt?
        le_client.deploy_certificate(domains, lineage.privkey, lineage.cert,
                                     lineage.chain)
        display_ops.success_renewal(domains)
    else:
        # TREAT AS NEW REQUEST
        lineage = le_client.obtain_and_enroll_certificate(
            domains, authenticator, installer, plugins)
        if not lineage:
            return "Certificate could not be obtained"
        # TODO: This treats the key as changed even when it wasn't
        # TODO: We also need to pass the fullchain (for Nginx)
        le_client.deploy_certificate(domains, lineage.privkey, lineage.cert,
                                     lineage.chain)
        le_client.enhance_config(domains, args.redirect)
        display_ops.success_installation(domains)
Example #17
0
def run(args, config, plugins):  # pylint: disable=too-many-branches,too-many-locals
    """Obtain a certificate and install."""
    if args.configurator is not None and (args.installer is not None or
                                          args.authenticator is not None):
        return ("Either --configurator or --authenticator/--installer"
                "pair, but not both, is allowed")

    if args.authenticator is not None or args.installer is not None:
        installer = display_ops.pick_installer(
            config, args.installer, plugins)
        authenticator = display_ops.pick_authenticator(
            config, args.authenticator, plugins)
    else:
        # TODO: this assumes that user doesn't want to pick authenticator
        #       and installer separately...
        authenticator = installer = display_ops.pick_configurator(
            config, args.configurator, plugins)

    if installer is None or authenticator is None:
        return "Configurator could not be determined"

    domains = _find_domains(args, installer)

    treat_as_renewal = False

    # Considering the possibility that the requested certificate is
    # related to an existing certificate.  (config.duplicate, which
    # is set with --duplicate, skips all of this logic and forces any
    # kind of certificate to be obtained with treat_as_renewal = False.)
    if not config.duplicate:
        identical_names_cert, subset_names_cert = _find_duplicative_certs(
            domains, config, configuration.RenewerConfiguration(config))
        # I am not sure whether that correctly reads the systemwide
        # configuration file.
        question = None
        if identical_names_cert is not None:
            question = (
                "You have an existing certificate that contains exactly the "
                "same domains you requested (ref: {0})\n\nDo you want to "
                "renew and replace this certificate with a newly-issued one?"
            ).format(identical_names_cert.configfile.filename)
        elif subset_names_cert is not None:
            question = (
                "You have an existing certificate that contains a portion of "
                "the domains you requested (ref: {0})\n\nIt contains these "
                "names: {1}\n\nYou requested these names for the new "
                "certificate: {2}.\n\nDo you want to replace this existing "
                "certificate with the new certificate?"
            ).format(subset_names_cert.configfile.filename,
                     ", ".join(subset_names_cert.names()),
                     ", ".join(domains))
        if question is None:
            # We aren't in a duplicative-names situation at all, so we don't
            # have to tell or ask the user anything about this.
            pass
        elif zope.component.getUtility(interfaces.IDisplay).yesno(
                question, "Replace", "Cancel"):
            treat_as_renewal = True
        else:
            reporter_util = zope.component.getUtility(interfaces.IReporter)
            reporter_util.add_message(
                "To obtain a new certificate that {0} an existing certificate "
                "in its domain-name coverage, you must use the --duplicate "
                "option.\n\nFor example:\n\n{1} --duplicate {2}".format(
                    "duplicates" if identical_names_cert is not None else
                    "overlaps with", sys.argv[0], " ".join(sys.argv[1:])),
                reporter_util.HIGH_PRIORITY)
            return 1

    # Attempting to obtain the certificate
    # TODO: Handle errors from _init_le_client?
    le_client = _init_le_client(args, config, authenticator, installer)
    if treat_as_renewal:
        lineage = identical_names_cert if identical_names_cert is not None else subset_names_cert
        # TODO: Use existing privkey instead of generating a new one
        new_certr, new_chain, new_key, _ = le_client.obtain_certificate(domains)
        # TODO: Check whether it worked!
        lineage.save_successor(
            lineage.latest_common_version(), OpenSSL.crypto.dump_certificate(
                OpenSSL.crypto.FILETYPE_PEM, new_certr.body),
            new_key.pem, crypto_util.dump_pyopenssl_chain(new_chain))

        lineage.update_all_links_to(lineage.latest_common_version())
        # TODO: Check return value of save_successor
        # TODO: Also update lineage renewal config with any relevant
        #       configuration values from this attempt?
        le_client.deploy_certificate(
            domains, lineage.privkey, lineage.cert, lineage.chain)
        display_ops.success_renewal(domains)
    else:
        # TREAT AS NEW REQUEST
        lineage = le_client.obtain_and_enroll_certificate(
            domains, authenticator, installer, plugins)
        if not lineage:
            return "Certificate could not be obtained"
        # TODO: This treats the key as changed even when it wasn't
        # TODO: We also need to pass the fullchain (for Nginx)
        le_client.deploy_certificate(
            domains, lineage.privkey, lineage.cert, lineage.chain)
        le_client.enhance_config(domains, args.redirect)
        display_ops.success_installation(domains)