Skip to content

Commit 32ce723

Browse files
Add tls to ftp (#1581)
1 parent 36cd82e commit 32ce723

File tree

5 files changed

+109
-11
lines changed

5 files changed

+109
-11
lines changed

fsspec/implementations/ftp.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import sys
33
import uuid
44
import warnings
5-
from ftplib import FTP, Error, error_perm
5+
from ftplib import FTP, FTP_TLS, Error, error_perm
66
from typing import Any
77

88
from ..spec import AbstractBufferedFile, AbstractFileSystem
@@ -27,6 +27,7 @@ def __init__(
2727
tempdir=None,
2828
timeout=30,
2929
encoding="utf-8",
30+
tls=False,
3031
**kwargs,
3132
):
3233
"""
@@ -56,28 +57,38 @@ def __init__(
5657
Timeout of the ftp connection in seconds
5758
encoding: str
5859
Encoding to use for directories and filenames in FTP connection
60+
tls: bool
61+
Use FTP-TLS, by default False
5962
"""
6063
super().__init__(**kwargs)
6164
self.host = host
6265
self.port = port
6366
self.tempdir = tempdir or "/tmp"
64-
self.cred = username, password, acct
67+
self.cred = username or "", password or "", acct or ""
68+
print(self.cred)
6569
self.timeout = timeout
6670
self.encoding = encoding
6771
if block_size is not None:
6872
self.blocksize = block_size
6973
else:
7074
self.blocksize = 2**16
75+
self.tls = tls
7176
self._connect()
77+
if self.tls:
78+
self.ftp.prot_p()
7279

7380
def _connect(self):
81+
if self.tls:
82+
ftp_cls = FTP_TLS
83+
else:
84+
ftp_cls = FTP
7485
if sys.version_info >= (3, 9):
75-
self.ftp = FTP(timeout=self.timeout, encoding=self.encoding)
86+
self.ftp = ftp_cls(timeout=self.timeout, encoding=self.encoding)
7687
elif self.encoding:
7788
warnings.warn("`encoding` not supported for python<3.9, ignoring")
78-
self.ftp = FTP(timeout=self.timeout)
89+
self.ftp = ftp_cls(timeout=self.timeout)
7990
else:
80-
self.ftp = FTP(timeout=self.timeout)
91+
self.ftp = ftp_cls(timeout=self.timeout)
8192
self.ftp.connect(self.host, self.port)
8293
self.ftp.login(*self.cred)
8394

fsspec/implementations/reference.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -997,9 +997,11 @@ def _process_gen(self, gens):
997997
out = {}
998998
for gen in gens:
999999
dimension = {
1000-
k: v
1001-
if isinstance(v, list)
1002-
else range(v.get("start", 0), v["stop"], v.get("step", 1))
1000+
k: (
1001+
v
1002+
if isinstance(v, list)
1003+
else range(v.get("start", 0), v["stop"], v.get("step", 1))
1004+
)
10031005
for k, v in gen["dimensions"].items()
10041006
}
10051007
products = (
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import os
2+
3+
from pyftpdlib.authorizers import DummyAuthorizer
4+
from pyftpdlib.handlers import TLS_FTPHandler
5+
from pyftpdlib.servers import FTPServer
6+
7+
8+
def ftp():
9+
"""Script to run FTP server that accepts TLS"""
10+
# Set up FTP server parameters
11+
FTP_HOST = "localhost"
12+
FTP_PORT = 2121
13+
FTP_DIRECTORY = os.path.dirname(os.path.abspath(__file__))
14+
15+
# Instantiate a dummy authorizer
16+
authorizer = DummyAuthorizer()
17+
authorizer.add_user(
18+
"user",
19+
"pass",
20+
FTP_DIRECTORY,
21+
"elradfmwMT",
22+
)
23+
authorizer.add_anonymous(FTP_DIRECTORY)
24+
25+
# Instantiate TLS_FTPHandler with required parameters
26+
handler = TLS_FTPHandler
27+
handler.certfile = os.path.join(os.path.dirname(__file__), "keycert.pem")
28+
handler.authorizer = authorizer
29+
30+
# Instantiate FTP server with TLS handler and authorizer
31+
server = FTPServer((FTP_HOST, FTP_PORT), handler)
32+
server.authorizer = authorizer
33+
34+
server.serve_forever()
35+
36+
37+
if __name__ == "__main__":
38+
ftp()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-----BEGIN EC PARAMETERS-----
2+
BggqhkjOPQMBBw==
3+
-----END EC PARAMETERS-----
4+
-----BEGIN EC PRIVATE KEY-----
5+
MHcCAQEEIBTg1e61mzYYPJ+MDkOWCSevnT1HUaaK9iopgTGyDoIuoAoGCCqGSM49
6+
AwEHoUQDQgAEDy3E+4WgohcRUlaSZBndEZQBTyoRztCSoaDbhZkqsPFBbeaGJ5zA
7+
E7qX+9LICDezAUsCiq2RYltOqDCsELteiQ==
8+
-----END EC PRIVATE KEY-----
9+
-----BEGIN CERTIFICATE-----
10+
MIICdzCCAh2gAwIBAgIUNN4kmTSxbLOoQXLFiYOs2XeK1jIwCgYIKoZIzj0EAwIw
11+
gY8xCzAJBgNVBAYTAk5MMRUwEwYDVQQIDAxadWlkLUhvbGxhbmQxDjAMBgNVBAcM
12+
BURlbGZ0MRAwDgYDVQQKDAdXaGlmZmxlMQ0wCwYDVQQLDARERVZBMRIwEAYDVQQD
13+
DAlCYXJ0dmFuRXMxJDAiBgkqhkiG9w0BCQEWFWJhcnQudmFuZXNAd2hpZmZsZS5u
14+
bDAgFw0yNDA0MTgxMDI0NDFaGA8yMjk4MDIwMTEwMjQ0MVowgY8xCzAJBgNVBAYT
15+
Ak5MMRUwEwYDVQQIDAxadWlkLUhvbGxhbmQxDjAMBgNVBAcMBURlbGZ0MRAwDgYD
16+
VQQKDAdXaGlmZmxlMQ0wCwYDVQQLDARERVZBMRIwEAYDVQQDDAlCYXJ0dmFuRXMx
17+
JDAiBgkqhkiG9w0BCQEWFWJhcnQudmFuZXNAd2hpZmZsZS5ubDBZMBMGByqGSM49
18+
AgEGCCqGSM49AwEHA0IABA8txPuFoKIXEVJWkmQZ3RGUAU8qEc7QkqGg24WZKrDx
19+
QW3mhiecwBO6l/vSyAg3swFLAoqtkWJbTqgwrBC7XomjUzBRMB0GA1UdDgQWBBRb
20+
1nPqritk/P2cbDzTw9SQ9vO7JDAfBgNVHSMEGDAWgBRb1nPqritk/P2cbDzTw9SQ
21+
9vO7JDAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIBcvCFS4AD3p
22+
Ix1v8pp3hcMvGFIQLeczh4kXkPfZWvBkAiEAiTCqsdKhZi8k814H6FFkaoQVIjTe
23+
iUtUlW6RfyDNZ9E=
24+
-----END CERTIFICATE-----

fsspec/implementations/tests/test_ftp.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import subprocess
33
import sys
44
import time
5+
from ftplib import FTP, FTP_TLS
56

67
import pytest
78

@@ -17,7 +18,7 @@
1718
def ftp():
1819
pytest.importorskip("pyftpdlib")
1920
P = subprocess.Popen(
20-
[sys.executable, "-m", "pyftpdlib", "-d", here],
21+
[sys.executable, os.path.join(here, "ftp_tls.py")],
2122
stderr=subprocess.STDOUT,
2223
stdout=subprocess.PIPE,
2324
)
@@ -29,9 +30,31 @@ def ftp():
2930
P.wait()
3031

3132

32-
def test_basic(ftp):
33+
@pytest.mark.parametrize(
34+
"tls,exp_cls",
35+
(
36+
(False, FTP),
37+
(True, FTP_TLS),
38+
),
39+
)
40+
def test_tls(ftp, tls, exp_cls):
3341
host, port = ftp
34-
fs = FTPFileSystem(host, port)
42+
fs = FTPFileSystem(host, port, tls=tls)
43+
assert isinstance(fs.ftp, exp_cls)
44+
45+
46+
@pytest.mark.parametrize(
47+
"tls,username,password",
48+
(
49+
(False, "", ""),
50+
(True, "", ""),
51+
(False, "user", "pass"),
52+
(True, "user", "pass"),
53+
),
54+
)
55+
def test_basic(ftp, tls, username, password):
56+
host, port = ftp
57+
fs = FTPFileSystem(host, port, username, password, tls=tls)
3558
assert fs.ls("/", detail=False) == sorted(os.listdir(here))
3659
out = fs.cat(f"/{os.path.basename(__file__)}")
3760
assert out == open(__file__, "rb").read()

0 commit comments

Comments
 (0)