コード例 #1
0
    def _sat_incremental(self):
        # Exact responses don't matter, just path/response match
        if self.iteration == 0:
            # Only solve one of "0" required challs
            self.handler.responses["0"][1] = "onecomplete"
            self.handler.responses["0"][3] = None
            self.handler.responses["1"] = [None, None, "goodresp"]
            self.handler.paths["0"] = [1, 3]
            self.handler.paths["1"] = [2]
            # This is probably overkill... but set it anyway
            dv_c, c_c = self.handler._challenge_factory("0", [1, 3])
            self.handler.dv_c["0"], self.handler.cont_c["0"] = dv_c, c_c
            dv_c, c_c = self.handler._challenge_factory("1", [2])
            self.handler.dv_c["1"], self.handler.cont_c["1"] = dv_c, c_c

            self.iteration += 1

        elif self.iteration == 1:
            # Quick check to make sure it was actually completed.
            self.assertEqual(self.mock_acme_auth.call_args_list,
                             [mock.call("1")])
            self.handler.responses["0"][1] = "now_finish"
            self.handler.responses["0"][3] = "finally!"

        else:
            raise errors.LetsEncryptAuthHandlerError(
                "Failed incremental test: too many invocations")
コード例 #2
0
    def get_authorizations(self):
        """Retrieve all authorizations for challenges.

        :raises LetsEncryptAuthHandlerError: If unable to retrieve all
            authorizations

        """
        progress = True
        while self.msgs and progress:
            progress = False
            self._satisfy_challenges()

            delete_list = []

            for dom in self.domains:
                if self._path_satisfied(dom):
                    self.acme_authorization(dom)
                    delete_list.append(dom)

            # This avoids modifying while iterating over the list
            if delete_list:
                self._cleanup_state(delete_list)
                progress = True

        if not progress:
            raise errors.LetsEncryptAuthHandlerError(
                "Unable to solve challenges for requested names.")
コード例 #3
0
    def _satisfy_challenges(self):
        """Attempt to satisfy all saved challenge messages.

        .. todo:: It might be worth it to try different challenges to
            find one that doesn't throw an exception
        .. todo:: separate into more functions

        """
        logging.info("Performing the following challenges:")
        for dom in self.domains:
            self.paths[dom] = gen_challenge_path(
                self.msgs[dom].challenges,
                self._get_chall_pref(dom),
                self.msgs[dom].combinations)

            self.dv_c[dom], self.cont_c[dom] = self._challenge_factory(
                dom, self.paths[dom])

        # Flatten challs for authenticator functions and remove index
        # Order is important here as we will not expose the outside
        # Authenticator to our own indices.
        flat_cont = []
        flat_dv = []

        for dom in self.domains:
            flat_cont.extend(ichall.achall for ichall in self.cont_c[dom])
            flat_dv.extend(ichall.achall for ichall in self.dv_c[dom])

        cont_resp = []
        dv_resp = []
        try:
            if flat_cont:
                cont_resp = self.cont_auth.perform(flat_cont)
            if flat_dv:
                dv_resp = self.dv_auth.perform(flat_dv)
        # This will catch both specific types of errors.
        except errors.LetsEncryptAuthHandlerError as err:
            logging.critical("Failure in setting up challenges:")
            logging.critical(str(err))
            logging.info("Attempting to clean up outstanding challenges...")
            for dom in self.domains:
                self._cleanup_challenges(dom)

            raise errors.LetsEncryptAuthHandlerError(
                "Unable to perform challenges")

        logging.info("Ready for verification...")

        # Assemble Responses
        if cont_resp:
            self._assign_responses(cont_resp, self.cont_c)
        if dv_resp:
            self._assign_responses(dv_resp, self.dv_c)
コード例 #4
0
    def add_chall_msg(self, domain, msg, authkey):
        """Add a challenge message to the AuthHandler.

        :param str domain: domain for authorization

        :param msg: ACME "challenge" message
        :type msg: :class:`letsencrypt.acme.message.Challenge`

        :param authkey: authorized key for the challenge
        :type authkey: :class:`letsencrypt.client.le_util.Key`

        """
        if domain in self.domains:
            raise errors.LetsEncryptAuthHandlerError(
                "Multiple ACMEChallengeMessages for the same domain "
                "is not supported.")
        self.domains.append(domain)
        self.responses[domain] = [None] * len(msg.challenges)
        self.msgs[domain] = msg
        self.authkey[domain] = authkey
コード例 #5
0
def _find_smart_path(challs, preferences, combinations):
    """Find challenge path with server hints.

    Can be called if combinations is included. Function uses a simple
    ranking system to choose the combo with the lowest cost.

    """
    chall_cost = {}
    max_cost = 1
    for i, chall_cls in enumerate(preferences):
        chall_cost[chall_cls] = i
        max_cost += i

    # max_cost is now equal to sum(indices) + 1

    best_combo = []
    # Set above completing all of the available challenges
    best_combo_cost = max_cost

    combo_total = 0
    for combo in combinations:
        for challenge_index in combo:
            combo_total += chall_cost.get(challs[
                challenge_index].__class__, max_cost)

        if combo_total < best_combo_cost:
            best_combo = combo
            best_combo_cost = combo_total

        combo_total = 0

    if not best_combo:
        msg = ("Client does not support any combination of challenges that "
               "will satisfy the CA.")
        logging.fatal(msg)
        raise errors.LetsEncryptAuthHandlerError(msg)

    return best_combo