def setUp(self):
        kwargs = {
            "chall": acme_util.HTTP01,
            "uri": "uri",
            "status": messages.STATUS_INVALID,
            "error": messages.Error(typ="tls", detail="detail"),
        }

        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")
    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)
        ])
Esempio n. 3
0
    def setUp(self):
        kwargs = {
            "chall": acme_util.HTTP01,
            "uri": "uri",
            "status": messages.STATUS_INVALID,
            "error": messages.Error(typ="urn:acme:error: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")
Esempio n. 4
0
    def test_perform(self, mock_restart, mock_dvsni_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)

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

        mock_dvsni_perform.return_value = dvsni_ret_val
        responses = self.config.perform([achall1, achall2])

        self.assertEqual(mock_dvsni_perform.call_count, 1)
        self.assertEqual(responses, dvsni_ret_val)
        self.assertEqual(mock_restart.call_count, 1)
Esempio n. 5
0
class TLSSNI01Test(unittest.TestCase):
    """Tests for letsencrypt.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="letsencrypt.demo",
            account_key=auth_key),
    ]

    def setUp(self):
        from letsencrypt.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("letsencrypt.plugins.common.open",
                        mock_open,
                        create=True):
            with mock.patch("letsencrypt.plugins.common.le_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))
Esempio n. 6
0
def challb_to_achall(challb, account_key, domain):
    """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:`letsencrypt.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)
    elif isinstance(chall, challenges.RecoveryContact):
        return achallenges.RecoveryContact(challb=challb, domain=domain)
    elif isinstance(chall, challenges.ProofOfPossession):
        return achallenges.ProofOfPossession(challb=challb, domain=domain)
    else:
        raise errors.Error("Received unsupported challenge of type: %s",
                           chall.typ)
Esempio n. 7
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"),
     )
Esempio n. 8
0
class AuthenticatorTest(unittest.TestCase):
    """Tests for letsencrypt.plugins.webroot.Authenticator."""

    achall = achallenges.KeyAuthorizationAnnotatedChallenge(
        challb=acme_util.HTTP01_P, domain=None, account_key=KEY)

    def setUp(self):
        from letsencrypt.plugins.webroot import Authenticator
        self.path = tempfile.mkdtemp()
        self.validation_path = os.path.join(
            self.path, ".well-known", "acme-challenge",
            "ZXZhR3hmQURzNnBTUmIyTEF2OUlaZjE3RHQzanV4R0orUEN0OTJ3citvQQ")
        self.config = mock.MagicMock(webroot_path=self.path)
        self.auth = Authenticator(self.config, "webroot")
        self.auth.prepare()

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

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

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

    def test_prepare_bad_root(self):
        self.config.webroot_path = os.path.join(self.path, "null")
        self.assertRaises(errors.PluginError, self.auth.prepare)

    def test_prepare_missing_root(self):
        self.config.webroot_path = None
        self.assertRaises(errors.PluginError, self.auth.prepare)

    def test_prepare_full_root_exists(self):
        # prepare() has already been called once in setUp()
        self.auth.prepare()  # shouldn't raise any exceptions

    def test_prepare_reraises_other_errors(self):
        self.auth.full_path = os.path.join(self.path, "null")
        os.chmod(self.path, 0o000)
        self.assertRaises(errors.PluginError, self.auth.prepare)
        os.chmod(self.path, 0o700)

    def test_perform_cleanup(self):
        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))
Esempio n. 9
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="letsencrypt.demo", account_key=account_key)

        return account_key, achall1, achall2
Esempio n. 10
0
    def test_perform_missing_path(self):
        self.auth.prepare()

        missing_achall = achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.HTTP01_P, domain="thing2.com", account_key=KEY)
        self.assertRaises(errors.PluginError, self.auth.perform,
                          [missing_achall])

        self.auth.full_roots[self.achall.domain] = 'null'
        self.assertRaises(errors.PluginError, self.auth.perform, [self.achall])
Esempio n. 11
0
    def setUp(self):
        from letsencrypt.plugins.manual import Authenticator
        self.config = mock.MagicMock(
            http01_port=8080, manual_test_mode=False, manual_public_ip_logging_ok=False)
        self.auth = Authenticator(config=self.config, name="manual")
        self.achalls = [achallenges.KeyAuthorizationAnnotatedChallenge(
            challb=acme_util.HTTP01_P, domain="foo.com", account_key=KEY)]

        config_test_mode = mock.MagicMock(
            http01_port=8080, manual_test_mode=True)
        self.auth_test_mode = Authenticator(
            config=config_test_mode, name="manual")
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.TLSSNI01:
                chall = challenges.TLSSNI01(
                    token=os.urandom(challenges.TLSSNI01.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
Esempio n. 13
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 letsencrypt.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", '{{"thing.com":"{0}"}}'.format(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 letsencrypt.plugins.webroot import Authenticator
        auth = Authenticator(config, "webroot")
        auth.perform([self.achall])
        return auth.config
Esempio n. 14
0
class AuthenticatorTest(unittest.TestCase):
    """Tests for letsencrypt.plugins.webroot.Authenticator."""

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

    def setUp(self):
        from letsencrypt.plugins.webroot import Authenticator
        self.path = tempfile.mkdtemp()
        self.validation_path = os.path.join(
            self.path, ".well-known", "acme-challenge",
            "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, str))
        self.assertTrue(self.path in more_info)

    def test_add_parser_arguments(self):
        add = mock.MagicMock()
        self.auth.add_parser_arguments(add)
        self.assertEqual(0, add.call_count)  # args moved to cli.py!

    def test_prepare_bad_root(self):
        self.config.webroot_path = os.path.join(self.path, "null")
        self.config.webroot_map["thing.com"] = self.config.webroot_path
        self.assertRaises(errors.PluginError, self.auth.prepare)

    def test_prepare_missing_root(self):
        self.config.webroot_path = None
        self.config.webroot_map = {}
        self.assertRaises(errors.PluginError, self.auth.prepare)

    def test_prepare_full_root_exists(self):
        # prepare() has already been called once in setUp()
        self.auth.prepare()  # shouldn't raise any exceptions

    def test_prepare_reraises_other_errors(self):
        self.auth.full_path = os.path.join(self.path, "null")
        os.chmod(self.path, 0o000)
        self.assertRaises(errors.PluginError, self.auth.prepare)
        os.chmod(self.path, 0o700)

    @mock.patch("letsencrypt.plugins.webroot.os.chown")
    def test_failed_chown_eacces(self, mock_chown):
        mock_chown.side_effect = OSError(errno.EACCES, "msg")
        self.auth.prepare()  # exception caught and logged

    @mock.patch("letsencrypt.plugins.webroot.os.chown")
    def test_failed_chown_not_eacces(self, mock_chown):
        mock_chown.side_effect = OSError()
        self.assertRaises(errors.PluginError, self.auth.prepare)

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

        # Remove exec bit from permission check, so that it
        # matches the file
        self.auth.perform([self.achall])
        path_permissions = stat.S_IMODE(os.stat(self.validation_path).st_mode)
        self.assertEqual(path_permissions, 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)
                dir_permissions = stat.S_IMODE(os.stat(full_path).st_mode)
                self.assertEqual(dir_permissions, 0o755)

        parent_gid = os.stat(self.path).st_gid
        parent_uid = os.stat(self.path).st_uid

        self.assertEqual(os.stat(self.validation_path).st_gid, parent_gid)
        self.assertEqual(os.stat(self.validation_path).st_uid, parent_uid)

    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))
class TlsSniPerformTest(util.NginxTest):
    """Test the NginxTlsSni01 challenge."""

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

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

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

        from letsencrypt_nginx import tls_sni_01
        self.sni = tls_sni_01.NginxTlsSni01(config)

    def tearDown(self):
        shutil.rmtree(self.temp_dir)
        shutil.rmtree(self.config_dir)
        shutil.rmtree(self.work_dir)

    @mock.patch("letsencrypt_nginx.configurator"
                ".NginxConfigurator.choose_vhost")
    def test_perform(self, mock_choose):
        self.sni.add_chall(self.achalls[1])
        mock_choose.return_value = None
        result = self.sni.perform()
        self.assertTrue(result is None)

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

    @mock.patch("letsencrypt_nginx.configurator.NginxConfigurator.save")
    def test_perform1(self, mock_save):
        self.sni.add_chall(self.achalls[0])
        response = self.achalls[0].response(self.account_key)
        mock_setup_cert = mock.MagicMock(return_value=response)

        # pylint: disable=protected-access
        self.sni._setup_challenge_cert = mock_setup_cert

        responses = self.sni.perform()

        mock_setup_cert.assert_called_once_with(self.achalls[0])
        self.assertEqual([response], responses)
        self.assertEqual(mock_save.call_count, 2)

        # Make sure challenge config is included in main config
        http = self.sni.configurator.parser.parsed[
            self.sni.configurator.parser.loc["root"]][-1]
        self.assertTrue(
            util.contains_at_depth(http, ['include', self.sni.challenge_conf], 1))

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

        mock_setup_cert = mock.MagicMock(side_effect=acme_responses)
        # pylint: disable=protected-access
        self.sni._setup_challenge_cert = mock_setup_cert

        sni_responses = self.sni.perform()

        self.assertEqual(mock_setup_cert.call_count, 3)

        for index, achall in enumerate(self.achalls):
            self.assertEqual(
                mock_setup_cert.call_args_list[index], mock.call(achall))

        http = self.sni.configurator.parser.parsed[
            self.sni.configurator.parser.loc["root"]][-1]
        self.assertTrue(['include', self.sni.challenge_conf] in http[1])
        self.assertTrue(
            util.contains_at_depth(http, ['server_name', 'blah'], 3))

        self.assertEqual(len(sni_responses), 3)
        for i in xrange(3):
            self.assertEqual(sni_responses[i], acme_responses[i])

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

        v_addr1 = [obj.Addr("69.50.225.155", "9000", True, False),
                   obj.Addr("127.0.0.1", "", False, False)]
        v_addr2 = [obj.Addr("myhost", "", False, True)]
        ll_addr = [v_addr1, v_addr2]
        self.sni._mod_config(ll_addr)  # pylint: disable=protected-access

        self.sni.configurator.save()

        self.sni.configurator.parser.load()

        http = self.sni.configurator.parser.parsed[
            self.sni.configurator.parser.loc["root"]][-1]
        self.assertTrue(['include', self.sni.challenge_conf] in http[1])

        vhosts = self.sni.configurator.parser.get_vhosts()
        vhs = [vh for vh in vhosts if vh.filep == self.sni.challenge_conf]

        for vhost in vhs:
            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))
            self.assertEqual(vhost.names, set([response.z_domain]))

        self.assertEqual(len(vhs), 2)

    def test_mod_config_fail(self):
        root = self.sni.configurator.parser.loc["root"]
        self.sni.configurator.parser.parsed[root] = [['include', 'foo.conf']]
        # pylint: disable=protected-access
        self.assertRaises(
            errors.MisconfigurationError, self.sni._mod_config, [])
Esempio n. 16
0
 def test_unexpected(self):
     unexpected = achallenges.KeyAuthorizationAnnotatedChallenge(
         challb=None, domain="0", account_key="dummy_key")
     self.assertRaises(errors.ContAuthError, self.auth.cleanup,
                       [unexpected])
Esempio n. 17
0
 def test_unexpected(self):
     self.assertRaises(errors.ContAuthError, self.auth.perform, [
         achallenges.KeyAuthorizationAnnotatedChallenge(
             challb=None, domain="0", account_key="invalid_key")
     ])
Esempio n. 18
0
class AuthenticatorTest(unittest.TestCase):
    """Tests for letsencrypt.plugins.webroot.Authenticator."""

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

    def setUp(self):
        from letsencrypt.plugins.webroot import Authenticator
        self.path = tempfile.mkdtemp()
        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, str))
        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

    @mock.patch("letsencrypt.plugins.webroot.zope.component.getUtility")
    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)

    @mock.patch("letsencrypt.plugins.webroot.zope.component.getUtility")
    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.HELP, -1),
            (display_util.CANCEL, -1),
        )
        self.assertRaises(errors.PluginError, self.auth.perform, [self.achall])
        self.assertTrue(mock_display.notification.called)
        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)))

    @mock.patch("letsencrypt.plugins.webroot.zope.component.getUtility")
    def test_new_webroot(self, mock_get_utility):
        self.config.webroot_path = []
        self.config.webroot_map = {}

        imaginary_dir = os.path.join(os.sep, "imaginary", "dir")

        mock_display = mock_get_utility()
        mock_display.menu.return_value = (
            display_util.OK,
            0,
        )
        mock_display.directory_select.side_effect = (
            (
                display_util.HELP,
                -1,
            ),
            (
                display_util.CANCEL,
                -1,
            ),
            (
                display_util.OK,
                imaginary_dir,
            ),
            (
                display_util.OK,
                self.path,
            ),
        )
        self.auth.perform([self.achall])

        self.assertTrue(mock_display.notification.called)
        for call in mock_display.notification.call_args_list:
            self.assertTrue(imaginary_dir in call[0][0]
                            or display_util.DSELECT_HELP == call[0][0])

        self.assertTrue(mock_display.directory_select.called)
        for call in mock_display.directory_select.call_args_list:
            self.assertTrue(self.achall.domain in call[0][0])

    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")
        os.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, [])
        os.chmod(self.path, 0o700)

    @mock.patch("letsencrypt.plugins.webroot.os.chown")
    def test_failed_chown_eacces(self, mock_chown):
        mock_chown.side_effect = OSError(errno.EACCES, "msg")
        self.auth.perform([self.achall])  # exception caught and logged

    @mock.patch("letsencrypt.plugins.webroot.os.chown")
    def test_failed_chown_not_eacces(self, mock_chown):
        mock_chown.side_effect = OSError()
        self.assertRaises(errors.PluginError, self.auth.perform, [])

    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])
        path_permissions = stat.S_IMODE(os.stat(self.validation_path).st_mode)
        self.assertEqual(path_permissions, 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)
                dir_permissions = stat.S_IMODE(os.stat(full_path).st_mode)
                self.assertEqual(dir_permissions, 0o755)

        parent_gid = os.stat(self.path).st_gid
        parent_uid = os.stat(self.path).st_uid

        self.assertEqual(os.stat(self.validation_path).st_gid, parent_gid)
        self.assertEqual(os.stat(self.validation_path).st_uid, parent_uid)

    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))

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

        leftover_path = os.path.join(self.root_challenge_path, 'leftover')
        os.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('os.rmdir')
    def test_cleanup_permission_denied(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))

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

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

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