Beispiel #1
0
    def setUp(self):
        from certbot.auth_handler import challb_to_achall
        from certbot.auth_handler import AuthHandler

        # Account and network are mocked...
        self.mock_net = mock.MagicMock()
        self.handler = AuthHandler(None, self.mock_net,
                                   mock.Mock(key="mock_key"), [])

        self.doms = ["0", "1", "2"]
        self.handler.authzr[self.doms[0]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[0],
            [acme_util.HTTP01, acme_util.TLSSNI01],
            [messages.STATUS_PENDING] * 2, False)

        self.handler.authzr[self.doms[1]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[1], acme_util.CHALLENGES,
            [messages.STATUS_PENDING] * 3, False)

        self.handler.authzr[self.doms[2]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[2], acme_util.CHALLENGES,
            [messages.STATUS_PENDING] * 3, False)

        self.chall_update = {}
        for dom in self.doms:
            self.chall_update[dom] = [
                challb_to_achall(challb, mock.Mock(key="dummy_key"), dom)
                for challb in self.handler.authzr[dom].body.challenges
            ]
Beispiel #2
0
class ChallengeFactoryTest(unittest.TestCase):
    # pylint: disable=protected-access

    def setUp(self):
        from certbot.auth_handler import AuthHandler

        # Account is mocked...
        self.handler = AuthHandler(None, None, mock.Mock(key="mock_key"), [])

        self.authzr = acme_util.gen_authzr(
            messages.STATUS_PENDING, "test", acme_util.CHALLENGES,
            [messages.STATUS_PENDING] * 6, False)

    def test_all(self):
        achalls = self.handler._challenge_factory(
            self.authzr, range(0, len(acme_util.CHALLENGES)))

        self.assertEqual(
            [achall.chall for achall in achalls], acme_util.CHALLENGES)

    def test_one_tls_sni(self):
        achalls = self.handler._challenge_factory(self.authzr, [1])

        self.assertEqual(
            [achall.chall for achall in achalls], [acme_util.TLSSNI01])

    def test_unrecognized(self):
        authzr = acme_util.gen_authzr(
             messages.STATUS_PENDING, "test",
             [mock.Mock(chall="chall", typ="unrecognized")],
             [messages.STATUS_PENDING])

        self.assertRaises(
             errors.Error, self.handler._challenge_factory, authzr, [0])
Beispiel #3
0
    def setUp(self):
        from certbot.auth_handler import challb_to_achall
        from certbot.auth_handler import AuthHandler, AnnotatedAuthzr

        # Account and network are mocked...
        self.mock_net = mock.MagicMock()
        self.handler = AuthHandler(None, self.mock_net,
                                   mock.Mock(key="mock_key"), [])

        self.doms = ["0", "1", "2"]
        self.aauthzrs = [
            AnnotatedAuthzr(
                acme_util.gen_authzr(messages.STATUS_PENDING, self.doms[0],
                                     [acme_util.HTTP01, acme_util.TLSSNI01],
                                     [messages.STATUS_PENDING] * 2, False),
                []),
            AnnotatedAuthzr(
                acme_util.gen_authzr(messages.STATUS_PENDING, self.doms[1],
                                     acme_util.CHALLENGES,
                                     [messages.STATUS_PENDING] * 3, False),
                []),
            AnnotatedAuthzr(
                acme_util.gen_authzr(messages.STATUS_PENDING, self.doms[2],
                                     acme_util.CHALLENGES,
                                     [messages.STATUS_PENDING] * 3, False), [])
        ]

        self.chall_update = {
        }  # type: Dict[int, achallenges.KeyAuthorizationAnnotatedChallenge]
        for i, aauthzr in enumerate(self.aauthzrs):
            self.chall_update[i] = [
                challb_to_achall(challb, mock.Mock(key="dummy_key"),
                                 self.doms[i])
                for challb in aauthzr.authzr.body.challenges
            ]
Beispiel #4
0
    def setUp(self):
        from certbot.auth_handler import AuthHandler

        # Account is mocked...
        self.handler = AuthHandler(None, None, mock.Mock(key="mock_key"), [])

        self.authzr = acme_util.gen_authzr(
            messages.STATUS_PENDING, "test", acme_util.CHALLENGES,
            [messages.STATUS_PENDING] * 6, False)
    def setUp(self):
        from certbot.auth_handler import challb_to_achall
        from certbot.auth_handler import AuthHandler

        # Account and network are mocked...
        self.mock_net = mock.MagicMock()
        self.handler = AuthHandler(
            None, self.mock_net, mock.Mock(key="mock_key"), [])

        self.doms = ["0", "1", "2"]
        self.handler.authzr[self.doms[0]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[0],
            [acme_util.HTTP01, acme_util.TLSSNI01],
            [messages.STATUS_PENDING] * 2, False)

        self.handler.authzr[self.doms[1]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[1],
            acme_util.CHALLENGES, [messages.STATUS_PENDING] * 3, False)

        self.handler.authzr[self.doms[2]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[2],
            acme_util.CHALLENGES, [messages.STATUS_PENDING] * 3, False)

        self.chall_update = {}
        for dom in self.doms:
            self.chall_update[dom] = [
                challb_to_achall(challb, mock.Mock(key="dummy_key"), dom)
                for challb in self.handler.authzr[dom].body.challenges]
Beispiel #6
0
    def setUp(self):
        from certbot.auth_handler import AuthHandler

        self.mock_auth = mock.MagicMock(name="ApacheConfigurator")

        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_auth.perform.side_effect = gen_auth_resp

        self.mock_account = mock.Mock(key=util.Key("file_path", "PEM"))
        self.mock_net = mock.MagicMock(spec=acme_client.Client)

        self.handler = AuthHandler(self.mock_auth, self.mock_net,
                                   self.mock_account)

        logging.disable(logging.CRITICAL)
Beispiel #7
0
    def setUp(self):
        from certbot.auth_handler import AuthHandler

        self.mock_display = mock.Mock()
        zope.component.provideUtility(self.mock_display, interfaces.IDisplay)
        zope.component.provideUtility(mock.Mock(debug_challenges=False),
                                      interfaces.IConfig)

        self.mock_auth = mock.MagicMock(name="ApacheConfigurator")

        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_auth.perform.side_effect = gen_auth_resp

        self.mock_account = mock.Mock(key=util.Key("file_path", "PEM"))
        self.mock_net = mock.MagicMock(spec=acme_client.Client)

        self.handler = AuthHandler(self.mock_auth, self.mock_net,
                                   self.mock_account, [])

        logging.disable(logging.CRITICAL)
    def setUp(self):
        from certbot.auth_handler import AuthHandler

        self.mock_auth = mock.MagicMock(name="ApacheConfigurator")

        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_auth.perform.side_effect = gen_auth_resp

        self.mock_account = mock.Mock(key=le_util.Key("file_path", "PEM"))
        self.mock_net = mock.MagicMock(spec=acme_client.Client)

        self.handler = AuthHandler(self.mock_auth, self.mock_net, self.mock_account)

        logging.disable(logging.CRITICAL)
