Example #1
0
    def setUp(self):
        from certbot.plugins.script import Authenticator
        self.auth_return_value = "return from auth\n"
        self.script_nonexec = create_script(b'# empty')
        self.script_exec = create_script_exec(b'echo "return from auth\n"')
        self.config = mock.MagicMock(
            script_auth=self.script_exec,
            script_cleanup=self.script_exec,
            pref_challs=[
                challenges.Challenge.TYPES["http-01"],
                challenges.Challenge.TYPES["dns-01"],
                challenges.Challenge.TYPES["tls-sni-01"]
            ])

        self.tlssni_config = mock.MagicMock(
            script_auth=self.script_exec,
            script_cleanup=self.script_exec,
            pref_challs=[challenges.Challenge.TYPES["tls-sni-01"]])

        self.nochall_config = mock.MagicMock(
            script_auth=self.script_exec,
            script_cleanup=self.script_exec,
        )

        self.default = Authenticator(config=self.config, name="script")
        self.onlytlssni = Authenticator(config=self.tlssni_config,
                                        name="script")
        self.nochall = Authenticator(config=self.nochall_config, name="script")

        self.http01 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.HTTP01_P, domain="foo.com", account_key=KEY)
        self.dns01 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.DNS01_P, domain="foo.com", account_key=KEY)

        self.achalls = [self.http01, self.dns01]
Example #2
0
    def setUp(self):
        kwargs = {
            "chall": acme_util.HTTP01,
            "uri": "uri",
            "status": messages.STATUS_INVALID,
            "error": messages.Error.with_code("tls", detail="detail"),
        }

        # Prevent future regressions if the error type changes
        self.assertTrue(kwargs["error"].description is not None)

        self.http01 = achallenges.KeyAuthorizationAnnotatedChallenge(
            # pylint: disable=star-args
            challb=messages.ChallengeBody(**kwargs),
            domain="example.com",
            account_key="key")

        kwargs["chall"] = acme_util.TLSSNI01
        self.tls_sni_same = achallenges.KeyAuthorizationAnnotatedChallenge(
            # pylint: disable=star-args
            challb=messages.ChallengeBody(**kwargs),
            domain="example.com",
            account_key="key")

        kwargs["error"] = messages.Error(typ="dnssec", detail="detail")
        self.tls_sni_diff = achallenges.KeyAuthorizationAnnotatedChallenge(
            # pylint: disable=star-args
            challb=messages.ChallengeBody(**kwargs),
            domain="foo.bar",
            account_key="key")
Example #3
0
    def test_perform2(self):
        domain = b'localhost'
        key = jose.JWK.load(test_util.load_vector('rsa512_key.pem'))
        http_01 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.HTTP01_P, domain=domain, account_key=key)
        tls_sni_01 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.TLSSNI01_P, domain=domain, account_key=key)

        self.auth.servers = mock.MagicMock()

        def _run(port, tls):  # pylint: disable=unused-argument
            return "server{0}".format(port)

        self.auth.servers.run.side_effect = _run
        responses = self.auth.perform2([http_01, tls_sni_01])

        self.assertTrue(isinstance(responses, list))
        self.assertEqual(2, len(responses))
        self.assertTrue(isinstance(responses[0], challenges.HTTP01Response))
        self.assertTrue(isinstance(responses[1], challenges.TLSSNI01Response))

        self.assertEqual(self.auth.servers.run.mock_calls, [
            mock.call(4321, challenges.HTTP01),
            mock.call(1234, challenges.TLSSNI01),
        ])
        self.assertEqual(self.auth.served, {
            "server1234": set([tls_sni_01]),
            "server4321": set([http_01]),
        })
        self.assertEqual(1, len(self.auth.http_01_resources))
        self.assertEqual(1, len(self.auth.certs))
        self.assertEqual(list(self.auth.http_01_resources), [
            acme_standalone.HTTP01RequestHandler.HTTP01Resource(
                acme_util.HTTP01, responses[0], mock.ANY)
        ])
Example #4
0
    def test_perform(self, mock_restart, mock_perform):
        # Only tests functionality specific to configurator.perform
        # Note: As more challenges are offered this will have to be expanded
        achall1 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=messages.ChallengeBody(
                chall=challenges.TLSSNI01(token="kNdwjwOeX0I_A8DXt9Msmg"),
                uri="https://ca.org/chall0_uri",
                status=messages.Status("pending"),
            ),
            domain="localhost",
            account_key=self.rsa512jwk)
        achall2 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=messages.ChallengeBody(
                chall=challenges.TLSSNI01(token="m8TdO1qik4JVFtgPPurJmg"),
                uri="https://ca.org/chall1_uri",
                status=messages.Status("pending"),
            ),
            domain="example.com",
            account_key=self.rsa512jwk)

        expected = [
            achall1.response(self.rsa512jwk),
            achall2.response(self.rsa512jwk),
        ]

        mock_perform.return_value = expected
        responses = self.config.perform([achall1, achall2])

        self.assertEqual(mock_perform.call_count, 1)
        self.assertEqual(responses, expected)
        self.assertEqual(mock_restart.call_count, 1)
Example #5
0
    def _get_achalls(cls):
        domain = b'localhost'
        key = jose.JWK.load(test_util.load_vector('rsa512_key.pem'))
        http_01 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.HTTP01_P, domain=domain, account_key=key)
        tls_sni_01 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.TLSSNI01_P, domain=domain, account_key=key)

        return [http_01, tls_sni_01]
