We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
apache authenticator should authenticate all duplicate vhosts
See https://community.letsencrypt.org/t/cant-renew-certificate/153274/3?u=_az. I've seen this a few other times as well.

The Apache authenticator needs to authenticate all of the virtual hosts which could match the requested domain, including duplicates and HTTPS ones.

#6729 fixed this for the most part, but there are seemingly still some edge cases left over.

Let's investigate and fix those.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `certbot-apache/certbot_apache/_internal/http_01.py`
Content:
```
1 """A class that performs HTTP-01 challenges for Apache"""
2 import errno
3 import logging
4 from typing import List
5 from typing import Set
6 
7 from certbot import errors
8 from certbot.compat import filesystem
9 from certbot.compat import os
10 from certbot.plugins import common
11 from certbot_apache._internal.obj import VirtualHost  # pylint: disable=unused-import
12 from certbot_apache._internal.parser import get_aug_path
13 
14 logger = logging.getLogger(__name__)
15 
16 
17 class ApacheHttp01(common.ChallengePerformer):
18     """Class that performs HTTP-01 challenges within the Apache configurator."""
19 
20     CONFIG_TEMPLATE22_PRE = """\
21         RewriteEngine on
22         RewriteRule ^/\\.well-known/acme-challenge/([A-Za-z0-9-_=]+)$ {0}/$1 [L]
23 
24     """
25     CONFIG_TEMPLATE22_POST = """\
26         <Directory {0}>
27             Order Allow,Deny
28             Allow from all
29         </Directory>
30         <Location /.well-known/acme-challenge>
31             Order Allow,Deny
32             Allow from all
33         </Location>
34     """
35 
36     CONFIG_TEMPLATE24_PRE = """\
37         RewriteEngine on
38         RewriteRule ^/\\.well-known/acme-challenge/([A-Za-z0-9-_=]+)$ {0}/$1 [END]
39     """
40     CONFIG_TEMPLATE24_POST = """\
41         <Directory {0}>
42             Require all granted
43         </Directory>
44         <Location /.well-known/acme-challenge>
45             Require all granted
46         </Location>
47     """
48 
49     def __init__(self, *args, **kwargs):
50         super().__init__(*args, **kwargs)
51         self.challenge_conf_pre = os.path.join(
52             self.configurator.conf("challenge-location"),
53             "le_http_01_challenge_pre.conf")
54         self.challenge_conf_post = os.path.join(
55             self.configurator.conf("challenge-location"),
56             "le_http_01_challenge_post.conf")
57         self.challenge_dir = os.path.join(
58             self.configurator.config.work_dir,
59             "http_challenges")
60         self.moded_vhosts: Set[VirtualHost] = set()
61 
62     def perform(self):
63         """Perform all HTTP-01 challenges."""
64         if not self.achalls:
65             return []
66         # Save any changes to the configuration as a precaution
67         # About to make temporary changes to the config
68         self.configurator.save("Changes before challenge setup", True)
69 
70         self.configurator.ensure_listen(str(
71             self.configurator.config.http01_port))
72         self.prepare_http01_modules()
73 
74         responses = self._set_up_challenges()
75 
76         self._mod_config()
77         # Save reversible changes
78         self.configurator.save("HTTP Challenge", True)
79 
80         return responses
81 
82     def prepare_http01_modules(self):
83         """Make sure that we have the needed modules available for http01"""
84 
85         if self.configurator.conf("handle-modules"):
86             needed_modules = ["rewrite"]
87             if self.configurator.version < (2, 4):
88                 needed_modules.append("authz_host")
89             else:
90                 needed_modules.append("authz_core")
91             for mod in needed_modules:
92                 if mod + "_module" not in self.configurator.parser.modules:
93                     self.configurator.enable_mod(mod, temp=True)
94 
95     def _mod_config(self):
96         selected_vhosts: List[VirtualHost] = []
97         http_port = str(self.configurator.config.http01_port)
98         for chall in self.achalls:
99             # Search for matching VirtualHosts
100             for vh in self._matching_vhosts(chall.domain):
101                 selected_vhosts.append(vh)
102 
103         # Ensure that we have one or more VirtualHosts that we can continue
104         # with. (one that listens to port configured with --http-01-port)
105         found = False
106         for vhost in selected_vhosts:
107             if any(a.is_wildcard() or a.get_port() == http_port for a in vhost.addrs):
108                 found = True
109 
110         if not found:
111             for vh in self._relevant_vhosts():
112                 selected_vhosts.append(vh)
113 
114         # Add the challenge configuration
115         for vh in selected_vhosts:
116             self._set_up_include_directives(vh)
117 
118         self.configurator.reverter.register_file_creation(
119             True, self.challenge_conf_pre)
120         self.configurator.reverter.register_file_creation(
121             True, self.challenge_conf_post)
122 
123         if self.configurator.version < (2, 4):
124             config_template_pre = self.CONFIG_TEMPLATE22_PRE
125             config_template_post = self.CONFIG_TEMPLATE22_POST
126         else:
127             config_template_pre = self.CONFIG_TEMPLATE24_PRE
128             config_template_post = self.CONFIG_TEMPLATE24_POST
129 
130         config_text_pre = config_template_pre.format(self.challenge_dir)
131         config_text_post = config_template_post.format(self.challenge_dir)
132 
133         logger.debug("writing a pre config file with text:\n %s", config_text_pre)
134         with open(self.challenge_conf_pre, "w") as new_conf:
135             new_conf.write(config_text_pre)
136         logger.debug("writing a post config file with text:\n %s", config_text_post)
137         with open(self.challenge_conf_post, "w") as new_conf:
138             new_conf.write(config_text_post)
139 
140     def _matching_vhosts(self, domain):
141         """Return all VirtualHost objects that have the requested domain name or
142         a wildcard name that would match the domain in ServerName or ServerAlias
143         directive.
144         """
145         matching_vhosts = []
146         for vhost in self.configurator.vhosts:
147             if self.configurator.domain_in_names(vhost.get_names(), domain):
148                 # domain_in_names also matches the exact names, so no need
149                 # to check "domain in vhost.get_names()" explicitly here
150                 matching_vhosts.append(vhost)
151 
152         return matching_vhosts
153 
154     def _relevant_vhosts(self):
155         http01_port = str(self.configurator.config.http01_port)
156         relevant_vhosts = []
157         for vhost in self.configurator.vhosts:
158             if any(a.is_wildcard() or a.get_port() == http01_port for a in vhost.addrs):
159                 if not vhost.ssl:
160                     relevant_vhosts.append(vhost)
161         if not relevant_vhosts:
162             raise errors.PluginError(
163                 "Unable to find a virtual host listening on port {0} which is"
164                 " currently needed for Certbot to prove to the CA that you"
165                 " control your domain. Please add a virtual host for port"
166                 " {0}.".format(http01_port))
167 
168         return relevant_vhosts
169 
170     def _set_up_challenges(self):
171         if not os.path.isdir(self.challenge_dir):
172             old_umask = filesystem.umask(0o022)
173             try:
174                 filesystem.makedirs(self.challenge_dir, 0o755)
175             except OSError as exception:
176                 if exception.errno not in (errno.EEXIST, errno.EISDIR):
177                     raise errors.PluginError(
178                         "Couldn't create root for http-01 challenge")
179             finally:
180                 filesystem.umask(old_umask)
181 
182         responses = []
183         for achall in self.achalls:
184             responses.append(self._set_up_challenge(achall))
185 
186         return responses
187 
188     def _set_up_challenge(self, achall):
189         response, validation = achall.response_and_validation()
190 
191         name = os.path.join(self.challenge_dir, achall.chall.encode("token"))
192 
193         self.configurator.reverter.register_file_creation(True, name)
194         with open(name, 'wb') as f:
195             f.write(validation.encode())
196         filesystem.chmod(name, 0o644)
197 
198         return response
199 
200     def _set_up_include_directives(self, vhost):
201         """Includes override configuration to the beginning and to the end of
202         VirtualHost. Note that this include isn't added to Augeas search tree"""
203 
204         if vhost not in self.moded_vhosts:
205             logger.debug(
206                 "Adding a temporary challenge validation Include for name: %s in: %s",
207                 vhost.name, vhost.filep)
208             self.configurator.parser.add_dir_beginning(
209                 vhost.path, "Include", self.challenge_conf_pre)
210             self.configurator.parser.add_dir(
211                 vhost.path, "Include", self.challenge_conf_post)
212 
213             if not vhost.enabled:
214                 self.configurator.parser.add_dir(
215                     get_aug_path(self.configurator.parser.loc["default"]),
216                     "Include", vhost.filep)
217 
218             self.moded_vhosts.add(vhost)
219
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/certbot-apache/certbot_apache/_internal/http_01.py b/certbot-apache/certbot_apache/_internal/http_01.py
--- a/certbot-apache/certbot_apache/_internal/http_01.py
+++ b/certbot-apache/certbot_apache/_internal/http_01.py
@@ -95,10 +95,10 @@
     def _mod_config(self):
         selected_vhosts: List[VirtualHost] = []
         http_port = str(self.configurator.config.http01_port)
+
+        # Search for VirtualHosts matching by name
         for chall in self.achalls:
-            # Search for matching VirtualHosts
-            for vh in self._matching_vhosts(chall.domain):
-                selected_vhosts.append(vh)
+            selected_vhosts += self._matching_vhosts(chall.domain)
 
         # Ensure that we have one or more VirtualHosts that we can continue
         # with. (one that listens to port configured with --http-01-port)
@@ -107,9 +107,13 @@
             if any(a.is_wildcard() or a.get_port() == http_port for a in vhost.addrs):
                 found = True
 
-        if not found:
-            for vh in self._relevant_vhosts():
-                selected_vhosts.append(vh)
+        # If there's at least one elgible VirtualHost, also add all unnamed VirtualHosts
+        # because they might match at runtime (#8890)
+        if found:
+            selected_vhosts += self._unnamed_vhosts()
+        # Otherwise, add every Virtualhost which listens on the right port
+        else:
+            selected_vhosts += self._relevant_vhosts()
 
         # Add the challenge configuration
         for vh in selected_vhosts:
@@ -167,6 +171,10 @@
 
         return relevant_vhosts
 
+    def _unnamed_vhosts(self) -> List[VirtualHost]:
+        """Return all VirtualHost objects with no ServerName"""
+        return [vh for vh in self.configurator.vhosts if vh.name is None]
+
     def _set_up_challenges(self):
         if not os.path.isdir(self.challenge_dir):
             old_umask = filesystem.umask(0o022)

{"golden_diff": "diff --git a/certbot-apache/certbot_apache/_internal/http_01.py b/certbot-apache/certbot_apache/_internal/http_01.py\n--- a/certbot-apache/certbot_apache/_internal/http_01.py\n+++ b/certbot-apache/certbot_apache/_internal/http_01.py\n@@ -95,10 +95,10 @@\n     def _mod_config(self):\n         selected_vhosts: List[VirtualHost] = []\n         http_port = str(self.configurator.config.http01_port)\n+\n+        # Search for VirtualHosts matching by name\n         for chall in self.achalls:\n-            # Search for matching VirtualHosts\n-            for vh in self._matching_vhosts(chall.domain):\n-                selected_vhosts.append(vh)\n+            selected_vhosts += self._matching_vhosts(chall.domain)\n \n         # Ensure that we have one or more VirtualHosts that we can continue\n         # with. (one that listens to port configured with --http-01-port)\n@@ -107,9 +107,13 @@\n             if any(a.is_wildcard() or a.get_port() == http_port for a in vhost.addrs):\n                 found = True\n \n-        if not found:\n-            for vh in self._relevant_vhosts():\n-                selected_vhosts.append(vh)\n+        # If there's at least one elgible VirtualHost, also add all unnamed VirtualHosts\n+        # because they might match at runtime (#8890)\n+        if found:\n+            selected_vhosts += self._unnamed_vhosts()\n+        # Otherwise, add every Virtualhost which listens on the right port\n+        else:\n+            selected_vhosts += self._relevant_vhosts()\n \n         # Add the challenge configuration\n         for vh in selected_vhosts:\n@@ -167,6 +171,10 @@\n \n         return relevant_vhosts\n \n+    def _unnamed_vhosts(self) -> List[VirtualHost]:\n+        \"\"\"Return all VirtualHost objects with no ServerName\"\"\"\n+        return [vh for vh in self.configurator.vhosts if vh.name is None]\n+\n     def _set_up_challenges(self):\n         if not os.path.isdir(self.challenge_dir):\n             old_umask = filesystem.umask(0o022)\n", "issue": "apache authenticator should authenticate all duplicate vhosts\nSee https://community.letsencrypt.org/t/cant-renew-certificate/153274/3?u=_az. I've seen this a few other times as well.\r\n\r\nThe Apache authenticator needs to authenticate all of the virtual hosts which could match the requested domain, including duplicates and HTTPS ones.\r\n\r\n#6729 fixed this for the most part, but there are seemingly still some edge cases left over.\r\n\r\nLet's investigate and fix those.\n", "before_files": [{"content": "\"\"\"A class that performs HTTP-01 challenges for Apache\"\"\"\nimport errno\nimport logging\nfrom typing import List\nfrom typing import Set\n\nfrom certbot import errors\nfrom certbot.compat import filesystem\nfrom certbot.compat import os\nfrom certbot.plugins import common\nfrom certbot_apache._internal.obj import VirtualHost  # pylint: disable=unused-import\nfrom certbot_apache._internal.parser import get_aug_path\n\nlogger = logging.getLogger(__name__)\n\n\nclass ApacheHttp01(common.ChallengePerformer):\n    \"\"\"Class that performs HTTP-01 challenges within the Apache configurator.\"\"\"\n\n    CONFIG_TEMPLATE22_PRE = \"\"\"\\\n        RewriteEngine on\n        RewriteRule ^/\\\\.well-known/acme-challenge/([A-Za-z0-9-_=]+)$ {0}/$1 [L]\n\n    \"\"\"\n    CONFIG_TEMPLATE22_POST = \"\"\"\\\n        <Directory {0}>\n            Order Allow,Deny\n            Allow from all\n        </Directory>\n        <Location /.well-known/acme-challenge>\n            Order Allow,Deny\n            Allow from all\n        </Location>\n    \"\"\"\n\n    CONFIG_TEMPLATE24_PRE = \"\"\"\\\n        RewriteEngine on\n        RewriteRule ^/\\\\.well-known/acme-challenge/([A-Za-z0-9-_=]+)$ {0}/$1 [END]\n    \"\"\"\n    CONFIG_TEMPLATE24_POST = \"\"\"\\\n        <Directory {0}>\n            Require all granted\n        </Directory>\n        <Location /.well-known/acme-challenge>\n            Require all granted\n        </Location>\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.challenge_conf_pre = os.path.join(\n            self.configurator.conf(\"challenge-location\"),\n            \"le_http_01_challenge_pre.conf\")\n        self.challenge_conf_post = os.path.join(\n            self.configurator.conf(\"challenge-location\"),\n            \"le_http_01_challenge_post.conf\")\n        self.challenge_dir = os.path.join(\n            self.configurator.config.work_dir,\n            \"http_challenges\")\n        self.moded_vhosts: Set[VirtualHost] = set()\n\n    def perform(self):\n        \"\"\"Perform all HTTP-01 challenges.\"\"\"\n        if not self.achalls:\n            return []\n        # Save any changes to the configuration as a precaution\n        # About to make temporary changes to the config\n        self.configurator.save(\"Changes before challenge setup\", True)\n\n        self.configurator.ensure_listen(str(\n            self.configurator.config.http01_port))\n        self.prepare_http01_modules()\n\n        responses = self._set_up_challenges()\n\n        self._mod_config()\n        # Save reversible changes\n        self.configurator.save(\"HTTP Challenge\", True)\n\n        return responses\n\n    def prepare_http01_modules(self):\n        \"\"\"Make sure that we have the needed modules available for http01\"\"\"\n\n        if self.configurator.conf(\"handle-modules\"):\n            needed_modules = [\"rewrite\"]\n            if self.configurator.version < (2, 4):\n                needed_modules.append(\"authz_host\")\n            else:\n                needed_modules.append(\"authz_core\")\n            for mod in needed_modules:\n                if mod + \"_module\" not in self.configurator.parser.modules:\n                    self.configurator.enable_mod(mod, temp=True)\n\n    def _mod_config(self):\n        selected_vhosts: List[VirtualHost] = []\n        http_port = str(self.configurator.config.http01_port)\n        for chall in self.achalls:\n            # Search for matching VirtualHosts\n            for vh in self._matching_vhosts(chall.domain):\n                selected_vhosts.append(vh)\n\n        # Ensure that we have one or more VirtualHosts that we can continue\n        # with. (one that listens to port configured with --http-01-port)\n        found = False\n        for vhost in selected_vhosts:\n            if any(a.is_wildcard() or a.get_port() == http_port for a in vhost.addrs):\n                found = True\n\n        if not found:\n            for vh in self._relevant_vhosts():\n                selected_vhosts.append(vh)\n\n        # Add the challenge configuration\n        for vh in selected_vhosts:\n            self._set_up_include_directives(vh)\n\n        self.configurator.reverter.register_file_creation(\n            True, self.challenge_conf_pre)\n        self.configurator.reverter.register_file_creation(\n            True, self.challenge_conf_post)\n\n        if self.configurator.version < (2, 4):\n            config_template_pre = self.CONFIG_TEMPLATE22_PRE\n            config_template_post = self.CONFIG_TEMPLATE22_POST\n        else:\n            config_template_pre = self.CONFIG_TEMPLATE24_PRE\n            config_template_post = self.CONFIG_TEMPLATE24_POST\n\n        config_text_pre = config_template_pre.format(self.challenge_dir)\n        config_text_post = config_template_post.format(self.challenge_dir)\n\n        logger.debug(\"writing a pre config file with text:\\n %s\", config_text_pre)\n        with open(self.challenge_conf_pre, \"w\") as new_conf:\n            new_conf.write(config_text_pre)\n        logger.debug(\"writing a post config file with text:\\n %s\", config_text_post)\n        with open(self.challenge_conf_post, \"w\") as new_conf:\n            new_conf.write(config_text_post)\n\n    def _matching_vhosts(self, domain):\n        \"\"\"Return all VirtualHost objects that have the requested domain name or\n        a wildcard name that would match the domain in ServerName or ServerAlias\n        directive.\n        \"\"\"\n        matching_vhosts = []\n        for vhost in self.configurator.vhosts:\n            if self.configurator.domain_in_names(vhost.get_names(), domain):\n                # domain_in_names also matches the exact names, so no need\n                # to check \"domain in vhost.get_names()\" explicitly here\n                matching_vhosts.append(vhost)\n\n        return matching_vhosts\n\n    def _relevant_vhosts(self):\n        http01_port = str(self.configurator.config.http01_port)\n        relevant_vhosts = []\n        for vhost in self.configurator.vhosts:\n            if any(a.is_wildcard() or a.get_port() == http01_port for a in vhost.addrs):\n                if not vhost.ssl:\n                    relevant_vhosts.append(vhost)\n        if not relevant_vhosts:\n            raise errors.PluginError(\n                \"Unable to find a virtual host listening on port {0} which is\"\n                \" currently needed for Certbot to prove to the CA that you\"\n                \" control your domain. Please add a virtual host for port\"\n                \" {0}.\".format(http01_port))\n\n        return relevant_vhosts\n\n    def _set_up_challenges(self):\n        if not os.path.isdir(self.challenge_dir):\n            old_umask = filesystem.umask(0o022)\n            try:\n                filesystem.makedirs(self.challenge_dir, 0o755)\n            except OSError as exception:\n                if exception.errno not in (errno.EEXIST, errno.EISDIR):\n                    raise errors.PluginError(\n                        \"Couldn't create root for http-01 challenge\")\n            finally:\n                filesystem.umask(old_umask)\n\n        responses = []\n        for achall in self.achalls:\n            responses.append(self._set_up_challenge(achall))\n\n        return responses\n\n    def _set_up_challenge(self, achall):\n        response, validation = achall.response_and_validation()\n\n        name = os.path.join(self.challenge_dir, achall.chall.encode(\"token\"))\n\n        self.configurator.reverter.register_file_creation(True, name)\n        with open(name, 'wb') as f:\n            f.write(validation.encode())\n        filesystem.chmod(name, 0o644)\n\n        return response\n\n    def _set_up_include_directives(self, vhost):\n        \"\"\"Includes override configuration to the beginning and to the end of\n        VirtualHost. Note that this include isn't added to Augeas search tree\"\"\"\n\n        if vhost not in self.moded_vhosts:\n            logger.debug(\n                \"Adding a temporary challenge validation Include for name: %s in: %s\",\n                vhost.name, vhost.filep)\n            self.configurator.parser.add_dir_beginning(\n                vhost.path, \"Include\", self.challenge_conf_pre)\n            self.configurator.parser.add_dir(\n                vhost.path, \"Include\", self.challenge_conf_post)\n\n            if not vhost.enabled:\n                self.configurator.parser.add_dir(\n                    get_aug_path(self.configurator.parser.loc[\"default\"]),\n                    \"Include\", vhost.filep)\n\n            self.moded_vhosts.add(vhost)\n", "path": "certbot-apache/certbot_apache/_internal/http_01.py"}], "after_files": [{"content": "\"\"\"A class that performs HTTP-01 challenges for Apache\"\"\"\nimport errno\nimport logging\nfrom typing import List\nfrom typing import Set\n\nfrom certbot import errors\nfrom certbot.compat import filesystem\nfrom certbot.compat import os\nfrom certbot.plugins import common\nfrom certbot_apache._internal.obj import VirtualHost  # pylint: disable=unused-import\nfrom certbot_apache._internal.parser import get_aug_path\n\nlogger = logging.getLogger(__name__)\n\n\nclass ApacheHttp01(common.ChallengePerformer):\n    \"\"\"Class that performs HTTP-01 challenges within the Apache configurator.\"\"\"\n\n    CONFIG_TEMPLATE22_PRE = \"\"\"\\\n        RewriteEngine on\n        RewriteRule ^/\\\\.well-known/acme-challenge/([A-Za-z0-9-_=]+)$ {0}/$1 [L]\n\n    \"\"\"\n    CONFIG_TEMPLATE22_POST = \"\"\"\\\n        <Directory {0}>\n            Order Allow,Deny\n            Allow from all\n        </Directory>\n        <Location /.well-known/acme-challenge>\n            Order Allow,Deny\n            Allow from all\n        </Location>\n    \"\"\"\n\n    CONFIG_TEMPLATE24_PRE = \"\"\"\\\n        RewriteEngine on\n        RewriteRule ^/\\\\.well-known/acme-challenge/([A-Za-z0-9-_=]+)$ {0}/$1 [END]\n    \"\"\"\n    CONFIG_TEMPLATE24_POST = \"\"\"\\\n        <Directory {0}>\n            Require all granted\n        </Directory>\n        <Location /.well-known/acme-challenge>\n            Require all granted\n        </Location>\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.challenge_conf_pre = os.path.join(\n            self.configurator.conf(\"challenge-location\"),\n            \"le_http_01_challenge_pre.conf\")\n        self.challenge_conf_post = os.path.join(\n            self.configurator.conf(\"challenge-location\"),\n            \"le_http_01_challenge_post.conf\")\n        self.challenge_dir = os.path.join(\n            self.configurator.config.work_dir,\n            \"http_challenges\")\n        self.moded_vhosts: Set[VirtualHost] = set()\n\n    def perform(self):\n        \"\"\"Perform all HTTP-01 challenges.\"\"\"\n        if not self.achalls:\n            return []\n        # Save any changes to the configuration as a precaution\n        # About to make temporary changes to the config\n        self.configurator.save(\"Changes before challenge setup\", True)\n\n        self.configurator.ensure_listen(str(\n            self.configurator.config.http01_port))\n        self.prepare_http01_modules()\n\n        responses = self._set_up_challenges()\n\n        self._mod_config()\n        # Save reversible changes\n        self.configurator.save(\"HTTP Challenge\", True)\n\n        return responses\n\n    def prepare_http01_modules(self):\n        \"\"\"Make sure that we have the needed modules available for http01\"\"\"\n\n        if self.configurator.conf(\"handle-modules\"):\n            needed_modules = [\"rewrite\"]\n            if self.configurator.version < (2, 4):\n                needed_modules.append(\"authz_host\")\n            else:\n                needed_modules.append(\"authz_core\")\n            for mod in needed_modules:\n                if mod + \"_module\" not in self.configurator.parser.modules:\n                    self.configurator.enable_mod(mod, temp=True)\n\n    def _mod_config(self):\n        selected_vhosts: List[VirtualHost] = []\n        http_port = str(self.configurator.config.http01_port)\n\n        # Search for VirtualHosts matching by name\n        for chall in self.achalls:\n            selected_vhosts += self._matching_vhosts(chall.domain)\n\n        # Ensure that we have one or more VirtualHosts that we can continue\n        # with. (one that listens to port configured with --http-01-port)\n        found = False\n        for vhost in selected_vhosts:\n            if any(a.is_wildcard() or a.get_port() == http_port for a in vhost.addrs):\n                found = True\n\n        # If there's at least one elgible VirtualHost, also add all unnamed VirtualHosts\n        # because they might match at runtime (#8890)\n        if found:\n            selected_vhosts += self._unnamed_vhosts()\n        # Otherwise, add every Virtualhost which listens on the right port\n        else:\n            selected_vhosts += self._relevant_vhosts()\n\n        # Add the challenge configuration\n        for vh in selected_vhosts:\n            self._set_up_include_directives(vh)\n\n        self.configurator.reverter.register_file_creation(\n            True, self.challenge_conf_pre)\n        self.configurator.reverter.register_file_creation(\n            True, self.challenge_conf_post)\n\n        if self.configurator.version < (2, 4):\n            config_template_pre = self.CONFIG_TEMPLATE22_PRE\n            config_template_post = self.CONFIG_TEMPLATE22_POST\n        else:\n            config_template_pre = self.CONFIG_TEMPLATE24_PRE\n            config_template_post = self.CONFIG_TEMPLATE24_POST\n\n        config_text_pre = config_template_pre.format(self.challenge_dir)\n        config_text_post = config_template_post.format(self.challenge_dir)\n\n        logger.debug(\"writing a pre config file with text:\\n %s\", config_text_pre)\n        with open(self.challenge_conf_pre, \"w\") as new_conf:\n            new_conf.write(config_text_pre)\n        logger.debug(\"writing a post config file with text:\\n %s\", config_text_post)\n        with open(self.challenge_conf_post, \"w\") as new_conf:\n            new_conf.write(config_text_post)\n\n    def _matching_vhosts(self, domain):\n        \"\"\"Return all VirtualHost objects that have the requested domain name or\n        a wildcard name that would match the domain in ServerName or ServerAlias\n        directive.\n        \"\"\"\n        matching_vhosts = []\n        for vhost in self.configurator.vhosts:\n            if self.configurator.domain_in_names(vhost.get_names(), domain):\n                # domain_in_names also matches the exact names, so no need\n                # to check \"domain in vhost.get_names()\" explicitly here\n                matching_vhosts.append(vhost)\n\n        return matching_vhosts\n\n    def _relevant_vhosts(self):\n        http01_port = str(self.configurator.config.http01_port)\n        relevant_vhosts = []\n        for vhost in self.configurator.vhosts:\n            if any(a.is_wildcard() or a.get_port() == http01_port for a in vhost.addrs):\n                if not vhost.ssl:\n                    relevant_vhosts.append(vhost)\n        if not relevant_vhosts:\n            raise errors.PluginError(\n                \"Unable to find a virtual host listening on port {0} which is\"\n                \" currently needed for Certbot to prove to the CA that you\"\n                \" control your domain. Please add a virtual host for port\"\n                \" {0}.\".format(http01_port))\n\n        return relevant_vhosts\n\n    def _unnamed_vhosts(self) -> List[VirtualHost]:\n        \"\"\"Return all VirtualHost objects with no ServerName\"\"\"\n        return [vh for vh in self.configurator.vhosts if vh.name is None]\n\n    def _set_up_challenges(self):\n        if not os.path.isdir(self.challenge_dir):\n            old_umask = filesystem.umask(0o022)\n            try:\n                filesystem.makedirs(self.challenge_dir, 0o755)\n            except OSError as exception:\n                if exception.errno not in (errno.EEXIST, errno.EISDIR):\n                    raise errors.PluginError(\n                        \"Couldn't create root for http-01 challenge\")\n            finally:\n                filesystem.umask(old_umask)\n\n        responses = []\n        for achall in self.achalls:\n            responses.append(self._set_up_challenge(achall))\n\n        return responses\n\n    def _set_up_challenge(self, achall):\n        response, validation = achall.response_and_validation()\n\n        name = os.path.join(self.challenge_dir, achall.chall.encode(\"token\"))\n\n        self.configurator.reverter.register_file_creation(True, name)\n        with open(name, 'wb') as f:\n            f.write(validation.encode())\n        filesystem.chmod(name, 0o644)\n\n        return response\n\n    def _set_up_include_directives(self, vhost):\n        \"\"\"Includes override configuration to the beginning and to the end of\n        VirtualHost. Note that this include isn't added to Augeas search tree\"\"\"\n\n        if vhost not in self.moded_vhosts:\n            logger.debug(\n                \"Adding a temporary challenge validation Include for name: %s in: %s\",\n                vhost.name, vhost.filep)\n            self.configurator.parser.add_dir_beginning(\n                vhost.path, \"Include\", self.challenge_conf_pre)\n            self.configurator.parser.add_dir(\n                vhost.path, \"Include\", self.challenge_conf_post)\n\n            if not vhost.enabled:\n                self.configurator.parser.add_dir(\n                    get_aug_path(self.configurator.parser.loc[\"default\"]),\n                    \"Include\", vhost.filep)\n\n            self.moded_vhosts.add(vhost)\n", "path": "certbot-apache/certbot_apache/_internal/http_01.py"}]}