Beispiel #9
0
    def setUp(self):
        from certbot.auth_handler import AuthHandler

        self.mock_display = mock.Mock()
        zope.component.provideUtility(
            self.mock_display, interfaces.IDisplay)
        zope.component.provideUtility(
            mock.Mock(debug_challenges=False), interfaces.IConfig)

        self.mock_auth = mock.MagicMock(name="ApacheConfigurator")

        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_auth.perform.side_effect = gen_auth_resp

        self.mock_account = mock.Mock(key=util.Key("file_path", "PEM"))
        self.mock_net = mock.MagicMock(spec=acme_client.Client)

        self.handler = AuthHandler(
            self.mock_auth, self.mock_net, self.mock_account, [])

        logging.disable(logging.CRITICAL)
Beispiel #10
0
class HandleAuthorizationsTest(unittest.TestCase):  # pylint: disable=too-many-public-methods
    """handle_authorizations test.

    This tests everything except for all functions under _poll_challenges.

    """

    def setUp(self):
        from certbot.auth_handler import AuthHandler

        self.mock_display = mock.Mock()
        zope.component.provideUtility(
            self.mock_display, interfaces.IDisplay)
        zope.component.provideUtility(
            mock.Mock(debug_challenges=False), interfaces.IConfig)

        self.mock_auth = mock.MagicMock(name="ApacheConfigurator")

        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_auth.perform.side_effect = gen_auth_resp

        self.mock_account = mock.Mock(key=util.Key("file_path", "PEM"))
        self.mock_net = mock.MagicMock(spec=acme_client.Client)
        self.mock_net.acme_version = 1
        self.mock_net.retry_after.side_effect = acme_client.Client.retry_after

        self.handler = AuthHandler(
            self.mock_auth, self.mock_net, self.mock_account, [])

        logging.disable(logging.CRITICAL)

    def tearDown(self):
        logging.disable(logging.NOTSET)

    def _test_name1_tls_sni_01_1_common(self, combos):
        authzr = gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES, combos=combos)
        mock_order = mock.MagicMock(authorizations=[authzr])

        self.mock_net.poll.side_effect = _gen_mock_on_poll(retry=1, wait_value=30)
        with mock.patch('certbot.auth_handler.time') as mock_time:
            authzr = self.handler.handle_authorizations(mock_order)

            self.assertEqual(self.mock_net.answer_challenge.call_count, 1)

            self.assertEqual(self.mock_net.poll.call_count, 2)  # Because there is one retry
            self.assertEqual(mock_time.sleep.call_count, 2)
            # Retry-After header is 30 seconds, but at the time sleep is invoked, several
            # instructions are executed, and next pool is in less than 30 seconds.
            self.assertTrue(mock_time.sleep.call_args_list[1][0][0] <= 30)
            # However, assert that we did not took the default value of 3 seconds.
            self.assertTrue(mock_time.sleep.call_args_list[1][0][0] > 3)

            self.assertEqual(self.mock_auth.cleanup.call_count, 1)
            # Test if list first element is TLSSNI01, use typ because it is an achall
            self.assertEqual(
                self.mock_auth.cleanup.call_args[0][0][0].typ, "tls-sni-01")

            self.assertEqual(len(authzr), 1)

    def test_name1_tls_sni_01_1_acme_1(self):
        self._test_name1_tls_sni_01_1_common(combos=True)

    def test_name1_tls_sni_01_1_acme_2(self):
        self.mock_net.acme_version = 2
        self._test_name1_tls_sni_01_1_common(combos=False)

    def test_name1_tls_sni_01_1_http_01_1_dns_1_acme_1(self):
        self.mock_net.poll.side_effect = _gen_mock_on_poll()
        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)
        self.mock_auth.get_chall_pref.return_value.append(challenges.DNS01)

        authzr = gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES, combos=False)
        mock_order = mock.MagicMock(authorizations=[authzr])
        authzr = self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        self.assertEqual(self.mock_net.poll.call_count, 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        # Test if list first element is TLSSNI01, use typ because it is an achall
        for achall in self.mock_auth.cleanup.call_args[0][0]:
            self.assertTrue(achall.typ in ["tls-sni-01", "http-01", "dns-01"])

        # Length of authorizations list
        self.assertEqual(len(authzr), 1)

    def test_name1_tls_sni_01_1_http_01_1_dns_1_acme_2(self):
        self.mock_net.acme_version = 2
        self.mock_net.poll.side_effect = _gen_mock_on_poll()
        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)
        self.mock_auth.get_chall_pref.return_value.append(challenges.DNS01)

        authzr = gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES, combos=False)
        mock_order = mock.MagicMock(authorizations=[authzr])
        authzr = self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_net.answer_challenge.call_count, 1)

        self.assertEqual(self.mock_net.poll.call_count, 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        cleaned_up_achalls = self.mock_auth.cleanup.call_args[0][0]
        self.assertEqual(len(cleaned_up_achalls), 1)
        self.assertEqual(cleaned_up_achalls[0].typ, "tls-sni-01")

        # Length of authorizations list
        self.assertEqual(len(authzr), 1)

    def _test_name3_tls_sni_01_3_common(self, combos):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES, combos=combos)

        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES),
                   gen_dom_authzr(domain="1", challs=acme_util.CHALLENGES),
                   gen_dom_authzr(domain="2", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)

        self.mock_net.poll.side_effect = _gen_mock_on_poll()
        authzr = self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        # Check poll call
        self.assertEqual(self.mock_net.poll.call_count, 3)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)

        self.assertEqual(len(authzr), 3)

    def test_name3_tls_sni_01_3_common_acme_1(self):
        self._test_name3_tls_sni_01_3_common(combos=True)

    def test_name3_tls_sni_01_3_common_acme_2(self):
        self.mock_net.acme_version = 2
        self._test_name3_tls_sni_01_3_common(combos=False)

    def test_debug_challenges(self):
        zope.component.provideUtility(
            mock.Mock(debug_challenges=True), interfaces.IConfig)
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)

        self.mock_net.poll.side_effect = _gen_mock_on_poll()

        self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_net.answer_challenge.call_count, 1)
        self.assertEqual(self.mock_display.notification.call_count, 1)

    def test_perform_failure(self):
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)

        self.mock_auth.perform.side_effect = errors.AuthorizationError

        self.assertRaises(
            errors.AuthorizationError, self.handler.handle_authorizations, mock_order)

    def test_max_retries_exceeded(self):
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)

        # We will return STATUS_PENDING twice before returning STATUS_VALID.
        self.mock_net.poll.side_effect = _gen_mock_on_poll(retry=2)

        with self.assertRaises(errors.AuthorizationError) as error:
            # We retry only once, so retries will be exhausted before STATUS_VALID is returned.
            self.handler.handle_authorizations(mock_order, False, 1)
        self.assertTrue('All authorizations were not finalized by the CA.' in str(error.exception))

    def test_no_domains(self):
        mock_order = mock.MagicMock(authorizations=[])
        self.assertRaises(errors.AuthorizationError, self.handler.handle_authorizations, mock_order)

    def _test_preferred_challenge_choice_common(self, combos):
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES, combos=combos)]
        mock_order = mock.MagicMock(authorizations=authzrs)

        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)

        self.handler.pref_challs.extend((challenges.HTTP01.typ,
                                         challenges.DNS01.typ,))

        self.mock_net.poll.side_effect = _gen_mock_on_poll()
        self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(
            self.mock_auth.cleanup.call_args[0][0][0].typ, "http-01")

    def test_preferred_challenge_choice_common_acme_1(self):
        self._test_preferred_challenge_choice_common(combos=True)

    def test_preferred_challenge_choice_common_acme_2(self):
        self.mock_net.acme_version = 2
        self._test_preferred_challenge_choice_common(combos=False)

    def _test_preferred_challenges_not_supported_common(self, combos):
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES, combos=combos)]
        mock_order = mock.MagicMock(authorizations=authzrs)
        self.handler.pref_challs.append(challenges.HTTP01.typ)
        self.assertRaises(
            errors.AuthorizationError, self.handler.handle_authorizations, mock_order)

    def test_preferred_challenges_not_supported_acme_1(self):
        self._test_preferred_challenges_not_supported_common(combos=True)

    def test_preferred_challenges_not_supported_acme_2(self):
        self.mock_net.acme_version = 2
        self._test_preferred_challenges_not_supported_common(combos=False)

    def test_dns_only_challenge_not_supported(self):
        authzrs = [gen_dom_authzr(domain="0", challs=[acme_util.DNS01])]
        mock_order = mock.MagicMock(authorizations=authzrs)
        self.assertRaises(
            errors.AuthorizationError, self.handler.handle_authorizations, mock_order)

    def test_perform_error(self):
        self.mock_auth.perform.side_effect = errors.AuthorizationError

        authzr = gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES, combos=True)
        mock_order = mock.MagicMock(authorizations=[authzr])
        self.assertRaises(errors.AuthorizationError, self.handler.handle_authorizations, mock_order)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(
            self.mock_auth.cleanup.call_args[0][0][0].typ, "tls-sni-01")

    def test_answer_error(self):
        self.mock_net.answer_challenge.side_effect = errors.AuthorizationError

        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)

        self.assertRaises(
            errors.AuthorizationError, self.handler.handle_authorizations, mock_order)
        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(
            self.mock_auth.cleanup.call_args[0][0][0].typ, "tls-sni-01")

    def test_incomplete_authzr_error(self):
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)
        self.mock_net.poll.side_effect = _gen_mock_on_poll(status=messages.STATUS_INVALID)

        with test_util.patch_get_utility():
            with self.assertRaises(errors.AuthorizationError) as error:
                self.handler.handle_authorizations(mock_order, False)
        self.assertTrue('Some challenges have failed.' in str(error.exception))
        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(
            self.mock_auth.cleanup.call_args[0][0][0].typ, "tls-sni-01")

    def test_best_effort(self):
        def _conditional_mock_on_poll(authzr):
            """This mock will invalidate one authzr, and invalidate the other one"""
            valid_mock = _gen_mock_on_poll(messages.STATUS_VALID)
            invalid_mock = _gen_mock_on_poll(messages.STATUS_INVALID)

            if authzr.body.identifier.value == 'will-be-invalid':
                return invalid_mock(authzr)
            return valid_mock(authzr)

        # Two authzrs. Only one will be valid.
        authzrs = [gen_dom_authzr(domain="will-be-valid", challs=acme_util.CHALLENGES),
                   gen_dom_authzr(domain="will-be-invalid", challs=acme_util.CHALLENGES)]
        self.mock_net.poll.side_effect = _conditional_mock_on_poll

        mock_order = mock.MagicMock(authorizations=authzrs)

        with mock.patch('certbot.auth_handler._report_failed_authzrs') as mock_report:
            valid_authzr = self.handler.handle_authorizations(mock_order, True)

        # Because best_effort=True, we did not blow up. Instead ...
        self.assertEqual(len(valid_authzr), 1)  # ... the valid authzr has been processed
        self.assertEqual(mock_report.call_count, 1)  # ... the invalid authzr has been reported

        self.mock_net.poll.side_effect = _gen_mock_on_poll(status=messages.STATUS_INVALID)

        with test_util.patch_get_utility():
            with self.assertRaises(errors.AuthorizationError) as error:
                self.handler.handle_authorizations(mock_order, True)

        # Despite best_effort=True, process will fail because no authzr is valid.
        self.assertTrue('All challenges have failed.' in str(error.exception))

    def test_validated_challenge_not_rerun(self):
        # With pending challenge, we expect the challenge to be tried, and fail.
        authzr = acme_util.gen_authzr(
                messages.STATUS_PENDING, "0",
                [acme_util.HTTP01],
                [messages.STATUS_PENDING], False)
        mock_order = mock.MagicMock(authorizations=[authzr])
        self.assertRaises(
            errors.AuthorizationError, self.handler.handle_authorizations, mock_order)

        # With validated challenge; we expect the challenge not be tried again, and succeed.
        authzr = acme_util.gen_authzr(
                messages.STATUS_VALID, "0",
                [acme_util.HTTP01],
                [messages.STATUS_VALID], False)
        mock_order = mock.MagicMock(authorizations=[authzr])
        self.handler.handle_authorizations(mock_order)

    @mock.patch("certbot.auth_handler.logger")
    def test_tls_sni_logs(self, logger):
        self._test_name1_tls_sni_01_1_common(combos=True)
        self.assertTrue("deprecated" in logger.warning.call_args[0][0])
Beispiel #11
0
    def setUp(self):
        from certbot.auth_handler import AuthHandler
        from certbot_external_auth.plugin import AuthenticatorOut

        self.name = 'certbot-external-auth'
        self.name_cfg = self.name.replace('-', '_') + '_'
        self.tempdir = tempfile.mkdtemp(dir=tempfile.gettempdir())
        self.config = configuration.NamespaceConfig(
            mock.MagicMock(**constants.CLI_DEFAULTS))

        self.patch_tls = mock.patch(
            'acme.challenges.TLSSNI01Response.simple_verify')
        self.patch_http = mock.patch(
            'acme.challenges.HTTP01Response.simple_verify')
        self.patch_dns = mock.patch(
            'acme.challenges.DNS01Response.simple_verify')

        self.patch_tls.start()
        self.patch_http.start()
        self.patch_dns.start()

        self.config.verb = "certonly"
        self.config.config_dir = os.path.join(self.tempdir, 'config')
        self.config.work_dir = os.path.join(self.tempdir, 'work')
        self.config.logs_dir = os.path.join(self.tempdir, 'logs')
        self.config.cert_path = constants.CLI_DEFAULTS['auth_cert_path']
        self.config.fullchain_path = constants.CLI_DEFAULTS['auth_chain_path']
        self.config.chain_path = constants.CLI_DEFAULTS['auth_chain_path']
        self.config.server = "example.com"
        self.config.__setattr__(self.name_cfg + 'handler', None)
        self.config.__setattr__(self.name_cfg + 'public_ip_logging_ok', True)
        self.config.__setattr__(self.name_cfg + 'test_mode', False)
        self.config.__setattr__(self.name_cfg + 'text_mode', False)
        self.config.__setattr__(self.name_cfg + 'dehydrated_dns', False)

        self.mock_display = mock.Mock()
        zope.component.provideUtility(self.mock_display, interfaces.IDisplay)
        zope.component.provideUtility(mock.Mock(debug_challenges=False),
                                      interfaces.IConfig)

        self.mock_auth = AuthenticatorOut(self.config, self.name)

        self.mock_auth.get_chall_pref = mock.MagicMock()
        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_data = []
        self.mock_json_out = mock.MagicMock(side_effect=self._update_data)
        self.mock_auth._json_out_and_wait = self.mock_json_out

        self.mock_auth.cleanup = mock.Mock()

        self.key_mock = mock.Mock()
        self.key_mock.key = mock.Mock()
        self.key_mock.key.file_path = 'PEM'
        self.key_mock.thumbprint = mock.MagicMock(
            return_value=b'00001234567890000')

        self.mock_account = mock.Mock(key=self.key_mock)
        self.mock_net = mock.MagicMock(spec=acme_client.Client)

        self.handler = AuthHandler(self.mock_auth, self.mock_net,
                                   self.mock_account, [])

        self.input_patch = mock.patch('six.moves.input')
        self.input_patch.start()

        logging.disable(logging.CRITICAL)