Example #6
0
class TLSSNI01Test(unittest.TestCase):
    """Tests for certbot.plugins.common.TLSSNI01."""

    auth_key = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem"))
    achalls = [
        achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.TLSSNI01(token=b'token1'), "pending"),
            domain="encryption-example.demo",
            account_key=auth_key),
        achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.TLSSNI01(token=b'token2'), "pending"),
            domain="certbot.demo",
            account_key=auth_key),
    ]

    def setUp(self):
        from certbot.plugins.common import TLSSNI01
        self.sni = TLSSNI01(configurator=mock.MagicMock())

    def test_add_chall(self):
        self.sni.add_chall(self.achalls[0], 0)
        self.assertEqual(1, len(self.sni.achalls))
        self.assertEqual([0], self.sni.indices)

    def test_setup_challenge_cert(self):
        # This is a helper function that can be used for handling
        # open context managers more elegantly. It avoids dealing with
        # __enter__ and __exit__ calls.
        # http://www.voidspace.org.uk/python/mock/helpers.html#mock.mock_open
        mock_open, mock_safe_open = mock.mock_open(), mock.mock_open()

        response = challenges.TLSSNI01Response()
        achall = mock.MagicMock()
        key = test_util.load_pyopenssl_private_key("rsa512_key.pem")
        achall.response_and_validation.return_value = (response, (
            test_util.load_cert("cert.pem"), key))

        with mock.patch("certbot.plugins.common.open", mock_open, create=True):
            with mock.patch("certbot.plugins.common.util.safe_open",
                            mock_safe_open):
                # pylint: disable=protected-access
                self.assertEqual(
                    response,
                    self.sni._setup_challenge_cert(achall, "randomS1"))

        # pylint: disable=no-member
        mock_open.assert_called_once_with(self.sni.get_cert_path(achall), "wb")
        mock_open.return_value.write.assert_called_once_with(
            test_util.load_vector("cert.pem"))
        mock_safe_open.assert_called_once_with(self.sni.get_key_path(achall),
                                               "wb",
                                               chmod=0o400)
        mock_safe_open.return_value.write.assert_called_once_with(
            OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key))
Example #7
0
 def test_same_vhost(self):
     vhost = next(v for v in self.config.vhosts if v.name == "certbot.demo")
     achalls = [
         achallenges.KeyAuthorizationAnnotatedChallenge(
             challb=acme_util.chall_to_challb(
                 challenges.HTTP01(token=((b'a' * 16))),
                 "pending"),
             domain=vhost.name, account_key=self.account_key),
         achallenges.KeyAuthorizationAnnotatedChallenge(
             challb=acme_util.chall_to_challb(
                 challenges.HTTP01(token=((b'b' * 16))),
                 "pending"),
             domain=next(iter(vhost.aliases)), account_key=self.account_key)
     ]
     self.common_perform_test(achalls, [vhost])
Example #8
0
 def test_it(self):
     self.assertEqual(
         self._call(acme_util.HTTP01_P),
         achallenges.KeyAuthorizationAnnotatedChallenge(
             challb=acme_util.HTTP01_P, account_key="account_key",
             domain="domain"),
     )
Example #9
0
class BaseAuthenticatorTest:
    """
    A base test class to reduce duplication between test code for DNS Authenticator Plugins.

    Assumes:
     * That subclasses also subclass unittest.TestCase
     * That the authenticator is stored as self.auth
    """

    achall = achallenges.KeyAuthorizationAnnotatedChallenge(
        challb=acme_util.DNS01, domain=DOMAIN, account_key=KEY)

    def test_more_info(self):
        self.assertTrue(isinstance(self.auth.more_info(), str))  # pylint: disable=no-member

    def test_get_chall_pref(self):
        self.assertEqual(self.auth.get_chall_pref(None), [challenges.DNS01])  # pylint: disable=no-member

    def test_parser_arguments(self):
        m = mock.MagicMock()
        self.auth.add_parser_arguments(m)  # pylint: disable=no-member

        m.assert_any_call('propagation-seconds',
                          type=int,
                          default=mock.ANY,
                          help=mock.ANY)
Example #10
0
    def setUp(self, *args, **kwargs):
        super(ApacheHttp01Test, self).setUp(*args, **kwargs)

        self.account_key = self.rsa512jwk
        self.achalls = []  # type: List[achallenges.KeyAuthorizationAnnotatedChallenge]
        vh_truth = util.get_vh_truth(
            self.temp_dir, "debian_apache_2_4/multiple_vhosts")
        # Takes the vhosts for encryption-example.demo, certbot.demo, and
        # vhost.in.rootconf
        self.vhosts = [vh_truth[0], vh_truth[3], vh_truth[10]]

        for i in range(NUM_ACHALLS):
            self.achalls.append(
                achallenges.KeyAuthorizationAnnotatedChallenge(
                    challb=acme_util.chall_to_challb(
                        challenges.HTTP01(token=((chr(ord('a') + i).encode() * 16))),
                        "pending"),
                    domain=self.vhosts[i].name, account_key=self.account_key))

        modules = ["rewrite", "authz_core", "authz_host"]
        for mod in modules:
            self.config.parser.modules.add("mod_{0}.c".format(mod))
            self.config.parser.modules.add(mod + "_module")

        from certbot_apache.http_01 import ApacheHttp01
        self.http = ApacheHttp01(self.config)
