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

                 Key: FTPSERVER-277
                 URL: https://issues.apache.org/jira/browse/FTPSERVER-277
             Project: FtpServer
          Issue Type: New Feature
            Reporter: Niklas Therning
            Priority: Minor


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;
    }

}

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to