Beispiel #12
0
class PollChallengesTest(unittest.TestCase):
    # pylint: disable=protected-access
    """Test poll challenges."""

    def setUp(self):
        from certbot.auth_handler import challb_to_achall
        from certbot.auth_handler import AuthHandler

        # Account and network are mocked...
        self.mock_net = mock.MagicMock()
        self.handler = AuthHandler(
            None, self.mock_net, mock.Mock(key="mock_key"), [])

        self.doms = ["0", "1", "2"]
        self.handler.authzr[self.doms[0]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[0],
            [acme_util.HTTP01, acme_util.TLSSNI01],
            [messages.STATUS_PENDING] * 2, False)

        self.handler.authzr[self.doms[1]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[1],
            acme_util.CHALLENGES, [messages.STATUS_PENDING] * 3, False)

        self.handler.authzr[self.doms[2]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[2],
            acme_util.CHALLENGES, [messages.STATUS_PENDING] * 3, False)

        self.chall_update = {}
        for dom in self.doms:
            self.chall_update[dom] = [
                challb_to_achall(challb, mock.Mock(key="dummy_key"), dom)
                for challb in self.handler.authzr[dom].body.challenges]

    @mock.patch("certbot.auth_handler.time")
    def test_poll_challenges(self, unused_mock_time):
        self.mock_net.poll.side_effect = self._mock_poll_solve_one_valid
        self.handler._poll_challenges(self.chall_update, False)

        for authzr in self.handler.authzr.values():
            self.assertEqual(authzr.body.status, messages.STATUS_VALID)

    @mock.patch("certbot.auth_handler.time")
    def test_poll_challenges_failure_best_effort(self, unused_mock_time):
        self.mock_net.poll.side_effect = self._mock_poll_solve_one_invalid
        self.handler._poll_challenges(self.chall_update, True)

        for authzr in self.handler.authzr.values():
            self.assertEqual(authzr.body.status, messages.STATUS_PENDING)

    @mock.patch("certbot.auth_handler.time")
    @test_util.patch_get_utility()
    def test_poll_challenges_failure(self, unused_mock_time, unused_mock_zope):
        self.mock_net.poll.side_effect = self._mock_poll_solve_one_invalid
        self.assertRaises(
            errors.AuthorizationError, self.handler._poll_challenges,
            self.chall_update, False)

    @mock.patch("certbot.auth_handler.time")
    def test_unable_to_find_challenge_status(self, unused_mock_time):
        from certbot.auth_handler import challb_to_achall
        self.mock_net.poll.side_effect = self._mock_poll_solve_one_valid
        self.chall_update[self.doms[0]].append(
            challb_to_achall(acme_util.DNS01_P, "key", self.doms[0]))
        self.assertRaises(
            errors.AuthorizationError, self.handler._poll_challenges,
            self.chall_update, False)

    def test_verify_authzr_failure(self):
        self.assertRaises(
            errors.AuthorizationError, self.handler.verify_authzr_complete)

    def _mock_poll_solve_one_valid(self, authzr):
        # Pending here because my dummy script won't change the full status.
        # Basically it didn't raise an error and it stopped earlier than
        # Making all challenges invalid which would make mock_poll_solve_one
        # change authzr to invalid
        return self._mock_poll_solve_one_chall(authzr, messages.STATUS_VALID)

    def _mock_poll_solve_one_invalid(self, authzr):
        return self._mock_poll_solve_one_chall(authzr, messages.STATUS_INVALID)

    def _mock_poll_solve_one_chall(self, authzr, desired_status):
        # pylint: disable=no-self-use
        """Dummy method that solves one chall at a time to desired_status.

        When all are solved.. it changes authzr.status to desired_status

        """
        new_challbs = authzr.body.challenges
        for challb in authzr.body.challenges:
            if challb.status != desired_status:
                new_challbs = tuple(
                    challb_temp if challb_temp != challb
                    else acme_util.chall_to_challb(challb.chall, desired_status)
                    for challb_temp in authzr.body.challenges
                )
                break

        if all(test_challb.status == desired_status
               for test_challb in new_challbs):
            status_ = desired_status
        else:
            status_ = authzr.body.status

        new_authzr = messages.AuthorizationResource(
            uri=authzr.uri,
            new_cert_uri=authzr.new_cert_uri,
            body=messages.Authorization(
                identifier=authzr.body.identifier,
                challenges=new_challbs,
                combinations=authzr.body.combinations,
                status=status_,
            ),
        )
        return (new_authzr, "response")
Beispiel #13
0
class GetAuthorizationsTest(unittest.TestCase):
    """get_authorizations test.

    This tests everything except for all functions under _poll_challenges.

    """
    def setUp(self):
        from certbot.auth_handler import AuthHandler
        from certbot_external_auth.plugin import AuthenticatorOut

        self.name = 'certbot-external-auth'
        self.name_cfg = self.name.replace('-', '_') + '_'
        self.tempdir = tempfile.mkdtemp(dir=tempfile.gettempdir())
        self.config = configuration.NamespaceConfig(
            mock.MagicMock(**constants.CLI_DEFAULTS))

        self.patch_tls = mock.patch(
            'acme.challenges.TLSSNI01Response.simple_verify')
        self.patch_http = mock.patch(
            'acme.challenges.HTTP01Response.simple_verify')
        self.patch_dns = mock.patch(
            'acme.challenges.DNS01Response.simple_verify')

        self.patch_tls.start()
        self.patch_http.start()
        self.patch_dns.start()

        self.config.verb = "certonly"
        self.config.config_dir = os.path.join(self.tempdir, 'config')
        self.config.work_dir = os.path.join(self.tempdir, 'work')
        self.config.logs_dir = os.path.join(self.tempdir, 'logs')
        self.config.cert_path = constants.CLI_DEFAULTS['auth_cert_path']
        self.config.fullchain_path = constants.CLI_DEFAULTS['auth_chain_path']
        self.config.chain_path = constants.CLI_DEFAULTS['auth_chain_path']
        self.config.server = "example.com"
        self.config.__setattr__(self.name_cfg + 'handler', None)
        self.config.__setattr__(self.name_cfg + 'public_ip_logging_ok', True)
        self.config.__setattr__(self.name_cfg + 'test_mode', False)
        self.config.__setattr__(self.name_cfg + 'text_mode', False)
        self.config.__setattr__(self.name_cfg + 'dehydrated_dns', False)

        self.mock_display = mock.Mock()
        zope.component.provideUtility(self.mock_display, interfaces.IDisplay)
        zope.component.provideUtility(mock.Mock(debug_challenges=False),
                                      interfaces.IConfig)

        self.mock_auth = AuthenticatorOut(self.config, self.name)

        self.mock_auth.get_chall_pref = mock.MagicMock()
        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_data = []
        self.mock_json_out = mock.MagicMock(side_effect=self._update_data)
        self.mock_auth._json_out_and_wait = self.mock_json_out

        self.mock_auth.cleanup = mock.Mock()

        self.key_mock = mock.Mock()
        self.key_mock.key = mock.Mock()
        self.key_mock.key.file_path = 'PEM'
        self.key_mock.thumbprint = mock.MagicMock(
            return_value=b'00001234567890000')

        self.mock_account = mock.Mock(key=self.key_mock)
        self.mock_net = mock.MagicMock(spec=acme_client.Client)

        self.handler = AuthHandler(self.mock_auth, self.mock_net,
                                   self.mock_account, [])

        self.input_patch = mock.patch('six.moves.input')
        self.input_patch.start()

        logging.disable(logging.CRITICAL)

    def tearDown(self):
        shutil.rmtree(self.tempdir)
        logging.disable(logging.NOTSET)
        self.input_patch.stop()
        self.patch_tls.stop()
        self.patch_http.stop()
        self.patch_dns.stop()

    def _help_output(self, args):
        "Run a command, and return the output string for scrutiny"

        output = six.StringIO()

        def write_msg(message, *args, **kwargs):  # pylint: disable=missing-docstring,unused-argument
            output.write(message)

        with mock.patch('certbot.main.sys.stdout', new=output):
            with test_util.patch_get_utility() as mock_get_utility:
                mock_get_utility().notification.side_effect = write_msg
                with mock.patch('certbot.main.sys.stderr'):
                    self.assertRaises(SystemExit, self._unmocked_parse, args,
                                      output)

        return output.getvalue()

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name1_tls_sni_01_1(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        mock_poll.side_effect = self._validate_all

        authzr = self.handler.get_authorizations(["0"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 1)

        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][0]
        self.assertEqual(list(six.iterkeys(chall_update)), ["0"])
        self.assertEqual(len(chall_update.values()), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        # Test if list first element is TLSSNI01, use typ because it is an achall
        self.assertEqual(self.mock_auth.cleanup.call_args[0][0][0].typ,
                         "tls-sni-01")

        self.assertEqual(len(authzr), 1)
        self.assertEqual(self.mock_json_out.call_count, 1)
        self.assertEqual(len(self.mock_data), 1)
        self.assertIn('cmd', self.mock_data[0])
        self.assertIn('token', self.mock_data[0])
        self.assertIn('validation', self.mock_data[0])
        self.assertTrue(len(self.mock_data[0]['validation']) > 5)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name1_tls_sni_01_1_http_01_1_dns_1(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES, combos=False)

        mock_poll.side_effect = self._validate_all
        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)
        self.mock_auth.get_chall_pref.return_value.append(challenges.DNS01)

        authzr = self.handler.get_authorizations(["0"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][0]
        self.assertEqual(list(six.iterkeys(chall_update)), ["0"])
        self.assertEqual(len(chall_update.values()), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        # Test if list first element is TLSSNI01, use typ because it is an achall
        for achall in self.mock_auth.cleanup.call_args[0][0]:
            self.assertTrue(achall.typ in ["tls-sni-01", "http-01", "dns-01"])

        # Length of authorizations list
        self.assertEqual(len(authzr), 1)
        self.assertEqual(self.mock_json_out.call_count, 3)
        self.assertEqual(len(self.mock_data), 3)
        for msg in self.mock_data:
            self.assertIn('cmd', msg)
            self.assertIn('token', msg)
            self.assertIn('validation', msg)
            self.assertTrue(len(msg['validation']) > 5)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name3_tls_sni_01_3(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        mock_poll.side_effect = self._validate_all

        with mock.patch('certbot.util.safe_open') as mock_open:
            mock_open.return_value = mock.MagicMock()
            authzr = self.handler.get_authorizations(["0", "1", "2"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        # Check poll call
        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][0]
        self.assertEqual(len(list(six.iterkeys(chall_update))), 3)
        self.assertTrue("0" in list(six.iterkeys(chall_update)))
        self.assertEqual(len(chall_update["0"]), 1)
        self.assertTrue("1" in list(six.iterkeys(chall_update)))
        self.assertEqual(len(chall_update["1"]), 1)
        self.assertTrue("2" in list(six.iterkeys(chall_update)))
        self.assertEqual(len(chall_update["2"]), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)

        self.assertEqual(len(authzr), 3)

        self.assertEqual(self.mock_json_out.call_count, 3)
        self.assertEqual(len(self.mock_data), 3)
        for msg in self.mock_data:
            self.assertIn('cmd', msg)
            self.assertIn('token', msg)
            self.assertIn('validation', msg)
            self.assertTrue(len(msg['validation']) > 5)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_debug_challenges(self, mock_poll):
        zope.component.provideUtility(mock.Mock(debug_challenges=True),
                                      interfaces.IConfig)
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        mock_poll.side_effect = self._validate_all

        self.handler.get_authorizations(["0"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 1)
        self.assertEqual(self.mock_display.notification.call_count, 1)

    def test_perform_failure(self):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        self.mock_auth.perform = mock.Mock()
        self.mock_auth.perform.side_effect = errors.AuthorizationError

        self.assertRaises(errors.AuthorizationError,
                          self.handler.get_authorizations, ["0"])

    def test_no_domains(self):
        self.assertRaises(errors.AuthorizationError,
                          self.handler.get_authorizations, [])

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_preferred_challenge_choice(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        mock_poll.side_effect = self._validate_all
        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)

        self.handler.pref_challs.extend((
            challenges.HTTP01.typ,
            challenges.DNS01.typ,
        ))

        self.handler.get_authorizations(["0"])

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(self.mock_auth.cleanup.call_args[0][0][0].typ,
                         "http-01")

    def test_preferred_challenges_not_supported(self):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)
        self.handler.pref_challs.append(challenges.HTTP01.typ)
        self.assertRaises(errors.AuthorizationError,
                          self.handler.get_authorizations, ["0"])

    def _validate_all(self, unused_1, unused_2):
        for dom in six.iterkeys(self.handler.authzr):
            azr = self.handler.authzr[dom]
            self.handler.authzr[dom] = acme_util.gen_authzr(
                messages.STATUS_VALID, dom,
                [challb.chall for challb in azr.body.challenges],
                [messages.STATUS_VALID] * len(azr.body.challenges),
                azr.body.combinations)

    def _update_data(self, x):
        self.mock_data.append(x)
Beispiel #14
0
class GetAuthorizationsTest(unittest.TestCase):
    """get_authorizations test.

    This tests everything except for all functions under _poll_challenges.

    """

    def setUp(self):
        from certbot.auth_handler import AuthHandler

        self.mock_auth = mock.MagicMock(name="ApacheConfigurator")

        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_auth.perform.side_effect = gen_auth_resp

        self.mock_account = mock.Mock(key=util.Key("file_path", "PEM"))
        self.mock_net = mock.MagicMock(spec=acme_client.Client)

        self.handler = AuthHandler(
            self.mock_auth, self.mock_net, self.mock_account, [])

        logging.disable(logging.CRITICAL)

    def tearDown(self):
        logging.disable(logging.NOTSET)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name1_tls_sni_01_1(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        mock_poll.side_effect = self._validate_all

        authzr = self.handler.get_authorizations(["0"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 1)

        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][0]
        self.assertEqual(list(six.iterkeys(chall_update)), ["0"])
        self.assertEqual(len(chall_update.values()), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        # Test if list first element is TLSSNI01, use typ because it is an achall
        self.assertEqual(
            self.mock_auth.cleanup.call_args[0][0][0].typ, "tls-sni-01")

        self.assertEqual(len(authzr), 1)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name1_tls_sni_01_1_http_01_1_dns_1(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES, combos=False)

        mock_poll.side_effect = self._validate_all
        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)
        self.mock_auth.get_chall_pref.return_value.append(challenges.DNS01)

        authzr = self.handler.get_authorizations(["0"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][0]
        self.assertEqual(list(six.iterkeys(chall_update)), ["0"])
        self.assertEqual(len(chall_update.values()), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        # Test if list first element is TLSSNI01, use typ because it is an achall
        for achall in self.mock_auth.cleanup.call_args[0][0]:
            self.assertTrue(achall.typ in ["tls-sni-01", "http-01", "dns-01"])

        # Length of authorizations list
        self.assertEqual(len(authzr), 1)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name3_tls_sni_01_3(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        mock_poll.side_effect = self._validate_all

        authzr = self.handler.get_authorizations(["0", "1", "2"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        # Check poll call
        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][0]
        self.assertEqual(len(list(six.iterkeys(chall_update))), 3)
        self.assertTrue("0" in list(six.iterkeys(chall_update)))
        self.assertEqual(len(chall_update["0"]), 1)
        self.assertTrue("1" in list(six.iterkeys(chall_update)))
        self.assertEqual(len(chall_update["1"]), 1)
        self.assertTrue("2" in list(six.iterkeys(chall_update)))
        self.assertEqual(len(chall_update["2"]), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)

        self.assertEqual(len(authzr), 3)

    def test_perform_failure(self):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)
        self.mock_auth.perform.side_effect = errors.AuthorizationError

        self.assertRaises(
            errors.AuthorizationError, self.handler.get_authorizations, ["0"])

    def test_no_domains(self):
        self.assertRaises(errors.AuthorizationError, self.handler.get_authorizations, [])

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_preferred_challenge_choice(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        mock_poll.side_effect = self._validate_all
        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)

        self.handler.pref_challs.extend((challenges.HTTP01.typ,
                                         challenges.DNS01.typ,))

        self.handler.get_authorizations(["0"])

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(
            self.mock_auth.cleanup.call_args[0][0][0].typ, "http-01")

    def test_preferred_challenges_not_supported(self):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)
        self.handler.pref_challs.append(challenges.HTTP01.typ)
        self.assertRaises(
            errors.AuthorizationError, self.handler.get_authorizations, ["0"])

    def _validate_all(self, unused_1, unused_2):
        for dom in six.iterkeys(self.handler.authzr):
            azr = self.handler.authzr[dom]
            self.handler.authzr[dom] = acme_util.gen_authzr(
                messages.STATUS_VALID,
                dom,
                [challb.chall for challb in azr.body.challenges],
                [messages.STATUS_VALID] * len(azr.body.challenges),
                azr.body.combinations)
Beispiel #15
0
class PollChallengesTest(unittest.TestCase):
    # pylint: disable=protected-access
    """Test poll challenges."""
    def setUp(self):
        from certbot.auth_handler import challb_to_achall
        from certbot.auth_handler import AuthHandler

        # Account and network are mocked...
        self.mock_net = mock.MagicMock()
        self.handler = AuthHandler(None, self.mock_net,
                                   mock.Mock(key="mock_key"), [])

        self.doms = ["0", "1", "2"]
        self.handler.authzr[self.doms[0]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[0],
            [acme_util.HTTP01, acme_util.TLSSNI01],
            [messages.STATUS_PENDING] * 2, False)

        self.handler.authzr[self.doms[1]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[1], acme_util.CHALLENGES,
            [messages.STATUS_PENDING] * 3, False)

        self.handler.authzr[self.doms[2]] = acme_util.gen_authzr(
            messages.STATUS_PENDING, self.doms[2], acme_util.CHALLENGES,
            [messages.STATUS_PENDING] * 3, False)

        self.chall_update = {}
        for dom in self.doms:
            self.chall_update[dom] = [
                challb_to_achall(challb, mock.Mock(key="dummy_key"), dom)
                for challb in self.handler.authzr[dom].body.challenges
            ]

    @mock.patch("certbot.auth_handler.time")
    def test_poll_challenges(self, unused_mock_time):
        self.mock_net.poll.side_effect = self._mock_poll_solve_one_valid
        self.handler._poll_challenges(self.chall_update, False)

        for authzr in self.handler.authzr.values():
            self.assertEqual(authzr.body.status, messages.STATUS_VALID)

    @mock.patch("certbot.auth_handler.time")
    def test_poll_challenges_failure_best_effort(self, unused_mock_time):
        self.mock_net.poll.side_effect = self._mock_poll_solve_one_invalid
        self.handler._poll_challenges(self.chall_update, True)

        for authzr in self.handler.authzr.values():
            self.assertEqual(authzr.body.status, messages.STATUS_PENDING)

    @mock.patch("certbot.auth_handler.time")
    @test_util.patch_get_utility()
    def test_poll_challenges_failure(self, unused_mock_time, unused_mock_zope):
        self.mock_net.poll.side_effect = self._mock_poll_solve_one_invalid
        self.assertRaises(errors.AuthorizationError,
                          self.handler._poll_challenges, self.chall_update,
                          False)

    @mock.patch("certbot.auth_handler.time")
    def test_unable_to_find_challenge_status(self, unused_mock_time):
        from certbot.auth_handler import challb_to_achall
        self.mock_net.poll.side_effect = self._mock_poll_solve_one_valid
        self.chall_update[self.doms[0]].append(
            challb_to_achall(acme_util.DNS01_P, "key", self.doms[0]))
        self.assertRaises(errors.AuthorizationError,
                          self.handler._poll_challenges, self.chall_update,
                          False)

    def test_verify_authzr_failure(self):
        self.assertRaises(errors.AuthorizationError,
                          self.handler.verify_authzr_complete)

    def _mock_poll_solve_one_valid(self, authzr):
        # Pending here because my dummy script won't change the full status.
        # Basically it didn't raise an error and it stopped earlier than
        # Making all challenges invalid which would make mock_poll_solve_one
        # change authzr to invalid
        return self._mock_poll_solve_one_chall(authzr, messages.STATUS_VALID)

    def _mock_poll_solve_one_invalid(self, authzr):
        return self._mock_poll_solve_one_chall(authzr, messages.STATUS_INVALID)

    def _mock_poll_solve_one_chall(self, authzr, desired_status):
        # pylint: disable=no-self-use
        """Dummy method that solves one chall at a time to desired_status.

        When all are solved.. it changes authzr.status to desired_status

        """
        new_challbs = authzr.body.challenges
        for challb in authzr.body.challenges:
            if challb.status != desired_status:
                new_challbs = tuple(
                    challb_temp if challb_temp != challb else acme_util.
                    chall_to_challb(challb.chall, desired_status)
                    for challb_temp in authzr.body.challenges)
                break

        if all(test_challb.status == desired_status
               for test_challb in new_challbs):
            status_ = desired_status
        else:
            status_ = authzr.body.status

        new_authzr = messages.AuthorizationResource(
            uri=authzr.uri,
            body=messages.Authorization(
                identifier=authzr.body.identifier,
                challenges=new_challbs,
                combinations=authzr.body.combinations,
                status=status_,
            ),
        )
        return new_authzr, "response"
Beispiel #16
0
class HandleAuthorizationsTest(unittest.TestCase):
    """handle_authorizations test.

    This tests everything except for all functions under _poll_challenges.

    """
    def setUp(self):
        from certbot.auth_handler import AuthHandler

        self.mock_display = mock.Mock()
        zope.component.provideUtility(self.mock_display, interfaces.IDisplay)
        zope.component.provideUtility(mock.Mock(debug_challenges=False),
                                      interfaces.IConfig)

        self.mock_auth = mock.MagicMock(name="ApacheConfigurator")

        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_auth.perform.side_effect = gen_auth_resp

        self.mock_account = mock.Mock(key=util.Key("file_path", "PEM"))
        self.mock_net = mock.MagicMock(spec=acme_client.Client)
        self.mock_net.acme_version = 1

        self.handler = AuthHandler(self.mock_auth, self.mock_net,
                                   self.mock_account, [])

        logging.disable(logging.CRITICAL)

    def tearDown(self):
        logging.disable(logging.NOTSET)

    def _test_name1_tls_sni_01_1_common(self, combos):
        authzr = gen_dom_authzr(domain="0",
                                challs=acme_util.CHALLENGES,
                                combos=combos)
        mock_order = mock.MagicMock(authorizations=[authzr])

        with mock.patch("certbot.auth_handler.AuthHandler._poll_challenges"
                        ) as mock_poll:
            mock_poll.side_effect = self._validate_all
            authzr = self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_net.answer_challenge.call_count, 1)

        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][1]
        self.assertEqual(list(six.iterkeys(chall_update)), [0])
        self.assertEqual(len(chall_update.values()), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        # Test if list first element is TLSSNI01, use typ because it is an achall
        self.assertEqual(self.mock_auth.cleanup.call_args[0][0][0].typ,
                         "tls-sni-01")

        self.assertEqual(len(authzr), 1)

    def test_name1_tls_sni_01_1_acme_1(self):
        self._test_name1_tls_sni_01_1_common(combos=True)

    def test_name1_tls_sni_01_1_acme_2(self):
        self.mock_net.acme_version = 2
        self._test_name1_tls_sni_01_1_common(combos=False)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name1_tls_sni_01_1_http_01_1_dns_1_acme_1(self, mock_poll):
        mock_poll.side_effect = self._validate_all
        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)
        self.mock_auth.get_chall_pref.return_value.append(challenges.DNS01)

        authzr = gen_dom_authzr(domain="0",
                                challs=acme_util.CHALLENGES,
                                combos=False)
        mock_order = mock.MagicMock(authorizations=[authzr])
        authzr = self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][1]
        self.assertEqual(list(six.iterkeys(chall_update)), [0])
        self.assertEqual(len(chall_update.values()), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        # Test if list first element is TLSSNI01, use typ because it is an achall
        for achall in self.mock_auth.cleanup.call_args[0][0]:
            self.assertTrue(achall.typ in ["tls-sni-01", "http-01", "dns-01"])

        # Length of authorizations list
        self.assertEqual(len(authzr), 1)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name1_tls_sni_01_1_http_01_1_dns_1_acme_2(self, mock_poll):
        self.mock_net.acme_version = 2
        mock_poll.side_effect = self._validate_all
        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)
        self.mock_auth.get_chall_pref.return_value.append(challenges.DNS01)

        authzr = gen_dom_authzr(domain="0",
                                challs=acme_util.CHALLENGES,
                                combos=False)
        mock_order = mock.MagicMock(authorizations=[authzr])
        authzr = self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_net.answer_challenge.call_count, 1)

        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][1]
        self.assertEqual(list(six.iterkeys(chall_update)), [0])
        self.assertEqual(len(chall_update.values()), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        cleaned_up_achalls = self.mock_auth.cleanup.call_args[0][0]
        self.assertEqual(len(cleaned_up_achalls), 1)
        self.assertEqual(cleaned_up_achalls[0].typ, "tls-sni-01")

        # Length of authorizations list
        self.assertEqual(len(authzr), 1)

    def _test_name3_tls_sni_01_3_common(self, combos):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES, combos=combos)

        authzrs = [
            gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES),
            gen_dom_authzr(domain="1", challs=acme_util.CHALLENGES),
            gen_dom_authzr(domain="2", challs=acme_util.CHALLENGES)
        ]
        mock_order = mock.MagicMock(authorizations=authzrs)
        with mock.patch("certbot.auth_handler.AuthHandler._poll_challenges"
                        ) as mock_poll:
            mock_poll.side_effect = self._validate_all
            authzr = self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        # Check poll call
        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][1]
        self.assertEqual(len(list(six.iterkeys(chall_update))), 3)
        self.assertTrue(0 in list(six.iterkeys(chall_update)))
        self.assertEqual(len(chall_update[0]), 1)
        self.assertTrue(1 in list(six.iterkeys(chall_update)))
        self.assertEqual(len(chall_update[1]), 1)
        self.assertTrue(2 in list(six.iterkeys(chall_update)))
        self.assertEqual(len(chall_update[2]), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)

        self.assertEqual(len(authzr), 3)

    def test_name3_tls_sni_01_3_common_acme_1(self):
        self._test_name3_tls_sni_01_3_common(combos=True)

    def test_name3_tls_sni_01_3_common_acme_2(self):
        self.mock_net.acme_version = 2
        self._test_name3_tls_sni_01_3_common(combos=False)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_debug_challenges(self, mock_poll):
        zope.component.provideUtility(mock.Mock(debug_challenges=True),
                                      interfaces.IConfig)
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)

        mock_poll.side_effect = self._validate_all

        self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_net.answer_challenge.call_count, 1)
        self.assertEqual(self.mock_display.notification.call_count, 1)

    def test_perform_failure(self):
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)

        self.mock_auth.perform.side_effect = errors.AuthorizationError

        self.assertRaises(errors.AuthorizationError,
                          self.handler.handle_authorizations, mock_order)

    def test_no_domains(self):
        mock_order = mock.MagicMock(authorizations=[])
        self.assertRaises(errors.AuthorizationError,
                          self.handler.handle_authorizations, mock_order)

    def _test_preferred_challenge_choice_common(self, combos):
        authzrs = [
            gen_dom_authzr(domain="0",
                           challs=acme_util.CHALLENGES,
                           combos=combos)
        ]
        mock_order = mock.MagicMock(authorizations=authzrs)

        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)

        self.handler.pref_challs.extend((
            challenges.HTTP01.typ,
            challenges.DNS01.typ,
        ))

        with mock.patch("certbot.auth_handler.AuthHandler._poll_challenges"
                        ) as mock_poll:
            mock_poll.side_effect = self._validate_all
            self.handler.handle_authorizations(mock_order)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(self.mock_auth.cleanup.call_args[0][0][0].typ,
                         "http-01")

    def test_preferred_challenge_choice_common_acme_1(self):
        self._test_preferred_challenge_choice_common(combos=True)

    def test_preferred_challenge_choice_common_acme_2(self):
        self.mock_net.acme_version = 2
        self._test_preferred_challenge_choice_common(combos=False)

    def _test_preferred_challenges_not_supported_common(self, combos):
        authzrs = [
            gen_dom_authzr(domain="0",
                           challs=acme_util.CHALLENGES,
                           combos=combos)
        ]
        mock_order = mock.MagicMock(authorizations=authzrs)
        self.handler.pref_challs.append(challenges.HTTP01.typ)
        self.assertRaises(errors.AuthorizationError,
                          self.handler.handle_authorizations, mock_order)

    def test_preferred_challenges_not_supported_acme_1(self):
        self._test_preferred_challenges_not_supported_common(combos=True)

    def test_preferred_challenges_not_supported_acme_2(self):
        self.mock_net.acme_version = 2
        self._test_preferred_challenges_not_supported_common(combos=False)

    def test_dns_only_challenge_not_supported(self):
        authzrs = [gen_dom_authzr(domain="0", challs=[acme_util.DNS01])]
        mock_order = mock.MagicMock(authorizations=authzrs)
        self.assertRaises(errors.AuthorizationError,
                          self.handler.handle_authorizations, mock_order)

    def test_perform_error(self):
        self.mock_auth.perform.side_effect = errors.AuthorizationError

        authzr = gen_dom_authzr(domain="0",
                                challs=acme_util.CHALLENGES,
                                combos=True)
        mock_order = mock.MagicMock(authorizations=[authzr])
        self.assertRaises(errors.AuthorizationError,
                          self.handler.handle_authorizations, mock_order)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(self.mock_auth.cleanup.call_args[0][0][0].typ,
                         "tls-sni-01")

    @mock.patch("certbot.auth_handler.AuthHandler._respond")
    def test_respond_error(self, mock_respond):
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)
        mock_respond.side_effect = errors.AuthorizationError

        self.assertRaises(errors.AuthorizationError,
                          self.handler.handle_authorizations, mock_order)
        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(self.mock_auth.cleanup.call_args[0][0][0].typ,
                         "tls-sni-01")

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    @mock.patch("certbot.auth_handler.AuthHandler.verify_authzr_complete")
    def test_incomplete_authzr_error(self, mock_verify, mock_poll):
        authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)]
        mock_order = mock.MagicMock(authorizations=authzrs)
        mock_verify.side_effect = errors.AuthorizationError
        mock_poll.side_effect = self._validate_all

        self.assertRaises(errors.AuthorizationError,
                          self.handler.handle_authorizations, mock_order)
        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        self.assertEqual(self.mock_auth.cleanup.call_args[0][0][0].typ,
                         "tls-sni-01")

    def _validate_all(self, aauthzrs, unused_1, unused_2):
        for i, aauthzr in enumerate(aauthzrs):
            azr = aauthzr.authzr
            updated_azr = acme_util.gen_authzr(
                messages.STATUS_VALID, azr.body.identifier.value,
                [challb.chall for challb in azr.body.challenges],
                [messages.STATUS_VALID] * len(azr.body.challenges),
                azr.body.combinations)
            aauthzrs[i] = type(aauthzr)(updated_azr, aauthzr.achalls)
Beispiel #17
0
class GetAuthorizationsTest(unittest.TestCase):
    """get_authorizations test.

    This tests everything except for all functions under _poll_challenges.

    """
    def setUp(self):
        from certbot.auth_handler import AuthHandler

        self.mock_auth = mock.MagicMock(name="ApacheConfigurator")

        self.mock_auth.get_chall_pref.return_value = [challenges.TLSSNI01]

        self.mock_auth.perform.side_effect = gen_auth_resp

        self.mock_account = mock.Mock(key=util.Key("file_path", "PEM"))
        self.mock_net = mock.MagicMock(spec=acme_client.Client)

        self.handler = AuthHandler(self.mock_auth, self.mock_net,
                                   self.mock_account)

        logging.disable(logging.CRITICAL)

    def tearDown(self):
        logging.disable(logging.NOTSET)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name1_tls_sni_01_1(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        mock_poll.side_effect = self._validate_all

        authzr = self.handler.get_authorizations(["0"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 1)

        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][0]
        self.assertEqual(chall_update.keys(), ["0"])
        self.assertEqual(len(chall_update.values()), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        # Test if list first element is TLSSNI01, use typ because it is an achall
        self.assertEqual(self.mock_auth.cleanup.call_args[0][0][0].typ,
                         "tls-sni-01")

        self.assertEqual(len(authzr), 1)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name1_tls_sni_01_1_http_01_1_dns_1(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES, combos=False)

        mock_poll.side_effect = self._validate_all
        self.mock_auth.get_chall_pref.return_value.append(challenges.HTTP01)
        self.mock_auth.get_chall_pref.return_value.append(challenges.DNS)

        authzr = self.handler.get_authorizations(["0"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][0]
        self.assertEqual(chall_update.keys(), ["0"])
        self.assertEqual(len(chall_update.values()), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)
        # Test if list first element is TLSSNI01, use typ because it is an achall
        for achall in self.mock_auth.cleanup.call_args[0][0]:
            self.assertTrue(achall.typ in ["tls-sni-01", "http-01", "dns"])

        # Length of authorizations list
        self.assertEqual(len(authzr), 1)

    @mock.patch("certbot.auth_handler.AuthHandler._poll_challenges")
    def test_name3_tls_sni_01_3(self, mock_poll):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)

        mock_poll.side_effect = self._validate_all

        authzr = self.handler.get_authorizations(["0", "1", "2"])

        self.assertEqual(self.mock_net.answer_challenge.call_count, 3)

        # Check poll call
        self.assertEqual(mock_poll.call_count, 1)
        chall_update = mock_poll.call_args[0][0]
        self.assertEqual(len(chall_update.keys()), 3)
        self.assertTrue("0" in chall_update.keys())
        self.assertEqual(len(chall_update["0"]), 1)
        self.assertTrue("1" in chall_update.keys())
        self.assertEqual(len(chall_update["1"]), 1)
        self.assertTrue("2" in chall_update.keys())
        self.assertEqual(len(chall_update["2"]), 1)

        self.assertEqual(self.mock_auth.cleanup.call_count, 1)

        self.assertEqual(len(authzr), 3)

    def test_perform_failure(self):
        self.mock_net.request_domain_challenges.side_effect = functools.partial(
            gen_dom_authzr, challs=acme_util.CHALLENGES)
        self.mock_auth.perform.side_effect = errors.AuthorizationError

        self.assertRaises(errors.AuthorizationError,
                          self.handler.get_authorizations, ["0"])

    def test_no_domains(self):
        self.assertRaises(errors.AuthorizationError,
                          self.handler.get_authorizations, [])

    def _validate_all(self, unused_1, unused_2):
        for dom in self.handler.authzr.keys():
            azr = self.handler.authzr[dom]
            self.handler.authzr[dom] = acme_util.gen_authzr(
                messages.STATUS_VALID, dom,
                [challb.chall for challb in azr.body.challenges],
                [messages.STATUS_VALID] * len(azr.body.challenges),
                azr.body.combinations)