Example #11
0
    def test_perform_and_cleanup(self, mock_revert, mock_restart,
                                 mock_http_perform):
        # Only tests functionality specific to configurator.perform
        # Note: As more challenges are offered this will have to be expanded
        achall = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=messages.ChallengeBody(
                chall=challenges.HTTP01(token=b"m8TdO1qik4JVFtgPPurJmg"),
                uri="https://ca.org/chall1_uri",
                status=messages.Status("pending"),
            ),
            domain="example.com",
            account_key=self.rsa512jwk)

        expected = [
            achall.response(self.rsa512jwk),
        ]

        mock_http_perform.return_value = expected[:]
        responses = self.config.perform([achall])

        self.assertEqual(mock_http_perform.call_count, 1)
        self.assertEqual(responses, expected)

        self.config.cleanup([achall])
        self.assertEqual(0, self.config._chall_out)  # pylint: disable=protected-access
        self.assertEqual(mock_revert.call_count, 1)
        self.assertEqual(mock_restart.call_count, 2)
Example #12
0
class WebrootActionTest(unittest.TestCase):
    """Tests for webroot argparse actions."""

    achall = achallenges.KeyAuthorizationAnnotatedChallenge(
        challb=acme_util.HTTP01_P, domain="thing.com", account_key=KEY)

    def setUp(self):
        from certbot.plugins.webroot import Authenticator
        self.path = tempfile.mkdtemp()
        self.parser = argparse.ArgumentParser()
        self.parser.add_argument("-d",
                                 "--domains",
                                 action="append",
                                 default=[])
        Authenticator.inject_parser_options(self.parser, "webroot")

    def test_webroot_map_action(self):
        args = self.parser.parse_args(
            ["--webroot-map",
             json.dumps({'thing.com': self.path})])
        self.assertEqual(args.webroot_map["thing.com"], self.path)

    def test_domain_before_webroot(self):
        args = self.parser.parse_args("-d {0} -w {1}".format(
            self.achall.domain, self.path).split())
        config = self._get_config_after_perform(args)
        self.assertEqual(config.webroot_map[self.achall.domain], self.path)

    def test_domain_before_webroot_error(self):
        self.assertRaises(errors.PluginError, self.parser.parse_args,
                          "-d foo -w bar -w baz".split())
        self.assertRaises(errors.PluginError, self.parser.parse_args,
                          "-d foo -w bar -d baz -w qux".split())

    def test_multiwebroot(self):
        args = self.parser.parse_args("-w {0} -d {1} -w {2} -d bar".format(
            self.path, self.achall.domain, tempfile.mkdtemp()).split())
        self.assertEqual(args.webroot_map[self.achall.domain], self.path)
        config = self._get_config_after_perform(args)
        self.assertEqual(config.webroot_map[self.achall.domain], self.path)

    def test_webroot_map_partial_without_perform(self):
        # This test acknowledges the fact that webroot_map content will be partial if webroot
        # plugin perform method is not invoked (corner case when all auths are already valid).
        # To not be a problem, the webroot_path must always been conserved during renew.
        # This condition is challenged by:
        # certbot.tests.renewal_tests::RenewalTest::test_webroot_params_conservation
        # See https://github.com/certbot/certbot/pull/7095 for details.
        other_webroot_path = tempfile.mkdtemp()
        args = self.parser.parse_args("-w {0} -d {1} -w {2} -d bar".format(
            self.path, self.achall.domain, other_webroot_path).split())
        self.assertEqual(args.webroot_map, {self.achall.domain: self.path})
        self.assertEqual(args.webroot_path, [self.path, other_webroot_path])

    def _get_config_after_perform(self, config):
        from certbot.plugins.webroot import Authenticator
        auth = Authenticator(config, "webroot")
        auth.perform([self.achall])
        return auth.config
Example #13
0
    def get_achalls(self):
        """Return testing achallenges."""
        account_key = self.rsa512jwk
        achall1 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.TLSSNI01(
                    token="jIq_Xy1mXGN37tb4L6Xj_es58fW571ZNyXekdZzhh7Q"),
                "pending"),
            domain="encryption-example.demo", account_key=account_key)
        achall2 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.TLSSNI01(
                    token="uqnaPzxtrndteOqtrXb0Asl5gOJfWAnnx6QJyvcmlDU"),
                "pending"),
            domain="certbot.demo", account_key=account_key)

        return account_key, achall1, achall2
Example #14
0
 def test_anonymous_vhost(self):
     vhosts = [v for v in self.config.vhosts if not v.ssl]
     achalls = [
         achallenges.KeyAuthorizationAnnotatedChallenge(
             challb=acme_util.chall_to_challb(
                 challenges.HTTP01(token=((b'a' * 16))),
                 "pending"),
             domain="something.nonexistent", account_key=self.account_key)]
     self.common_perform_test(achalls, vhosts)
Example #15
0
 def test_configure_multiple_vhosts(self):
     vhosts = [v for v in self.config.vhosts if "duplicate.example.com" in v.get_names()]
     self.assertEqual(len(vhosts), 2)
     achalls = [
         achallenges.KeyAuthorizationAnnotatedChallenge(
             challb=acme_util.chall_to_challb(
                 challenges.HTTP01(token=((b'a' * 16))),
                 "pending"),
             domain="duplicate.example.com", account_key=self.account_key)]
     self.common_perform_test(achalls, vhosts)
