17

I have an FTP server which only accepts connections through running FTPS (explicit FTP over TLS). I need to be able to connect to this using a Ruby on Rails app.

Does anybody know of a method to do this? I have tried the Net::FTP library but this does not appear to support FTPS connections.

adamjford
  • 7,478
  • 6
  • 29
  • 41
Craig Wanstall
  • 295
  • 3
  • 8

7 Answers7

8

How about using Net::FTPTLS ?

PetrosB
  • 4,134
  • 5
  • 22
  • 21
  • Where is this found? How can I install it? I couldn't figure it out by searching for it on Google. – adamjford May 04 '11 at 14:50
  • 1
    @adamjford, It should come with your Ruby. On my box, it's in `/usr/lib/ruby/1.8/net/ftptls.rb`. On yours, it may be somewhere else. Wherever it is, `require 'net/ftptls'` ought to work. – Wayne Conrad May 16 '11 at 22:26
  • 4
    Wondering where it went in ruby 1.9 – mat May 19 '11 at 20:10
  • @mat : Have you tried the ftpfxp gem? It has a FTPFXPTLS class that wraps TLS over the standard Net::FTP class. – jason.rickman Jun 14 '11 at 13:43
  • I actually made a small one which works for 1.9, but only in passive mode (only needed passive) : https://gist.github.com/1039994 – mat Jun 22 '11 at 12:42
5

Since Ruby 2.4, TLS over FTP has been available with Net::FTP... this has caused gems like double-bag-ftps to become archived and all your google searches to yield outdated answers.

If you can do explicit FTP over TLS (Connects to FTP normally, then issues a command AUTH TLS to switch to TLS Mode), then great... that should be able to use Ruby's Net::FTP out of the box by just passing {ssl: true} in the options.

Implicit FTP over TLS (runs over TLS from the get-go) does not work out of the box, however, and you must override Net::FTP's connection method to establish an SSL socket and then optionally send commands to the FTP server.

Inidka K posted a Github Gist, but since those are bad form (can go stale), I've posted my version that works against a ShareFile Implicit FTP setup (which seems to only support Implicit FTP):

require 'net/ftp'

class ImplicitFtp < Net::FTP
  FTP_PORT = 990

  def connect(host, port = FTP_PORT)
    synchronize do
      @host = host
      @bare_sock = open_socket(host, port)
      begin
        ssl_sock = start_tls_session(Socket.tcp(host, port))
        @sock = BufferedSSLSocket.new(ssl_sock, read_timeout: @read_timeout)
        voidresp
        if @private_data_connection
          voidcmd("PBSZ 0")
          voidcmd("PROT P")
        end
      rescue OpenSSL::SSL::SSLError, Net::OpenTimeout
        @sock.close
        raise
      end
    end
  end
end

Then, in your code:

ftp_options = {
  port:    990,
  ssl:      true,
  debug_mode: true, # If you want to see what's going on
  username: FTP_USER,
  password: FTP_PASS
}
ftp = ImplicitFtp.open(FTP_HOST, ftp_options)
puts ftp.list
ftp.close
Brett Green
  • 3,535
  • 1
  • 22
  • 29
4

I done something like this with Implicit/Explicit FTPS, I used double-bag-ftps gem that I patched to support reuse of ssl session. It's a requirement for a lot of ftps servers.

I put the code on github here : https://github.com/alain75007/double-bag-ftps

Alain Beauvois
  • 5,896
  • 3
  • 44
  • 26
2

EDIT: I figured out how to get it running locally, but am having issues getting it to work on Heroku. That's a bit of a departure from this question, so I've created a new one:

Heroku with FTPTLS - Error on SSL Connection

require 'net/ftptls'
ftp = Net::FTPTLS.new()
ftp.passive = true
#make sure you define port_number
ftp.connect('host.com', port_number)
ftp.login('Username', 'Password')
ftp.gettextfile('filename.ext', 'where/to/save/file.ext')
ftp.close
Community
  • 1
  • 1
Colin
  • 2,814
  • 5
  • 27
  • 37
2

If you want to use Implicit FTPS, please try this gist.

For Explicit FTPs, you can use the ruby gem ftpfxp.

Marshall Anschutz
  • 1,200
  • 1
  • 12
  • 23
Indika K
  • 1,332
  • 17
  • 27
  • Running `gem install ftpfxp` produces `ERROR: While executing gem ... (Gem::FormatException) ftpfxp-0.0.4 has an invalid value for @cert_chain` – adamjford May 04 '11 at 14:51
2

Support for implicit FTPS was merged into ruby/net-ftp in January 2022 (in this PR). If you want to make use of this straight away, you can include the latest version directly in your Gemfile:

gem "net-ftp", github: "ruby/net-ftp", branch: "master"

Then you just need:

options = {
  ssl: true,
  port: 990,
  implicit_ftps: true,
  username: "your-user",
  password: "*********",
  debug_mode: true
}

Net::FTP.open("yourhost.com", options) do |ftp|
  ftp.list.map{ |f| puts f }
end
Dan
  • 778
  • 11
  • 18
0

I implemented an ftps solution using double-bag-ftps

double-bag-ftps

duinness
  • 46
  • 2