Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a67299e

Browse files
committed
Fix issue #8806: add SSL contexts support to ftplib
1 parent 6085321 commit a67299e

4 files changed

Lines changed: 49 additions & 6 deletions

File tree

Doc/library/ftplib.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ The module defines the following items:
6565
Support for the :keyword:`with` statement was added.
6666

6767

68-
.. class:: FTP_TLS(host='', user='', passwd='', acct='', [keyfile[, certfile[, timeout]]])
68+
.. class:: FTP_TLS(host='', user='', passwd='', acct='', [keyfile[, certfile[, context[, timeout]]]])
6969

7070
A :class:`FTP` subclass which adds TLS support to FTP as described in
7171
:rfc:`4217`.
@@ -74,6 +74,9 @@ The module defines the following items:
7474
explicitly ask for it by calling the :meth:`prot_p` method.
7575
*keyfile* and *certfile* are optional -- they can contain a PEM formatted
7676
private key and certificate chain file name for the SSL connection.
77+
*context* parameter is a :class:`ssl.SSLContext` object which allows
78+
bundling SSL configuration options, certificates and private keys into a
79+
single (potentially long-lived) structure.
7780

7881
.. versionadded:: 3.2
7982

Lib/ftplib.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -638,9 +638,17 @@ class FTP_TLS(FTP):
638638
ssl_version = ssl.PROTOCOL_TLSv1
639639

640640
def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
641-
certfile=None, timeout=_GLOBAL_DEFAULT_TIMEOUT):
641+
certfile=None, context=None,
642+
timeout=_GLOBAL_DEFAULT_TIMEOUT):
643+
if context is not None and keyfile is not None:
644+
raise ValueError("context and keyfile arguments are mutually "
645+
"exclusive")
646+
if context is not None and certfile is not None:
647+
raise ValueError("context and certfile arguments are mutually "
648+
"exclusive")
642649
self.keyfile = keyfile
643650
self.certfile = certfile
651+
self.context = context
644652
self._prot_p = False
645653
FTP.__init__(self, host, user, passwd, acct, timeout)
646654

@@ -657,8 +665,12 @@ def auth(self):
657665
resp = self.voidcmd('AUTH TLS')
658666
else:
659667
resp = self.voidcmd('AUTH SSL')
660-
self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile,
661-
ssl_version=self.ssl_version)
668+
if self.context is not None:
669+
self.sock = self.context.wrap_socket(self.sock)
670+
else:
671+
self.sock = ssl.wrap_socket(self.sock, self.keyfile,
672+
self.certfile,
673+
ssl_version=self.ssl_version)
662674
self.file = self.sock.makefile(mode='r', encoding=self.encoding)
663675
return resp
664676

@@ -689,8 +701,11 @@ def prot_c(self):
689701
def ntransfercmd(self, cmd, rest=None):
690702
conn, size = FTP.ntransfercmd(self, cmd, rest)
691703
if self._prot_p:
692-
conn = ssl.wrap_socket(conn, self.keyfile, self.certfile,
693-
ssl_version=self.ssl_version)
704+
if self.context is not None:
705+
conn = self.context.wrap_socket(conn)
706+
else:
707+
conn = ssl.wrap_socket(conn, self.keyfile, self.certfile,
708+
ssl_version=self.ssl_version)
694709
return conn, size
695710

696711
def retrbinary(self, cmd, callback, blocksize=8192, rest=None):

Lib/test/test_ftplib.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,29 @@ def test_auth_ssl(self):
719719
finally:
720720
self.client.ssl_version = ssl.PROTOCOL_TLSv1
721721

722+
def test_context(self):
723+
self.client.quit()
724+
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
725+
self.assertRaises(ValueError, ftplib.FTP_TLS, keyfile=CERTFILE,
726+
context=ctx)
727+
self.assertRaises(ValueError, ftplib.FTP_TLS, certfile=CERTFILE,
728+
context=ctx)
729+
self.assertRaises(ValueError, ftplib.FTP_TLS, certfile=CERTFILE,
730+
keyfile=CERTFILE, context=ctx)
731+
732+
self.client = ftplib.FTP_TLS(context=ctx, timeout=2)
733+
self.client.connect(self.server.host, self.server.port)
734+
self.assertNotIsInstance(self.client.sock, ssl.SSLSocket)
735+
self.client.auth()
736+
self.assertIs(self.client.sock.context, ctx)
737+
self.assertIsInstance(self.client.sock, ssl.SSLSocket)
738+
739+
self.client.prot_p()
740+
sock = self.client.transfercmd('list')
741+
self.assertIs(self.client.sock.context, ctx)
742+
self.assertIsInstance(sock, ssl.SSLSocket)
743+
sock.close()
744+
722745

723746
class TestTimeouts(TestCase):
724747

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ C-API
392392
Library
393393
-------
394394

395+
- Issue #8806: add SSL contexts support to ftplib.
396+
395397
- Issue #4769: Fix main() function of the base64 module, use sys.stdin.buffer
396398
and sys.stdout.buffer (instead of sys.stdin and sys.stdout) to use the bytes
397399
API

0 commit comments

Comments
 (0)