Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for implicit FTPS on port 990 #1122

Merged
merged 1 commit into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading