Skip to content

Add support for explicit FTPS to server - #214

Open
Cycloctane wants to merge 14 commits into
aio-libs:masterfrom
Cycloctane:server_explicit_ftps
Open

Cycloctane wants to merge 14 commits into
aio-libs:masterfrom
Cycloctane:server_explicit_ftps

Conversation

@Cycloctane

@Cycloctane Cycloctane commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

What do these changes do?

  • Make aioftp server support explicit FTPS mode ("AUTH TLS", FTPES).
  • Add support for FEAT command.
  • Make PBSZ and PROT only available after setting up tls connection.
  • Add FTPS arguments to aioftp command (python3 -m aioftp).

Are there changes in behavior for the user?

Users can use aioftp.Server(ssl=ssl_context, ssl_explicit=True) to set up an explicit FTPS server.

Related issue number

Resolves #37

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes

@codecov

codecov Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.25%. Comparing base (4c18bde) to head (7c71e63).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #214      +/-   ##
==========================================
+ Coverage   97.95%   98.25%   +0.30%     
==========================================
  Files           6        6              
  Lines        2098     2123      +25     
==========================================
+ Hits         2055     2086      +31     
+ Misses         43       37       -6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Cycloctane
Cycloctane marked this pull request as ready for review September 27, 2026 12:56
@greptile-apps

greptile-apps Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 3/5

[Critical risk] Adds TLS/FTPS support to the FTP server implementation.

Not safe to merge until explicit FTPS requires TLS before accepting credentials. The remaining configuration and reply-ordering concerns are non-blocking.

Reviews (3) · Last reviewed commit: "add more tests for coverage"

Comment thread src/aioftp/server.py
host,
port,
ssl=self.ssl,
ssl=self.ssl if not self.ssl_explicit else None, # implicit ftps

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Explicit FTPS allows plaintext

With explicit FTPS enabled, a client can skip AUTH TLS and still send USER and PASS and upload or download files. The server accepts those operations over plaintext control and data connections, exposing credentials and file contents on the wire. Require the intended TLS protection before accepting them; this must be fixed before merging.

How this was verified: A connection that never sent AUTH TLS logged in and transferred a file with neither connection using TLS.

Artifacts

Local FTP request reproduction script

  • The authored Python source runs the same credential, upload, and download sequence in both configurations; it shows exactly how the transport checks were performed.

Implicit-TLS FTP request and response capture

  • A TLS-configured implicit-mode server accepted login and file transfers without AUTH TLS, with TLS present on both connections.

Explicit-FTPS plaintext request and response capture

  • A TLS-configured explicit-mode server accepted the same login and file transfers without AUTH TLS, with plaintext on both connections.

View artifacts

T-Rex Ran code and verified through T-Rex

Comment thread src/aioftp/server.py Outdated
Comment thread src/aioftp/server.py Outdated
Comment thread src/aioftp/__main__.py

ssl_context: ssl.SSLContext | None = None
if args.ftps != "off":
if not all((args.keyfile, args.certfile)):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Allow combined PEM files

The CLI rejects --certfile without --keyfile even when that PEM contains both the certificate and private key. SSLContext.load_cert_chain can load the file without a separate keyfile, so this guard unnecessarily prevents a valid FTPS configuration from starting. This is a non-blocking configuration limitation.

Suggested change
if not all((args.keyfile, args.certfile)):
if not args.certfile:

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Artifacts

Full executed combined-PEM reproduction source

  • Captured the complete Python source with the cat command, working directory, and exit code; this is the script used for both runs.

Explicit FTPS without a separate keyfile

  • Ran the CLI with only a combined-PEM certfile after Python loaded that PEM successfully; the CLI rejected it before starting a listener.

Explicit FTPS with the combined PEM also supplied as keyfile

  • Ran the same CLI with the PEM supplied as both arguments and completed AUTH TLS and a TLS-protected QUIT; the certificate and key work.

View artifacts

T-Rex Ran code and verified through T-Rex

@greptile-apps

This comment has been minimized.

- fix AUTH TLS typo
- send response directly for auth tls instead of queue
Comment thread src/aioftp/server.py
connection.response("504", f"AUTH {rest!r} not implemented")
else:
connection.ssl_enabled = True
await self.write_response(connection.command_connection, "234", "ready for TLS")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Keep TLS replies ordered

If a client sends FEAT and AUTH TLS before reading their replies and the queued FEAT response is delayed, this direct 234 write arrives first. The earlier 211 response can then arrive only after TLS negotiation begins, making the upgrade sequence difficult for the client to handle. This is a non-blocking interoperability concern; finish earlier queued replies before sending 234.

Artifacts

Loopback FTP reproduction script

  • The executed script sends pipelined commands to a real loopback server and optionally holds the FEAT writer to expose response ordering.

Prior implementation with FEAT held

  • The executed prior-implementation run received no reply while FEAT was held, then received plaintext 211 before 234.

Current implementation with held and ordinary FEAT responses

  • The executed current-code runs show 234 overtaking held FEAT, while the ordinary path returns plaintext 211 before 234.

View artifacts

T-Rex Ran code and verified through T-Rex

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Secure FTP

1 participant