Uploaded image for project: 'FtpServer'
  1. FtpServer
  2. FTPSERVER-277

Ftplet which forces TLS/SSL for control and data channels when using explicit FTPS

    XMLWordPrintableJSON

Details

    • New Feature
    • Status: Open
    • Minor
    • Resolution: Unresolved
    • None
    • 1.1.5
    • Ftplets
    • None

    Description

      I've developed a simple Ftplet which forces the client to use secure control and data channels when the server has been configured for explicit FTPS. The code has been pasted below. Let me know what you think about it. I've tried it with curl and it seems to work as expected both for passive and active data channels. Feel free to include it in Ftpserver if you find it useful.

      import java.io.IOException;
      import java.util.HashSet;
      import java.util.Set;

      import org.apache.ftpserver.ftplet.DefaultFtpReply;
      import org.apache.ftpserver.ftplet.FtpException;
      import org.apache.ftpserver.ftplet.FtpReply;
      import org.apache.ftpserver.ftplet.FtpRequest;
      import org.apache.ftpserver.ftplet.FtpSession;
      import org.apache.ftpserver.ftplet.Ftplet;
      import org.apache.ftpserver.ftplet.FtpletContext;
      import org.apache.ftpserver.ftplet.FtpletResult;

      /**

      • {@link Ftplet} which forces the client to use secure control and data
        * channels when connecting in explicit FTPS mode. In implicit FTPS the control
        * channel is always secure, however, the data channel can be plain text. This
        * {@link Ftplet}

        will not allow clients to open insecure data channels in

      • implicit FTPS mode.
        *
      • @version $Id$
        */
        public class ExplicitSslForcingFtplet implements Ftplet {
        private static final String SECURE = ExplicitSslForcingFtplet.class.getName() + ".secure";
        private static final Set<String> DATA_CHANNEL_COMMANDS;

      static

      { DATA_CHANNEL_COMMANDS = new HashSet<String>(); DATA_CHANNEL_COMMANDS.add("APPE"); DATA_CHANNEL_COMMANDS.add("LIST"); DATA_CHANNEL_COMMANDS.add("MLSD"); DATA_CHANNEL_COMMANDS.add("NLST"); DATA_CHANNEL_COMMANDS.add("RETR"); DATA_CHANNEL_COMMANDS.add("STOR"); DATA_CHANNEL_COMMANDS.add("STOU"); }

      public FtpletResult afterCommand(FtpSession session, FtpRequest request,
      FtpReply reply) throws FtpException, IOException {

      String cmd = request.getCommand().toUpperCase();
      int code = reply.getCode();
      if ("AUTH".equals(cmd) && code >= 200 && code < 300)

      { session.setAttribute(SECURE, true); }

      return FtpletResult.DEFAULT;
      }

      public FtpletResult beforeCommand(FtpSession session, FtpRequest request)
      throws FtpException, IOException {

      String cmd = request.getCommand().toUpperCase();
      boolean secure = (Boolean) session.getAttribute(SECURE);
      if ("USER".equals(cmd)) {
      if (!secure)

      { session.write(new DefaultFtpReply(500, "Control channel not secure. Issue AUTH command first.")); return FtpletResult.SKIP; }

      } else if (DATA_CHANNEL_COMMANDS.contains(cmd)) {
      if (!session.getDataConnection().isSecure())

      { session.write(new DefaultFtpReply(500, "Data channel not secure. Issue PROT command first.")); return FtpletResult.SKIP; }

      }

      return FtpletResult.DEFAULT;
      }

      public void destroy() {
      }

      public void init(FtpletContext ftpletContext) throws FtpException {
      }

      public FtpletResult onConnect(FtpSession session) throws FtpException,
      IOException

      { session.setAttribute(SECURE, session.isSecure()); return FtpletResult.DEFAULT; }

      public FtpletResult onDisconnect(FtpSession session) throws FtpException,
      IOException

      { return FtpletResult.DEFAULT; }

      }

      Attachments

        Activity

          People

            niklas Niklas Therning
            niklas@trillian.se Niklas Therning
            Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated: