mirror of
https://github.com/certbot/certbot.git
synced 2026-08-01 19:14:54 +02:00
http-01 for manual plugin
This commit is contained in:
@@ -27,7 +27,7 @@ class Authenticator(common.Plugin):
|
|||||||
"""Manual Authenticator.
|
"""Manual Authenticator.
|
||||||
|
|
||||||
This plugin requires user's manual intervention in setting up a HTTP
|
This plugin requires user's manual intervention in setting up a HTTP
|
||||||
server for solving SimpleHTTP challenges and thus does not need to be
|
server for solving http-01 challenges and thus does not need to be
|
||||||
run as a privileged process. Alternatively shows instructions on how
|
run as a privileged process. Alternatively shows instructions on how
|
||||||
to use Python's built-in HTTP server.
|
to use Python's built-in HTTP server.
|
||||||
|
|
||||||
@@ -68,9 +68,9 @@ Are you OK with your IP being logged?
|
|||||||
# anything recursively under the cwd
|
# anything recursively under the cwd
|
||||||
|
|
||||||
CMD_TEMPLATE = """\
|
CMD_TEMPLATE = """\
|
||||||
mkdir -p {root}/public_html/{response.URI_ROOT_PATH}
|
mkdir -p {root}/public_html/{achall.URI_ROOT_PATH}
|
||||||
cd {root}/public_html
|
cd {root}/public_html
|
||||||
printf "%s" {validation} > {response.URI_ROOT_PATH}/{encoded_token}
|
printf "%s" {validation} > {achall.URI_ROOT_PATH}/{encoded_token}
|
||||||
# run only once per server:
|
# run only once per server:
|
||||||
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \\
|
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \\
|
||||||
"import BaseHTTPServer, SimpleHTTPServer; \\
|
"import BaseHTTPServer, SimpleHTTPServer; \\
|
||||||
@@ -95,14 +95,14 @@ s.serve_forever()" """
|
|||||||
|
|
||||||
def more_info(self): # pylint: disable=missing-docstring,no-self-use
|
def more_info(self): # pylint: disable=missing-docstring,no-self-use
|
||||||
return ("This plugin requires user's manual intervention in setting "
|
return ("This plugin requires user's manual intervention in setting "
|
||||||
"up an HTTP server for solving SimpleHTTP challenges and thus "
|
"up an HTTP server for solving http-01 challenges and thus "
|
||||||
"does not need to be run as a privileged process. "
|
"does not need to be run as a privileged process. "
|
||||||
"Alternatively shows instructions on how to use Python's "
|
"Alternatively shows instructions on how to use Python's "
|
||||||
"built-in HTTP server.")
|
"built-in HTTP server.")
|
||||||
|
|
||||||
def get_chall_pref(self, domain):
|
def get_chall_pref(self, domain):
|
||||||
# pylint: disable=missing-docstring,no-self-use,unused-argument
|
# pylint: disable=missing-docstring,no-self-use,unused-argument
|
||||||
return [challenges.SimpleHTTP]
|
return [challenges.HTTP01]
|
||||||
|
|
||||||
def perform(self, achalls): # pylint: disable=missing-docstring
|
def perform(self, achalls): # pylint: disable=missing-docstring
|
||||||
responses = []
|
responses = []
|
||||||
@@ -130,16 +130,16 @@ s.serve_forever()" """
|
|||||||
# same path for each challenge response would be easier for
|
# same path for each challenge response would be easier for
|
||||||
# users, but will not work if multiple domains point at the
|
# users, but will not work if multiple domains point at the
|
||||||
# same server: default command doesn't support virtual hosts
|
# same server: default command doesn't support virtual hosts
|
||||||
response, validation = achall.gen_response_and_validation(
|
response, validation = achall.response_and_validation()
|
||||||
tls=False) # SimpleHTTP TLS is dead: ietf-wg-acme/acme#7
|
|
||||||
|
|
||||||
port = (response.port if self.config.simple_http_port is None
|
port = (response.port if self.config.simple_http_port is None
|
||||||
else int(self.config.simple_http_port))
|
else int(self.config.simple_http_port))
|
||||||
command = self.CMD_TEMPLATE.format(
|
command = self.CMD_TEMPLATE.format(
|
||||||
root=self._root, achall=achall, response=response,
|
root=self._root, achall=achall, response=response,
|
||||||
validation=pipes.quote(validation.json_dumps()),
|
# TODO(kuba): pipes still necessary?
|
||||||
|
validation=pipes.quote(validation),
|
||||||
encoded_token=achall.chall.encode("token"),
|
encoded_token=achall.chall.encode("token"),
|
||||||
ct=response.CONTENT_TYPE, port=port)
|
ct=achall.CONTENT_TYPE, port=port)
|
||||||
if self.conf("test-mode"):
|
if self.conf("test-mode"):
|
||||||
logger.debug("Test mode. Executing the manual command: %s", command)
|
logger.debug("Test mode. Executing the manual command: %s", command)
|
||||||
# sh shipped with OS X does't support echo -n, but supports printf
|
# sh shipped with OS X does't support echo -n, but supports printf
|
||||||
@@ -168,9 +168,9 @@ s.serve_forever()" """
|
|||||||
raise errors.PluginError("Must agree to IP logging to proceed")
|
raise errors.PluginError("Must agree to IP logging to proceed")
|
||||||
|
|
||||||
self._notify_and_wait(self.MESSAGE_TEMPLATE.format(
|
self._notify_and_wait(self.MESSAGE_TEMPLATE.format(
|
||||||
validation=validation.json_dumps(), response=response,
|
validation=validation, response=response,
|
||||||
uri=response.uri(achall.domain, achall.challb.chall),
|
uri=achall.chall.uri(achall.domain),
|
||||||
ct=response.CONTENT_TYPE, command=command))
|
ct=achall.CONTENT_TYPE, command=command))
|
||||||
|
|
||||||
if response.simple_verify(
|
if response.simple_verify(
|
||||||
achall.chall, achall.domain,
|
achall.chall, achall.domain,
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class AuthenticatorTest(unittest.TestCase):
|
|||||||
self.config = mock.MagicMock(
|
self.config = mock.MagicMock(
|
||||||
simple_http_port=8080, manual_test_mode=False)
|
simple_http_port=8080, manual_test_mode=False)
|
||||||
self.auth = Authenticator(config=self.config, name="manual")
|
self.auth = Authenticator(config=self.config, name="manual")
|
||||||
self.achalls = [achallenges.SimpleHTTP(
|
self.achalls = [achallenges.KeyAuthorizationAnnotatedChallenge(
|
||||||
challb=acme_util.SIMPLE_HTTP_P, domain="foo.com", account_key=KEY)]
|
challb=acme_util.HTTP01_P, domain="foo.com", account_key=KEY)]
|
||||||
|
|
||||||
config_test_mode = mock.MagicMock(
|
config_test_mode = mock.MagicMock(
|
||||||
simple_http_port=8080, manual_test_mode=True)
|
simple_http_port=8080, manual_test_mode=True)
|
||||||
@@ -45,13 +45,13 @@ class AuthenticatorTest(unittest.TestCase):
|
|||||||
|
|
||||||
@mock.patch("letsencrypt.plugins.manual.zope.component.getUtility")
|
@mock.patch("letsencrypt.plugins.manual.zope.component.getUtility")
|
||||||
@mock.patch("letsencrypt.plugins.manual.sys.stdout")
|
@mock.patch("letsencrypt.plugins.manual.sys.stdout")
|
||||||
@mock.patch("acme.challenges.SimpleHTTPResponse.simple_verify")
|
@mock.patch("acme.challenges.HTTP01Response.simple_verify")
|
||||||
@mock.patch("__builtin__.raw_input")
|
@mock.patch("__builtin__.raw_input")
|
||||||
def test_perform(self, mock_raw_input, mock_verify, mock_stdout, mock_interaction):
|
def test_perform(self, mock_raw_input, mock_verify, mock_stdout, mock_interaction):
|
||||||
mock_verify.return_value = True
|
mock_verify.return_value = True
|
||||||
mock_interaction().yesno.return_value = True
|
mock_interaction().yesno.return_value = True
|
||||||
|
|
||||||
resp = challenges.SimpleHTTPResponse(tls=False)
|
resp = self.achalls[0].response(KEY)
|
||||||
self.assertEqual([resp], self.auth.perform(self.achalls))
|
self.assertEqual([resp], self.auth.perform(self.achalls))
|
||||||
self.assertEqual(1, mock_raw_input.call_count)
|
self.assertEqual(1, mock_raw_input.call_count)
|
||||||
mock_verify.assert_called_with(
|
mock_verify.assert_called_with(
|
||||||
@@ -89,7 +89,7 @@ class AuthenticatorTest(unittest.TestCase):
|
|||||||
|
|
||||||
@mock.patch("letsencrypt.plugins.manual.socket.socket")
|
@mock.patch("letsencrypt.plugins.manual.socket.socket")
|
||||||
@mock.patch("letsencrypt.plugins.manual.time.sleep", autospec=True)
|
@mock.patch("letsencrypt.plugins.manual.time.sleep", autospec=True)
|
||||||
@mock.patch("acme.challenges.SimpleHTTPResponse.simple_verify",
|
@mock.patch("acme.challenges.HTTP01Response.simple_verify",
|
||||||
autospec=True)
|
autospec=True)
|
||||||
@mock.patch("letsencrypt.plugins.manual.subprocess.Popen", autospec=True)
|
@mock.patch("letsencrypt.plugins.manual.subprocess.Popen", autospec=True)
|
||||||
def test_perform_test_mode(self, mock_popen, mock_verify, mock_sleep,
|
def test_perform_test_mode(self, mock_popen, mock_verify, mock_sleep,
|
||||||
|
|||||||
Reference in New Issue
Block a user