com.jamesashepherd.sshproxyj.Start.java Source code

Java tutorial

Introduction

Here is the source code for com.jamesashepherd.sshproxyj.Start.java

Source

/**
 * Copyright 2013 James A. Shepherd
 * http://www.JamesAshepherd.com/
 *
 * LICENCE: http://www.gnu.org/licenses/lgpl.html
 */
package com.jamesashepherd.sshproxyj;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.LinkedList;
import java.util.List;

import org.apache.sshd.ClientChannel;
import org.apache.sshd.ClientSession;
import org.apache.sshd.SshClient;
import org.apache.sshd.SshServer;
import org.apache.sshd.common.Factory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.codehaus.plexus.util.Base64;
import org.codehaus.plexus.util.IOUtil;

import com.jamesashepherd.start.StartException;
import com.jamesashepherd.start.Startable;

/**
 * @author James A. Shepherd
 * @since 1.0
 */
public class Start implements Startable {

    private SshServer sshd;

    private SshClient client;

    public void startup() throws StartException {

        clientSessions = new LinkedList<ClientSession>();

        // set up client
        client = SshClient.setUpDefaultClient();
        PublicKey publicKey = null;
        KeyPair kp = null;
        try {
            InputStream is = new FileInputStream(new File("/tmp/id_rsa.pub"));
            publicKey = decodePublicKey(IOUtil.toString(is));

            BufferedReader br = new BufferedReader(new FileReader("/tmp/id_rsa"));
            Security.addProvider(new BouncyCastleProvider());
            PEMReader pr = new PEMReader(br);
            kp = (KeyPair) pr.readObject();
            pr.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        final KeyPair keyPair = new KeyPair(publicKey, kp.getPrivate());

        client.start();

        // set up server
        sshd = SshServer.setUpDefaultServer();
        sshd.setPort(6667);
        sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("/tmp/host.key"));
        // sshd.setShellFactory(new ProcessShellFactory(new String[] {
        // "/bin/bash", "-i", "-l" }));
        sshd.setShellFactory(new Factory<Command>() {

            ExitCallback exitCallBack;

            public Command create() {
                try {
                    final ClientSession session = client.connect("localhost", 22).await().getSession();
                    clientSessions.add(session);
                    System.out.println("Started Client Session");
                    session.authPublicKey("jas", keyPair);

                    int ret = session.waitFor(ClientSession.CLOSED | ClientSession.AUTHED, 10 * 1000); // milliseconds
                    System.out.println("Waited for auth: " + ret);
                    if ((ret & ClientSession.CLOSED) != 0) {
                        System.err.println("error session closed");
                        System.exit(-1);
                    }

                    System.out.println("Still open");

                    final ClientChannel channel = session.createChannel("shell");
                    System.out.println("Returning Command");

                    return new Command() {

                        public void setInputStream(InputStream in) {
                            channel.setIn(in);
                        }

                        public void setOutputStream(OutputStream out) {
                            channel.setOut(out);
                        }

                        public void setErrorStream(OutputStream err) {
                            channel.setErr(err);
                        }

                        public void setExitCallback(ExitCallback callback) {
                            exitCallBack = callback;
                        }

                        public void start(Environment env) throws IOException {
                            try {
                                channel.open();
                                new Thread(new Runnable() {

                                    public void run() {
                                        channel.waitFor(ClientChannel.CLOSED, 0);
                                        exitCallBack.onExit(
                                                channel.getExitStatus() == null ? 1 : channel.getExitStatus());
                                        session.close(false);
                                    }

                                }).start();
                            } catch (Exception e) {
                                throw new IOException(e);
                            }
                        }

                        public void destroy() {
                            try {
                                session.close(true);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    };
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        });

        sshd.setPublickeyAuthenticator(new PublickeyAuthenticator() {

            public boolean authenticate(String username, PublicKey key, ServerSession session) {
                PublicKey publicKey;
                try {
                    InputStream is = new FileInputStream(new File("/tmp/id_rsa.pub"));
                    publicKey = decodePublicKey(IOUtil.toString(is));
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }

                return ((RSAPublicKey) publicKey).getModulus().equals(((RSAPublicKey) key).getModulus());
            }
        });

        try {
            sshd.start();
        } catch (IOException e) {
            throw new StartException("Failed to start SshServer", e);
        }
    }

    public void shutdown() throws StartException {
        try {
            for (ClientSession session : clientSessions) {
                session.close(false);
            }
            client.stop();
            sshd.stop();
        } catch (InterruptedException e) {
            throw new StartException("Failed to stop SshServer", e);
        }
    }

    private List<ClientSession> clientSessions;

    private byte[] bytes;

    private int pos;

    /**
     * http://maven.apache.org/wagon/xref/org/apache/maven/wagon/providers/ssh/TestPublickeyAuthenticator.html
     * @since 1.9.5
     * @param keyLine
     * @return
     * @throws Exception
     */
    public PublicKey decodePublicKey(String keyLine) throws Exception {
        bytes = null;
        pos = 0;

        for (String part : keyLine.split(" ")) {
            if (part.startsWith("AAAA")) {
                bytes = Base64.decodeBase64(part.getBytes());
                break;
            }
        }
        if (bytes == null) {
            throw new IllegalArgumentException("no Base64 part to decode");
        }

        String type = decodeType();
        if (type.equals("ssh-rsa")) {
            BigInteger e = decodeBigInt();
            BigInteger m = decodeBigInt();
            RSAPublicKeySpec spec = new RSAPublicKeySpec(m, e);
            return KeyFactory.getInstance("RSA").generatePublic(spec);
        } else if (type.equals("ssh-dss")) {
            BigInteger p = decodeBigInt();
            BigInteger q = decodeBigInt();
            BigInteger g = decodeBigInt();
            BigInteger y = decodeBigInt();
            DSAPublicKeySpec spec = new DSAPublicKeySpec(y, p, q, g);
            return KeyFactory.getInstance("DSA").generatePublic(spec);
        } else {
            throw new IllegalArgumentException("unknown type " + type);
        }
    }

    private String decodeType() {
        int len = decodeInt();
        String type = new String(bytes, pos, len);
        pos += len;
        return type;
    }

    private int decodeInt() {
        return ((bytes[pos++] & 0xFF) << 24) | ((bytes[pos++] & 0xFF) << 16) | ((bytes[pos++] & 0xFF) << 8)
                | (bytes[pos++] & 0xFF);
    }

    private BigInteger decodeBigInt() {
        int len = decodeInt();
        byte[] bigIntBytes = new byte[len];
        System.arraycopy(bytes, pos, bigIntBytes, 0, len);
        pos += len;
        return new BigInteger(bigIntBytes);
    }
}