Example #16
0
    def test_mod_config_deduplicate(self, mock_add_server_directives):
        """A vhost that appears in both HTTP and HTTPS vhosts only gets modded once"""
        achall = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.HTTP01(token=b"kNdwjxOeX0I_A8DXt9Msmg"), "pending"),
            domain="ssl.both.com", account_key=AUTH_KEY)
        self.http01.add_chall(achall)
        self.http01._mod_config() # pylint: disable=protected-access

        # Should only get called 5 times, rather than 6, because two vhosts are the same
        self.assertEqual(mock_add_server_directives.call_count, 5*2)
Example #17
0
    def setUp(self):
        from certbot.plugins.manual import Authenticator
        self.config = mock.MagicMock(http01_port=8080,
                                     manual_test_mode=False,
                                     manual_public_ip_logging_ok=False,
                                     noninteractive_mode=True)
        self.auth = Authenticator(config=self.config, name="manual")

        self.http01 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.HTTP01_P, domain="foo.com", account_key=KEY)
        self.dns01 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.DNS01_P, domain="foo.com", account_key=KEY)

        self.achalls = [self.http01, self.dns01]

        config_test_mode = mock.MagicMock(http01_port=8080,
                                          manual_test_mode=True,
                                          noninteractive_mode=True)
        self.auth_test_mode = Authenticator(config=config_test_mode,
                                            name="manual")
Example #18
0
 def test_perform_new_webroot_not_in_map(self, mock_get_utility):
     new_webroot = tempfile.mkdtemp()
     self.config.webroot_path = []
     self.config.webroot_map = {"whatever.com": self.path}
     mock_display = mock_get_utility()
     mock_display.menu.side_effect = ((display_util.OK, 0),
                                      (display_util.OK, new_webroot))
     achall = achallenges.KeyAuthorizationAnnotatedChallenge(
         challb=acme_util.HTTP01_P, domain="something.com", account_key=KEY)
     with mock.patch('certbot.display.ops.validated_directory') as m:
         m.return_value = (display_util.OK, new_webroot,)
         self.auth.perform([achall])
     self.assertEqual(self.config.webroot_map[achall.domain], new_webroot)
Example #19
0
 def test_configure_name_and_blank(self):
     domain = "certbot.demo"
     vhosts = [
         v for v in self.config.vhosts if v.name == domain or v.name is None
     ]
     achalls = [
         achallenges.KeyAuthorizationAnnotatedChallenge(
             challb=acme_util.chall_to_challb(
                 challenges.HTTP01(token=((b'a' * 16))), "pending"),
             domain=domain,
             account_key=self.account_key),
     ]
     self.common_perform_test(achalls, vhosts)
Example #20
0
 def test_activate_disabled_vhost(self):
     vhosts = [v for v in self.config.vhosts if v.name == "certbot.demo"]
     achalls = [
         achallenges.KeyAuthorizationAnnotatedChallenge(
             challb=acme_util.chall_to_challb(
                 challenges.HTTP01(token=((b'a' * 16))),
                 "pending"),
             domain="certbot.demo", account_key=self.account_key)]
     vhosts[0].enabled = False
     self.common_perform_test(achalls, vhosts)
     matches = self.config.parser.find_dir(
         "Include", vhosts[0].filep,
         get_aug_path(self.config.parser.loc["default"]))
     self.assertEqual(len(matches), 1)
Example #21
0
    def test_foreign_webconfig_multiple_domains(self):
        # Covers bug https://github.com/certbot/certbot/issues/9091
        achall_2 = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(challenges.HTTP01(token=b"bingo"),
                                             "pending"),
            domain="second-thing.com",
            account_key=KEY)
        self.config.webroot_map["second-thing.com"] = self.path

        challenge_path = os.path.join(self.path, ".well-known",
                                      "acme-challenge")
        filesystem.makedirs(challenge_path)

        webconfig_path = os.path.join(challenge_path, "web.config")
        with open(webconfig_path, "w") as file:
            file.write("something")
        self.auth.perform([self.achall, achall_2])
Example #22
0
    def test_perform_cleanup_multiple_challenges(self):
        bingo_achall = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.HTTP01(token=b"bingo"), "pending"),
            domain="thing.com", account_key=KEY)

        bingo_validation_path = "YmluZ28"
        os.mkdir(self.partial_root_challenge_path)
        self.auth.prepare()
        self.auth.perform([bingo_achall, self.achall])

        self.auth.cleanup([self.achall])
        self.assertFalse(os.path.exists(bingo_validation_path))
        self.assertTrue(os.path.exists(self.root_challenge_path))
        self.auth.cleanup([bingo_achall])
        self.assertFalse(os.path.exists(self.validation_path))
        self.assertFalse(os.path.exists(self.root_challenge_path))
Example #23
0
class WebrootActionTest(unittest.TestCase):
    """Tests for webroot argparse actions."""

    achall = achallenges.KeyAuthorizationAnnotatedChallenge(
        challb=acme_util.HTTP01_P, domain="thing.com", account_key=KEY)

    def setUp(self):
        from certbot.plugins.webroot import Authenticator
        self.path = tempfile.mkdtemp()
        self.parser = argparse.ArgumentParser()
        self.parser.add_argument("-d",
                                 "--domains",
                                 action="append",
                                 default=[])
        Authenticator.inject_parser_options(self.parser, "webroot")

    def test_webroot_map_action(self):
        args = self.parser.parse_args(
            ["--webroot-map",
             json.dumps({'thing.com': self.path})])
        self.assertEqual(args.webroot_map["thing.com"], self.path)

    def test_domain_before_webroot(self):
        args = self.parser.parse_args("-d {0} -w {1}".format(
            self.achall.domain, self.path).split())
        config = self._get_config_after_perform(args)
        self.assertEqual(config.webroot_map[self.achall.domain], self.path)

    def test_domain_before_webroot_error(self):
        self.assertRaises(errors.PluginError, self.parser.parse_args,
                          "-d foo -w bar -w baz".split())
        self.assertRaises(errors.PluginError, self.parser.parse_args,
                          "-d foo -w bar -d baz -w qux".split())

    def test_multiwebroot(self):
        args = self.parser.parse_args("-w {0} -d {1} -w {2} -d bar".format(
            self.path, self.achall.domain, tempfile.mkdtemp()).split())
        self.assertEqual(args.webroot_map[self.achall.domain], self.path)
        config = self._get_config_after_perform(args)
        self.assertEqual(config.webroot_map[self.achall.domain], self.path)

    def _get_config_after_perform(self, config):
        from certbot.plugins.webroot import Authenticator
        auth = Authenticator(config, "webroot")
        auth.perform([self.achall])
        return auth.config
Example #24
0
def _create_achalls(plugin):
    """Returns a list of annotated challenges to test on plugin"""
    achalls = list()
    names = plugin.get_testable_domain_names()
    for domain in names:
        prefs = plugin.get_chall_pref(domain)
        for chall_type in prefs:
            if chall_type == challenges.HTTP01:
                chall = challenges.HTTP01(
                    token=os.urandom(challenges.HTTP01.TOKEN_SIZE))
                challb = acme_util.chall_to_challb(
                    chall, messages.STATUS_PENDING)
                achall = achallenges.KeyAuthorizationAnnotatedChallenge(
                    challb=challb, domain=domain, account_key=util.JWK)
                achalls.append(achall)

    return achalls
Example #25
0
def _create_achalls(plugin: common.Proxy) -> List[achallenges.AnnotatedChallenge]:
    """Returns a list of annotated challenges to test on plugin"""
    achalls: List[achallenges.AnnotatedChallenge] = []
    names = plugin.get_testable_domain_names()
    for domain in names:
        prefs = plugin.get_chall_pref(domain)
        for chall_type in prefs:
            if chall_type == challenges.HTTP01:
                # challenges.HTTP01.TOKEN_SIZE is a float but os.urandom
                # expects an integer.
                chall = challenges.HTTP01(
                    token=os.urandom(int(challenges.HTTP01.TOKEN_SIZE)))
                challb = acme_util.chall_to_challb(
                    chall, messages.STATUS_PENDING)
                achall = achallenges.KeyAuthorizationAnnotatedChallenge(
                    challb=challb, domain=domain, account_key=util.JWK)
                achalls.append(achall)

    return achalls
Example #26
0
def challb_to_achall(challb: messages.ChallengeBody, account_key: josepy.JWK,
                     domain: str) -> achallenges.AnnotatedChallenge:
    """Converts a ChallengeBody object to an AnnotatedChallenge.

    :param .ChallengeBody challb: ChallengeBody
    :param .JWK account_key: Authorized Account Key
    :param str domain: Domain of the challb

    :returns: Appropriate AnnotatedChallenge
    :rtype: :class:`certbot.achallenges.AnnotatedChallenge`

    """
    chall = challb.chall
    logger.info("%s challenge for %s", chall.typ, domain)

    if isinstance(chall, challenges.KeyAuthorizationChallenge):
        return achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=challb, domain=domain, account_key=account_key)
    elif isinstance(chall, challenges.DNS):
        return achallenges.DNS(challb=challb, domain=domain)
    raise errors.Error(f"Received unsupported challenge of type: {chall.typ}")
Example #27
0
    def setUp(self, *args, **kwargs):
        super(ApacheHttp01Test, self).setUp(*args, **kwargs)

        self.account_key = self.rsa512jwk
        self.achalls = []
        for i in range(NUM_ACHALLS):
            self.achalls.append(
                achallenges.KeyAuthorizationAnnotatedChallenge(
                    challb=acme_util.chall_to_challb(
                        challenges.HTTP01(token=((chr(ord('a') + i) * 16))),
                        "pending"),
                    domain="example{0}.com".format(i),
                    account_key=self.account_key))

        modules = ["alias", "authz_core", "authz_host"]
        for mod in modules:
            self.config.parser.modules.add("mod_{0}.c".format(mod))
            self.config.parser.modules.add(mod + "_module")

        from certbot_apache.http_01 import ApacheHttp01
        self.http = ApacheHttp01(self.config)
Example #28
0
except ImportError:  # pragma: no cover
    from unittest import mock

from acme import challenges
from certbot import achallenges
from certbot import crypto_util
from certbot import errors
from certbot.compat import filesystem
from certbot.compat import os
from certbot.tests import acme_util
from certbot.tests import util as test_util

AUTH_KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem"))
ACHALL = achallenges.KeyAuthorizationAnnotatedChallenge(
    challb=acme_util.chall_to_challb(challenges.HTTP01(token=b'token1'),
                                     "pending"),
    domain="encryption-example.demo",
    account_key=AUTH_KEY)


class NamespaceFunctionsTest(unittest.TestCase):
    """Tests for certbot.plugins.common.*_namespace functions."""
    def test_option_namespace(self):
        from certbot.plugins.common import option_namespace
        self.assertEqual("foo-", option_namespace("foo"))

    def test_dest_namespace(self):
        from certbot.plugins.common import dest_namespace
        self.assertEqual("foo_", dest_namespace("foo"))

    def test_dest_namespace_with_dashes(self):
Example #29
0
class HttpPerformTest(util.NginxTest):
    """Test the NginxHttp01 challenge."""

    account_key = AUTH_KEY
    achalls = [
        achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.HTTP01(token=b"kNdwjwOeX0I_A8DXt9Msmg"), "pending"),
            domain="www.example.com", account_key=account_key),
        achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.HTTP01(
                    token=b"\xba\xa9\xda?<m\xaewmx\xea\xad\xadv\xf4\x02\xc9y"
                          b"\x80\xe2_X\t\xe7\xc7\xa4\t\xca\xf7&\x945"
                ), "pending"),
            domain="ipv6.com", account_key=account_key),
        achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.HTTP01(
                    token=b"\x8c\x8a\xbf_-f\\cw\xee\xd6\xf8/\xa5\xe3\xfd"
                          b"\xeb9\xf1\xf5\xb9\xefVM\xc9w\xa4u\x9c\xe1\x87\xb4"
                ), "pending"),
            domain="www.example.org", account_key=account_key),
        achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.HTTP01(token=b"kNdwjxOeX0I_A8DXt9Msmg"), "pending"),
            domain="migration.com", account_key=account_key),
        achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.HTTP01(token=b"kNdwjxOeX0I_A8DXt9Msmg"), "pending"),
            domain="ipv6ssl.com", account_key=account_key),
    ]

    def setUp(self):
        super().setUp()

        config = self.get_nginx_configurator(
            self.config_path, self.config_dir, self.work_dir, self.logs_dir)

        from certbot_nginx._internal import http_01
        self.http01 = http_01.NginxHttp01(config)

    def test_perform0(self):
        responses = self.http01.perform()
        self.assertEqual([], responses)

    @mock.patch("certbot_nginx._internal.configurator.NginxConfigurator.save")
    def test_perform1(self, mock_save):
        self.http01.add_chall(self.achalls[0])
        response = self.achalls[0].response(self.account_key)

        responses = self.http01.perform()

        self.assertEqual([response], responses)
        self.assertEqual(mock_save.call_count, 1)

    def test_perform2(self):
        acme_responses = []
        for achall in self.achalls:
            self.http01.add_chall(achall)
            acme_responses.append(achall.response(self.account_key))

        http_responses = self.http01.perform()

        self.assertEqual(len(http_responses), 5)
        for i in range(5):
            self.assertEqual(http_responses[i], acme_responses[i])

    def test_mod_config(self):
        self.http01.add_chall(self.achalls[0])
        self.http01.add_chall(self.achalls[2])

        self.http01._mod_config()  # pylint: disable=protected-access

        self.http01.configurator.save()

        self.http01.configurator.parser.load()

        # vhosts = self.http01.configurator.parser.get_vhosts()

        # for vhost in vhosts:
        #     pass
            # if the name matches
            # check that the location block is in there and is correct

            # if vhost.addrs == set(v_addr1):
            #     response = self.achalls[0].response(self.account_key)
            # else:
            #     response = self.achalls[2].response(self.account_key)
            #     self.assertEqual(vhost.addrs, set(v_addr2_print))
            # self.assertEqual(vhost.names, set([response.z_domain.decode('ascii')]))

    @mock.patch('certbot_nginx._internal.parser.NginxParser.add_server_directives')
    def test_mod_config_http_and_https(self, mock_add_server_directives):
        """A server_name with both HTTP and HTTPS vhosts should get modded in both vhosts"""
        self.configuration.https_port = 443
        self.http01.add_chall(self.achalls[3]) # migration.com
        self.http01._mod_config()  # pylint: disable=protected-access

        # Domain has an HTTP and HTTPS vhost
        # 2 * 'rewrite' + 2 * 'return 200 keyauthz' = 4
        self.assertEqual(mock_add_server_directives.call_count, 4)

    @mock.patch('certbot_nginx._internal.parser.nginxparser.dump')
    @mock.patch('certbot_nginx._internal.parser.NginxParser.add_server_directives')
    def test_mod_config_only_https(self, mock_add_server_directives, mock_dump):
        """A server_name with only an HTTPS vhost should get modded"""
        self.http01.add_chall(self.achalls[4]) # ipv6ssl.com
        self.http01._mod_config() # pylint: disable=protected-access

        # It should modify the existing HTTPS vhost
        self.assertEqual(mock_add_server_directives.call_count, 2)
        # since there was no suitable HTTP vhost or default HTTP vhost, a non-empty one
        # should have been created and written to the challenge conf file
        self.assertNotEqual(mock_dump.call_args[0][0], [])

    @mock.patch('certbot_nginx._internal.parser.NginxParser.add_server_directives')
    def test_mod_config_deduplicate(self, mock_add_server_directives):
        """A vhost that appears in both HTTP and HTTPS vhosts only gets modded once"""
        achall = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(
                challenges.HTTP01(token=b"kNdwjxOeX0I_A8DXt9Msmg"), "pending"),
            domain="ssl.both.com", account_key=AUTH_KEY)
        self.http01.add_chall(achall)
        self.http01._mod_config() # pylint: disable=protected-access

        # Should only get called 5 times, rather than 6, because two vhosts are the same
        self.assertEqual(mock_add_server_directives.call_count, 5*2)

    @mock.patch("certbot_nginx._internal.configurator.NginxConfigurator.ipv6_info")
    def test_default_listen_addresses_no_memoization(self, ipv6_info):
        # pylint: disable=protected-access
        ipv6_info.return_value = (True, True)
        self.http01._default_listen_addresses()
        self.assertEqual(ipv6_info.call_count, 1)
        ipv6_info.return_value = (False, False)
        self.http01._default_listen_addresses()
        self.assertEqual(ipv6_info.call_count, 2)

    @mock.patch("certbot_nginx._internal.configurator.NginxConfigurator.ipv6_info")
    def test_default_listen_addresses_t_t(self, ipv6_info):
        # pylint: disable=protected-access
        ipv6_info.return_value = (True, True)
        addrs = self.http01._default_listen_addresses()
        http_addr = Addr.fromstring("80")
        http_ipv6_addr = Addr.fromstring("[::]:80")
        self.assertEqual(addrs, [http_addr, http_ipv6_addr])

    @mock.patch("certbot_nginx._internal.configurator.NginxConfigurator.ipv6_info")
    def test_default_listen_addresses_t_f(self, ipv6_info):
        # pylint: disable=protected-access
        ipv6_info.return_value = (True, False)
        addrs = self.http01._default_listen_addresses()
        http_addr = Addr.fromstring("80")
        http_ipv6_addr = Addr.fromstring("[::]:80 ipv6only=on")
        self.assertEqual(addrs, [http_addr, http_ipv6_addr])

    @mock.patch("certbot_nginx._internal.configurator.NginxConfigurator.ipv6_info")
    def test_default_listen_addresses_f_f(self, ipv6_info):
        # pylint: disable=protected-access
        ipv6_info.return_value = (False, False)
        addrs = self.http01._default_listen_addresses()
        http_addr = Addr.fromstring("80")
        self.assertEqual(addrs, [http_addr])
