com.adaptris.core.ftp.SftpKeyAuthConnection.java Source code

Java tutorial

Introduction

Here is the source code for com.adaptris.core.ftp.SftpKeyAuthConnection.java

Source

/*
 * Copyright 2015 Adaptris Ltd.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

package com.adaptris.core.ftp;

import java.io.File;
import java.io.IOException;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import org.apache.commons.io.FileUtils;

import com.adaptris.annotation.AdapterComponent;
import com.adaptris.annotation.AdvancedConfig;
import com.adaptris.annotation.AutoPopulated;
import com.adaptris.annotation.ComponentProfile;
import com.adaptris.annotation.DisplayOrder;
import com.adaptris.filetransfer.FileTransferClient;
import com.adaptris.filetransfer.FileTransferException;
import com.adaptris.security.exc.PasswordException;
import com.adaptris.security.password.Password;
import com.adaptris.sftp.DefaultSftpBehaviour;
import com.adaptris.sftp.SftpClient;
import com.adaptris.sftp.SftpConnectionBehaviour;
import com.adaptris.sftp.SftpException;
import com.thoughtworks.xstream.annotations.XStreamAlias;

/**
 * SFTP Connection class using public/private key authentication
 * <p>
 * This connection implementation allows you to use a public / private key pair to authenticate against the sftp server. It deviates
 * from a standard {@link SftpConnection}. Rather than specifying a default password for accessing the server, you specify a
 * {@link #setPrivateKeyFilename(String)} and {@link #setPrivateKeyPassword(String)} which contains your private key credentials
 * which are then supplied to the server.
 * </p>
 * <p>
 * It has the following behavioural changes from a standard SftpConnection :
 * <ul>
 * <li>If the private key is not accepted by the target server, then an exception will be thrown.</li>
 * <li>If no private key password is specified then it is assumed to be a 0 length string.</li>
 * <li>Only a single privatekey file will be supported per SftpKeyAuthConnection instance.</li>
 * <li>Specifying the username+password in the destination (e.g. <code>sftp://lchan:myPassword@1.2.3.4:22//opt/sftp</code>), will
 * override the username used to login but no other credentials. The only valid authentication is via the specified private
 * key.</li>
 * <li>You can specify additional behaviour using one of {@link DefaultSftpBehaviour}, {@link com.adaptris.sftp.LenientKnownHosts}
 * or {@link com.adaptris.sftp.StrictKnownHosts}. {@link com.adaptris.sftp.StrictKnownHosts} will cause an exception to be thrown
 * if the servers key is not present in any configured known_hosts file.</li>
 * <li>The private key and known_hosts file are expected to be in OpenSSH format</li>
 * </ul>
 * </p>
 * <p>
 * The password associated with {@link #setPrivateKeyPassword(String)} may be encoded using any of the standard {@link
 * com.adaptris.security.password.Password}
 * mechanisms and it will be decoded when the private key is first accessed.
 * </p>
 * 
 * @config sftp-key-auth-connection
 * 
 * @author dsefton
 */
@XStreamAlias("sftp-key-auth-connection")
@AdapterComponent
@ComponentProfile(summary = "Connect to a server using the SSH File Transfer Protocol; authentication via keys", tag = "connections,sftp")
@DisplayOrder(order = { "defaultUserName", "privateKeyFilename", "privateKeyPassword", "defaultControlPort" })
public class SftpKeyAuthConnection extends FileTransferConnection {

    private static final String SCHEME_SFTP = "sftp";

    static final int DEFAULT_CONTROL_PORT = 22;
    private static final int DEFAULT_TIMEOUT = 60000;

    private String privateKeyFilename;
    private String privateKeyPassword;
    @AdvancedConfig
    private Integer socketTimeout;
    @Valid
    @NotNull
    @AutoPopulated
    @AdvancedConfig
    private SftpConnectionBehaviour sftpConnectionBehaviour;
    // For sending keep alives every 60 seconds on the control port when downloading stuff.
    // Could make it configurable
    private transient long keepAlive = 60;

    public SftpKeyAuthConnection() {
        super();
        setSftpConnectionBehaviour(new DefaultSftpBehaviour());
    }

    @Override
    protected boolean acceptProtocol(String s) {
        return SCHEME_SFTP.equalsIgnoreCase(s);
    }

    @Override
    protected FileTransferClient create(String remoteHost, int port, UserInfo ui)
            throws IOException, FileTransferException {
        log.debug("Connecting to " + remoteHost + ":" + port + " as user " + ui.getUser());
        SftpClient sftp = new SftpClient(remoteHost, port, socketTimeout(), getSftpConnectionBehaviour());
        sftp.setAdditionalDebug(additionalDebug());
        sftp.setKeepAliveTimeout(keepAlive);
        try {
            byte[] privateKey = FileUtils.readFileToByteArray(new File(getPrivateKeyFilename()));
            sftp.connect(ui.getUser(), privateKey, Password.decode(getPrivateKeyPassword()).getBytes());
        } catch (PasswordException e) {
            throw new SftpException(e);
        }
        return sftp;
    }

    public Integer getSocketTimeout() {
        return socketTimeout;
    }

    /**
     * The socket timeout in milliseconds for connect / read /write operations.
     * 
     * @param t The socketTimeout to set, default is 60000
     */
    public void setSocketTimeout(Integer t) {
        socketTimeout = t;
    }

    int socketTimeout() {
        return getSocketTimeout() != null ? getSocketTimeout().intValue() : DEFAULT_TIMEOUT;
    }

    public String getPrivateKeyFilename() {
        return privateKeyFilename;
    }

    /**
     * The name of the file where the private key is held
     *
     * @param privateKeyFilename name of file holding the private key
     */
    public void setPrivateKeyFilename(String privateKeyFilename) {
        this.privateKeyFilename = privateKeyFilename;
    }

    /**
     * The password for the private key (if it has one)
     *
     * @return private key password
     */
    public String getPrivateKeyPassword() {
        return privateKeyPassword;
    }

    /**
     * The password for the private key (if it has one)
     *
     * @param privateKeyPassword
     */
    public void setPrivateKeyPassword(String privateKeyPassword) {
        this.privateKeyPassword = privateKeyPassword;
    }

    @Override
    protected UserInfo createUserInfo() throws FileTransferException {
        return new UserInfo(getDefaultUserName());
    }

    public SftpConnectionBehaviour getSftpConnectionBehaviour() {
        return sftpConnectionBehaviour;
    }

    public void setSftpConnectionBehaviour(SftpConnectionBehaviour k) {
        if (k == null) {
            throw new IllegalArgumentException("known_hosts handler may not be null");
        }
        sftpConnectionBehaviour = k;
    }

    @Override
    public int defaultControlPort() {
        return getDefaultControlPort() != null ? getDefaultControlPort().intValue() : DEFAULT_CONTROL_PORT;
    }
}