Skip to content

Commit

Permalink
Merge pull request #1122 from MetPX/issue1121_ftp_990
Browse files Browse the repository at this point in the history
Implement support for implicit FTPS on port 990
  • Loading branch information
reidsunderland committed Jun 26, 2024
2 parents 6b24f67 + 9cde524 commit 6b49df1
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 2 deletions.
2 changes: 2 additions & 0 deletions docs/source/Reference/sr3_credentials.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ passwords and settings needed by components. The format is one entry per line.

- **ftps://user7:De%3Aize@host passive,binary,tls**
- **ftps://user8:%2fdot8@host:2121 active,ascii,tls,prot_p**
- **ftp://user8:%2fdot8@host:990 implicit_ftps**
- **https://ladsweb.modaps.eosdis.nasa.gov/ bearer_token=89APCBF0-FEBE-11EA-A705-B0QR41911BF4**


Expand All @@ -71,6 +72,7 @@ Supported details:
- ``prot_p`` - (FTPS) Use a secure data connection for TLS connections (otherwise, clear text is used)
- ``bearer_token=<token>`` (or ``bt=<token>``) - (HTTP) Bearer token for authentication
- ``login_method=<PLAIN|AMQPLAIN|EXTERNAL|GSSAPI>`` - (AMQP) By default, the login method will be automatically determined. This can be overriden by explicity specifying a login method, which may be required if a broker supports multiple methods and an incorrect one is automatically selected.
- ``implicit_ftps`` - (FTPS) Use implicit FTPS (otherwise, explicit FTPS is used). Setting this will also set ``tls`` to True.

Note::
SFTP credentials are optional, in that sarracenia will look in the .ssh directory
Expand Down
2 changes: 2 additions & 0 deletions docs/source/fr/Reference/sr3_credentials.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ ainsi que les paramètres nécessaires aux composants. Le format est d'une entr

- **ftps://user7:De%3Aize@host passive,binary,tls**
- **ftps://user8:%2fdot8@host:2121 active,ascii,tls,prot_p**
- **ftp://user8:%2fdot8@host:990 implicit_ftps**
- **https://ladsweb.modaps.eosdis.nasa.gov/ bearer_token=89APCBF0-FEBE-11EA-A705-B0QR41911BF4**

Dans d’autres fichiers de configuration ou sur la ligne de commande, l’url n’a tout simplement pas le
Expand All @@ -71,6 +72,7 @@ Détails pris en charge :
- ``prot_p`` - (FTPS) Utiliser une connexion de données sécurisée pour les connexions TLS (sinon, du texte clair est utilisé)
- ``bearer_token=<token>`` (ou ``bt=<token>``) - (HTTP) Jeton Bearer pour l’authentification
- ``login_method=<PLAIN|AMQPLAIN|EXTERNAL|GSSAPI>`` - (AMQP) Par défaut, la méthode de connexion sera automatiquement
- ``implicit_ftps`` - (FTPS) Utilisez FTPS implicite (sinon, FTPS explicite est utilisé). Définir ceci définira également ``tls`` sur True.

déterminée. Cela peut être remplacé en spécifiant une méthode Particulière de connexion, ce qui peut être
nécessaire si un broker prend en charge plusieurs méthodes et qu’une méthode incorrecte est automatiquement
Expand Down
6 changes: 6 additions & 0 deletions sarracenia/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class Credential:
bearer_token (str): bearer token for HTTP authentication
login_method (str): force a specific login method for AMQP (PLAIN,
AMQPLAIN, EXTERNAL or GSSAPI)
implicit_ftps (bool): use implicit FTPS, defaults to ``False`` (i.e. explicit FTPS)
Usage:
Expand Down Expand Up @@ -101,6 +102,7 @@ def __init__(self, urlstr=None):
self.s3_endpoint = None
self.s3_session_token = None
self.azure_credentials = None
self.implicit_ftps = False

def __str__(self):
"""Returns attributes of the Credential object as a readable string.
Expand Down Expand Up @@ -133,6 +135,7 @@ def __str__(self):
#want to show they provided a session token, but not leak it (like passwords above)
s += " %s" % 'Yes' if self.s3_session_token != None else 'No'
s += " %s" % 'Yes' if self.azure_credentials != None else 'No'
s += " %s" % self.implicit_ftps

return s

Expand Down Expand Up @@ -383,6 +386,9 @@ def _parse(self, line):
details.s3_endpoint = parts[1].strip()
elif keyword == 'azure_storage_credentials':
details.azure_credentials = urllib.parse.unquote(parts[1].strip())
elif keyword == 'implicit_ftps':
details.implicit_ftps = True
details.tls = True
else:
logger.warning("bad credential option (%s)" % keyword)

Expand Down
39 changes: 37 additions & 2 deletions sarracenia/transfer/ftp.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,34 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#

import ftplib, os, subprocess, sys, time
import ftplib, os, subprocess, sys, time, ssl
import logging
from sarracenia.transfer import Transfer
from sarracenia.transfer import alarm_cancel, alarm_set, alarm_raise
from urllib.parse import unquote

logger = logging.getLogger(__name__)

class IMPLICIT_FTP_TLS(ftplib.FTP_TLS):
""" FTP_TLS subclass that automatically wraps sockets in SSL to support implicit FTPS.
Copied from https://stackoverflow.com/questions/12164470/python-ftp-implicit-tls-connection-issue
"""

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._sock = None

@property
def sock(self):
"""Return the socket."""
return self._sock

@sock.setter
def sock(self, value):
"""When modifying the socket, ensure that it is ssl wrapped."""
if value is not None and not isinstance(value, ssl.SSLSocket):
value = self.context.wrap_socket(value)
self._sock = value

class Ftp(Transfer):
"""
Expand Down Expand Up @@ -176,13 +196,27 @@ def connect(self):
try:
expire = -999
if self.o.timeout: expire = self.o.timeout
if self.port == '' or self.port == None: self.port = 21
if self.port == '' or self.port == None:
if self.implicit_ftps:
self.port = 990
else:
self.port = 21

# plain FTP with no encryption (usually port 21)
if not self.tls:
ftp = ftplib.FTP()
ftp.encoding = 'utf-8'
ftp.connect(self.host, self.port, timeout=expire)
ftp.login(self.user, unquote(self.password))
# implicit FTPS (usually port 990)
elif self.tls and self.implicit_ftps:
ftp = IMPLICIT_FTP_TLS()
ftp.encoding = 'utf-8'
ftp.connect(host=self.host, port=self.port, timeout=expire)
ftp.login(user=self.user, passwd=unquote(self.password))
if self.prot_p:
ftp.prot_p()
# explicit FTPS (port 21)
else:
# ftplib supports FTPS with TLS
ftp = ftplib.FTP_TLS(self.host,
Expand Down Expand Up @@ -233,6 +267,7 @@ def credentials(self):
self.binary = details.binary
self.tls = details.tls
self.prot_p = details.prot_p
self.implicit_ftps = details.implicit_ftps

return True

Expand Down

0 comments on commit 6b49df1

Please sign in to comment.