Example #30
0
class AuthenticatorTest(unittest.TestCase):
    """Tests for certbot.plugins.webroot.Authenticator."""

    achall = achallenges.KeyAuthorizationAnnotatedChallenge(
        challb=acme_util.HTTP01_P, domain="thing.com", account_key=KEY)

    def setUp(self):
        from certbot.plugins.webroot import Authenticator
        # On Linux directories created by tempfile.mkdtemp inherit their permissions from their
        # parent directory. So the actual permissions are inconsistent over various tests env.
        # To circumvent this, a dedicated sub-workspace is created under the workspace, using
        # filesystem.mkdir to get consistent permissions.
        self.workspace = tempfile.mkdtemp()
        self.path = os.path.join(self.workspace, 'webroot')
        filesystem.mkdir(self.path)
        self.partial_root_challenge_path = os.path.join(
            self.path, ".well-known")
        self.root_challenge_path = os.path.join(self.path, ".well-known",
                                                "acme-challenge")
        self.validation_path = os.path.join(
            self.root_challenge_path,
            "ZXZhR3hmQURzNnBTUmIyTEF2OUlaZjE3RHQzanV4R0orUEN0OTJ3citvQQ")
        self.config = mock.MagicMock(webroot_path=self.path,
                                     webroot_map={"thing.com": self.path})
        self.auth = Authenticator(self.config, "webroot")

    def tearDown(self):
        shutil.rmtree(self.path)

    def test_more_info(self):
        more_info = self.auth.more_info()
        self.assertTrue(isinstance(more_info, six.string_types))
        self.assertTrue(self.path in more_info)

    def test_add_parser_arguments(self):
        add = mock.MagicMock()
        self.auth.add_parser_arguments(add)
        self.assertEqual(2, add.call_count)

    def test_prepare(self):
        self.auth.prepare()  # shouldn't raise any exceptions

    @test_util.patch_get_utility()
    def test_webroot_from_list(self, mock_get_utility):
        self.config.webroot_path = []
        self.config.webroot_map = {"otherthing.com": self.path}
        mock_display = mock_get_utility()
        mock_display.menu.return_value = (
            display_util.OK,
            1,
        )

        self.auth.perform([self.achall])
        self.assertTrue(mock_display.menu.called)
        for call in mock_display.menu.call_args_list:
            self.assertTrue(self.achall.domain in call[0][0])
            self.assertTrue(
                all(webroot in call[0][1]
                    for webroot in six.itervalues(self.config.webroot_map)))
        self.assertEqual(self.config.webroot_map[self.achall.domain],
                         self.path)

    @test_util.patch_get_utility()
    def test_webroot_from_list_help_and_cancel(self, mock_get_utility):
        self.config.webroot_path = []
        self.config.webroot_map = {"otherthing.com": self.path}

        mock_display = mock_get_utility()
        mock_display.menu.side_effect = ((display_util.CANCEL, -1), )
        self.assertRaises(errors.PluginError, self.auth.perform, [self.achall])
        self.assertTrue(mock_display.menu.called)
        for call in mock_display.menu.call_args_list:
            self.assertTrue(self.achall.domain in call[0][0])
            self.assertTrue(
                all(webroot in call[0][1]
                    for webroot in six.itervalues(self.config.webroot_map)))

    @test_util.patch_get_utility()
    def test_new_webroot(self, mock_get_utility):
        self.config.webroot_path = []
        self.config.webroot_map = {"something.com": self.path}

        mock_display = mock_get_utility()
        mock_display.menu.return_value = (
            display_util.OK,
            0,
        )
        with mock.patch('certbot.display.ops.validated_directory') as m:
            m.side_effect = ((display_util.CANCEL, -1), (
                display_util.OK,
                self.path,
            ))

            self.auth.perform([self.achall])

        self.assertEqual(self.config.webroot_map[self.achall.domain],
                         self.path)

    @test_util.patch_get_utility()
    def test_new_webroot_empty_map_cancel(self, mock_get_utility):
        self.config.webroot_path = []
        self.config.webroot_map = {}

        mock_display = mock_get_utility()
        mock_display.menu.return_value = (
            display_util.OK,
            0,
        )
        with mock.patch('certbot.display.ops.validated_directory') as m:
            m.return_value = (display_util.CANCEL, -1)
            self.assertRaises(errors.PluginError, self.auth.perform,
                              [self.achall])

    def test_perform_missing_root(self):
        self.config.webroot_path = None
        self.config.webroot_map = {}
        self.assertRaises(errors.PluginError, self.auth.perform, [])

    def test_perform_reraises_other_errors(self):
        self.auth.full_path = os.path.join(self.path, "null")
        permission_canary = os.path.join(self.path, "rnd")
        with open(permission_canary, "w") as f:
            f.write("thingimy")
        filesystem.chmod(self.path, 0o000)
        try:
            open(permission_canary, "r")
            print("Warning, running tests as root skips permissions tests...")
        except IOError:
            # ok, permissions work, test away...
            self.assertRaises(errors.PluginError, self.auth.perform, [])
        filesystem.chmod(self.path, 0o700)

    @mock.patch(
        "certbot.plugins.webroot.filesystem.copy_ownership_and_apply_mode")
    def test_failed_chown(self, mock_ownership):
        mock_ownership.side_effect = OSError(errno.EACCES, "msg")
        self.auth.perform([self.achall])  # exception caught and logged

    @test_util.patch_get_utility()
    def test_perform_new_webroot_not_in_map(self, mock_get_utility):
        new_webroot = tempfile.mkdtemp()
        self.config.webroot_path = []
        self.config.webroot_map = {"whatever.com": self.path}
        mock_display = mock_get_utility()
        mock_display.menu.side_effect = ((display_util.OK, 0),
                                         (display_util.OK, new_webroot))
        achall = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.HTTP01_P, domain="something.com", account_key=KEY)
        with mock.patch('certbot.display.ops.validated_directory') as m:
            m.return_value = (
                display_util.OK,
                new_webroot,
            )
            self.auth.perform([achall])
        self.assertEqual(self.config.webroot_map[achall.domain], new_webroot)

    def test_perform_permissions(self):
        self.auth.prepare()

        # Remove exec bit from permission check, so that it
        # matches the file
        self.auth.perform([self.achall])
        self.assertTrue(filesystem.check_mode(self.validation_path, 0o644))

        # Check permissions of the directories
        for dirpath, dirnames, _ in os.walk(self.path):
            for directory in dirnames:
                full_path = os.path.join(dirpath, directory)
                self.assertTrue(filesystem.check_mode(full_path, 0o755))

        self.assertTrue(
            filesystem.has_same_ownership(self.validation_path, self.path))

    def test_perform_cleanup(self):
        self.auth.prepare()
        responses = self.auth.perform([self.achall])
        self.assertEqual(1, len(responses))
        self.assertTrue(os.path.exists(self.validation_path))
        with open(self.validation_path) as validation_f:
            validation = validation_f.read()
        self.assertTrue(
            challenges.KeyAuthorizationChallengeResponse(
                key_authorization=validation).verify(self.achall.chall,
                                                     KEY.public_key()))

        self.auth.cleanup([self.achall])
        self.assertFalse(os.path.exists(self.validation_path))
        self.assertFalse(os.path.exists(self.root_challenge_path))
        self.assertFalse(os.path.exists(self.partial_root_challenge_path))

    def test_perform_cleanup_existing_dirs(self):
        filesystem.mkdir(self.partial_root_challenge_path)
        self.auth.prepare()
        self.auth.perform([self.achall])
        self.auth.cleanup([self.achall])

        # Ensure we don't "clean up" directories that previously existed
        self.assertFalse(os.path.exists(self.validation_path))
        self.assertFalse(os.path.exists(self.root_challenge_path))

    def test_perform_cleanup_multiple_challenges(self):
        bingo_achall = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.chall_to_challb(challenges.HTTP01(token=b"bingo"),
                                             "pending"),
            domain="thing.com",
            account_key=KEY)

        bingo_validation_path = "YmluZ28"
        filesystem.mkdir(self.partial_root_challenge_path)
        self.auth.prepare()
        self.auth.perform([bingo_achall, self.achall])

        self.auth.cleanup([self.achall])
        self.assertFalse(os.path.exists(bingo_validation_path))
        self.assertTrue(os.path.exists(self.root_challenge_path))
        self.auth.cleanup([bingo_achall])
        self.assertFalse(os.path.exists(self.validation_path))
        self.assertFalse(os.path.exists(self.root_challenge_path))

    def test_cleanup_leftovers(self):
        self.auth.prepare()
        self.auth.perform([self.achall])

        leftover_path = os.path.join(self.root_challenge_path, 'leftover')
        filesystem.mkdir(leftover_path)

        self.auth.cleanup([self.achall])
        self.assertFalse(os.path.exists(self.validation_path))
        self.assertTrue(os.path.exists(self.root_challenge_path))

        os.rmdir(leftover_path)

    @mock.patch('certbot.compat.os.rmdir')
    def test_cleanup_failure(self, mock_rmdir):
        self.auth.prepare()
        self.auth.perform([self.achall])

        os_error = OSError()
        os_error.errno = errno.EACCES
        mock_rmdir.side_effect = os_error

        self.auth.cleanup([self.achall])
        self.assertFalse(os.path.exists(self.validation_path))
        self.assertTrue(os.path.exists(self.root_challenge_path))