Kaydet (Commit) 00535e8e authored tarafından Andi Albrecht's avatar Andi Albrecht Kaydeden (comit) Tim Graham

Fixed #20743 -- Added support for keyfile/certfile in SMTP connections.

Thanks jwmayfield, serg.partizan, and Wojciech Banaś for work on the patch.
üst 61f56e23
...@@ -194,6 +194,8 @@ EMAIL_HOST_USER = '' ...@@ -194,6 +194,8 @@ EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = '' EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = False EMAIL_USE_TLS = False
EMAIL_USE_SSL = False EMAIL_USE_SSL = False
EMAIL_SSL_CERTFILE = None
EMAIL_SSL_KEYFILE = None
# List of strings representing installed apps. # List of strings representing installed apps.
INSTALLED_APPS = () INSTALLED_APPS = ()
......
...@@ -15,6 +15,7 @@ class EmailBackend(BaseEmailBackend): ...@@ -15,6 +15,7 @@ class EmailBackend(BaseEmailBackend):
""" """
def __init__(self, host=None, port=None, username=None, password=None, def __init__(self, host=None, port=None, username=None, password=None,
use_tls=None, fail_silently=False, use_ssl=None, timeout=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None,
ssl_keyfile=None, ssl_certfile=None,
**kwargs): **kwargs):
super(EmailBackend, self).__init__(fail_silently=fail_silently) super(EmailBackend, self).__init__(fail_silently=fail_silently)
self.host = host or settings.EMAIL_HOST self.host = host or settings.EMAIL_HOST
...@@ -24,6 +25,8 @@ class EmailBackend(BaseEmailBackend): ...@@ -24,6 +25,8 @@ class EmailBackend(BaseEmailBackend):
self.use_tls = settings.EMAIL_USE_TLS if use_tls is None else use_tls self.use_tls = settings.EMAIL_USE_TLS if use_tls is None else use_tls
self.use_ssl = settings.EMAIL_USE_SSL if use_ssl is None else use_ssl self.use_ssl = settings.EMAIL_USE_SSL if use_ssl is None else use_ssl
self.timeout = timeout self.timeout = timeout
self.ssl_keyfile = settings.EMAIL_SSL_KEYFILE if ssl_keyfile is None else ssl_keyfile
self.ssl_certfile = settings.EMAIL_SSL_CERTFILE if ssl_certfile is None else ssl_certfile
if self.use_ssl and self.use_tls: if self.use_ssl and self.use_tls:
raise ValueError( raise ValueError(
"EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set " "EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set "
...@@ -46,6 +49,11 @@ class EmailBackend(BaseEmailBackend): ...@@ -46,6 +49,11 @@ class EmailBackend(BaseEmailBackend):
connection_params = {'local_hostname': DNS_NAME.get_fqdn()} connection_params = {'local_hostname': DNS_NAME.get_fqdn()}
if self.timeout is not None: if self.timeout is not None:
connection_params['timeout'] = self.timeout connection_params['timeout'] = self.timeout
if self.use_ssl:
connection_params.update({
'keyfile': self.ssl_keyfile,
'certfile': self.ssl_certfile,
})
try: try:
self.connection = connection_class(self.host, self.port, **connection_params) self.connection = connection_class(self.host, self.port, **connection_params)
...@@ -53,7 +61,7 @@ class EmailBackend(BaseEmailBackend): ...@@ -53,7 +61,7 @@ class EmailBackend(BaseEmailBackend):
# non-secure connections. # non-secure connections.
if not self.use_ssl and self.use_tls: if not self.use_ssl and self.use_tls:
self.connection.ehlo() self.connection.ehlo()
self.connection.starttls() self.connection.starttls(keyfile=self.ssl_keyfile, certfile=self.ssl_certfile)
self.connection.ehlo() self.connection.ehlo()
if self.username and self.password: if self.username and self.password:
self.connection.login(self.username, self.password) self.connection.login(self.username, self.password)
......
...@@ -1228,6 +1228,38 @@ see the explicit TLS setting :setting:`EMAIL_USE_TLS`. ...@@ -1228,6 +1228,38 @@ see the explicit TLS setting :setting:`EMAIL_USE_TLS`.
Note that :setting:`EMAIL_USE_TLS`/:setting:`EMAIL_USE_SSL` are mutually Note that :setting:`EMAIL_USE_TLS`/:setting:`EMAIL_USE_SSL` are mutually
exclusive, so only set one of those settings to ``True``. exclusive, so only set one of those settings to ``True``.
.. setting:: EMAIL_SSL_CERTFILE
EMAIL_SSL_CERTFILE
------------------
.. versionadded:: 1.8
Default: ``None``
If :setting:`EMAIL_USE_SSL` or :setting:`EMAIL_USE_TLS` is ``True``, you can
optionally specify the path to a PEM-formatted certificate chain file to use
for the SSL connection.
.. setting:: EMAIL_SSL_KEYFILE
EMAIL_SSL_KEYFILE
-----------------
.. versionadded:: 1.8
Default: ``None``
If :setting:`EMAIL_USE_SSL` or :setting:`EMAIL_USE_TLS` is ``True``, you can
optionally specify the path to a PEM-formatted private key file to use for the
SSL connection.
Note that setting :setting:`EMAIL_SSL_CERTFILE` and :setting:`EMAIL_SSL_KEYFILE`
doesn't result in any certificate checking. They're passed to the underlying SSL
connection. Please refer to the documentation of Python's
:func:`python:ssl.wrap_socket` function for details on how the certificate chain
file and private key file are handled.
.. setting:: FILE_CHARSET .. setting:: FILE_CHARSET
FILE_CHARSET FILE_CHARSET
...@@ -2926,6 +2958,8 @@ Email ...@@ -2926,6 +2958,8 @@ Email
* :setting:`EMAIL_HOST_PASSWORD` * :setting:`EMAIL_HOST_PASSWORD`
* :setting:`EMAIL_HOST_USER` * :setting:`EMAIL_HOST_USER`
* :setting:`EMAIL_PORT` * :setting:`EMAIL_PORT`
* :setting:`EMAIL_SSL_CERTFILE`
* :setting:`EMAIL_SSL_KEYFILE`
* :setting:`EMAIL_SUBJECT_PREFIX` * :setting:`EMAIL_SUBJECT_PREFIX`
* :setting:`EMAIL_USE_TLS` * :setting:`EMAIL_USE_TLS`
* :setting:`MANAGERS` * :setting:`MANAGERS`
......
...@@ -140,6 +140,10 @@ Email ...@@ -140,6 +140,10 @@ Email
* :ref:`Email backends <topic-email-backends>` now support the context manager * :ref:`Email backends <topic-email-backends>` now support the context manager
protocol for opening and closing connections. protocol for opening and closing connections.
* The SMTP email backend now supports ``keyfile`` and ``certfile``
authentication with the :setting:`EMAIL_SSL_CERTFILE` and
:setting:`EMAIL_SSL_KEYFILE` settings.
File Storage File Storage
^^^^^^^^^^^^ ^^^^^^^^^^^^
......
...@@ -426,6 +426,7 @@ Palau ...@@ -426,6 +426,7 @@ Palau
params params
parens parens
pdf pdf
PEM
perl perl
permalink permalink
pessimization pessimization
......
...@@ -445,13 +445,14 @@ can :ref:`write your own email backend <topic-custom-email-backend>`. ...@@ -445,13 +445,14 @@ can :ref:`write your own email backend <topic-custom-email-backend>`.
SMTP backend SMTP backend
~~~~~~~~~~~~ ~~~~~~~~~~~~
.. class:: backends.smtp.EmailBackend([host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, **kwargs]) .. class:: backends.smtp.EmailBackend([host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, ssl_keyfile=None, ssl_certfile=None, **kwargs])
This is the default backend. Email will be sent through a SMTP server. This is the default backend. Email will be sent through a SMTP server.
The server address and authentication credentials are set in the The server address and authentication credentials are set in the
:setting:`EMAIL_HOST`, :setting:`EMAIL_PORT`, :setting:`EMAIL_HOST_USER`, :setting:`EMAIL_HOST`, :setting:`EMAIL_PORT`, :setting:`EMAIL_HOST_USER`,
:setting:`EMAIL_HOST_PASSWORD`, :setting:`EMAIL_USE_TLS` and :setting:`EMAIL_HOST_PASSWORD`, :setting:`EMAIL_USE_TLS`,
:setting:`EMAIL_USE_SSL` settings in your settings file. :setting:`EMAIL_USE_SSL`, :setting:`EMAIL_SSL_CERTFILE` and
:setting:`EMAIL_SSL_KEYFILE` settings in your settings file.
The SMTP backend is the default configuration inherited by Django. If you The SMTP backend is the default configuration inherited by Django. If you
want to specify it explicitly, put the following in your settings:: want to specify it explicitly, put the following in your settings::
...@@ -481,6 +482,11 @@ SMTP backend ...@@ -481,6 +482,11 @@ SMTP backend
If unspecified, the default ``timeout`` will be the one provided by If unspecified, the default ``timeout`` will be the one provided by
:func:`socket.getdefaulttimeout()`, which defaults to ``None`` (no timeout). :func:`socket.getdefaulttimeout()`, which defaults to ``None`` (no timeout).
.. versionchanged:: 1.8
The ``ssl_keyfile`` and ``ssl_certfile`` parameters and
corresponding settings were added.
.. _topic-email-console-backend: .. _topic-email-console-backend:
Console backend Console backend
......
...@@ -969,6 +969,34 @@ class SMTPBackendTests(BaseEmailBackendTests, SimpleTestCase): ...@@ -969,6 +969,34 @@ class SMTPBackendTests(BaseEmailBackendTests, SimpleTestCase):
backend = smtp.EmailBackend() backend = smtp.EmailBackend()
self.assertFalse(backend.use_ssl) self.assertFalse(backend.use_ssl)
@override_settings(EMAIL_SSL_CERTFILE='foo')
def test_email_ssl_certfile_use_settings(self):
backend = smtp.EmailBackend()
self.assertEqual(backend.ssl_certfile, 'foo')
@override_settings(EMAIL_SSL_CERTFILE='foo')
def test_email_ssl_certfile_override_settings(self):
backend = smtp.EmailBackend(ssl_certfile='bar')
self.assertEqual(backend.ssl_certfile, 'bar')
def test_email_ssl_certfile_default_disabled(self):
backend = smtp.EmailBackend()
self.assertEqual(backend.ssl_certfile, None)
@override_settings(EMAIL_SSL_KEYFILE='foo')
def test_email_ssl_keyfile_use_settings(self):
backend = smtp.EmailBackend()
self.assertEqual(backend.ssl_keyfile, 'foo')
@override_settings(EMAIL_SSL_KEYFILE='foo')
def test_email_ssl_keyfile_override_settings(self):
backend = smtp.EmailBackend(ssl_keyfile='bar')
self.assertEqual(backend.ssl_keyfile, 'bar')
def test_email_ssl_keyfile_default_disabled(self):
backend = smtp.EmailBackend()
self.assertEqual(backend.ssl_keyfile, None)
@override_settings(EMAIL_USE_TLS=True) @override_settings(EMAIL_USE_TLS=True)
def test_email_tls_attempts_starttls(self): def test_email_tls_attempts_starttls(self):
backend = smtp.EmailBackend() backend = smtp.EmailBackend()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment