geronimo-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jason Dillon <jason.dil...@gmail.com>
Subject Re: [Heads up] SSH server in java
Date Sat, 22 Nov 2008 11:57:19 GMT
Your limited is my "kick-ass amazing" :-P

--jason


On Nov 22, 2008, at 6:45 PM, Guillaume Nodet wrote:

> Yes, i've refactored things a bit in the sshd project to make room for
> the client side.
> It's really limited for now and only support user/password
> authentication and launching a shell.
> I've implemented a gshell action at [1] for the client:
>
> [1] https://svn.apache.org/repos/asf/servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/sshd/SshAction.java
>
> On Sat, Nov 22, 2008 at 7:03 AM, Jason Dillon  
> <jason.dillon@gmail.com> wrote:
>> Cool, I'm going to start a gshell-ssh module under gshell-commands  
>> for the
>> sshd and ssh commands, which will replace the gshell-remote bits :-)
>>
>> I noticed you got some client goo in there too... how is that  
>> working?
>>
>> --jason
>>
>>
>> On Nov 21, 2008, at 3:29 PM, Guillaume Nodet wrote:
>>
>>> Yes, I've checked that in yesterday or so:
>>>
>>> https://svn.apache.org/repos/asf/servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/java/org/apache/servicemix/kernel/gshell/core/sshd/
>>>
>>> https://svn.apache.org/repos/asf/servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-remote.xml
>>>
>>>
>>> On Fri, Nov 21, 2008 at 7:08 AM, Jason Dillon <jason.dillon@gmail.com 
>>> >
>>> wrote:
>>>>
>>>> Hey, do you have "org.apache.servicemix.kernel.gshell.core.sshd"  
>>>> checked
>>>> in
>>>> somewhere?
>>>>
>>>> --jason
>>>>
>>>>
>>>> On Nov 13, 2008, at 5:58 AM, Guillaume Nodet wrote:
>>>>
>>>>> I've just done a real quick prototype to plug into smx kernel  
>>>>> and I've
>>>>> been able to log in into smx kernel using an ssh client and  
>>>>> issue a
>>>>> few commands.
>>>>> Following is the class that does everything and the spring  
>>>>> config to
>>>>> start the ssh server.
>>>>> The BogusPasswordAuthenticator is a dummy class which I pasted  
>>>>> below
>>>>> too.
>>>>>
>>>>> Notice the use of stream filters to convert CR / CRLF stuff.  I  
>>>>> think
>>>>> this is because both sshd and the geronimo gshell do not handle  
>>>>> well
>>>>> the pty request and/or VT100 stuff.  But I'm still not sure  
>>>>> where the
>>>>> conversion should happen exactly.
>>>>>
>>>>> Also note that i've redefined the ConsoleErrorHandlerImpl,  
>>>>> because the
>>>>> default one uses the application.getIO() for displaying errors  
>>>>> so they
>>>>> are not available remotely.
>>>>>
>>>>> Let me know what you think, but it basically makes the whole  
>>>>> remote
>>>>> bits of gshell unused.
>>>>> I have not implemented the ssh command which should be easy  
>>>>> using jsch
>>>>> lib.
>>>>>
>>>>> Let me know if / how I can help you with that bits.
>>>>>
>>>>> ==================================================
>>>>> package org.apache.servicemix.kernel.gshell.core.sshd;
>>>>>
>>>>> import com.google.code.sshd.PasswordAuthenticator;
>>>>>
>>>>> public class BogusPasswordAuthenticator implements  
>>>>> PasswordAuthenticator
>>>>> {
>>>>>
>>>>> public Object authenticate(String username, String password) {
>>>>>    return (username != null && username.equals(password)) ?
>>>>> username : null;
>>>>> }
>>>>> }
>>>>>
>>>>>
>>>>> ==================================================
>>>>> <bean name="sshServer" class="com.google.code.sshd.SshServer"
>>>>> init-method="start" destroy-method="stop">
>>>>>    <property name="port" value="8000" />
>>>>>    <property name="shellFactory">
>>>>>        <bean
>>>>>
>>>>> class 
>>>>> = 
>>>>> "org 
>>>>> .apache.servicemix.kernel.gshell.core.sshd.GShellShellFactory">
>>>>>            <property name="branding" ref="branding" />
>>>>>            <property name="completers">
>>>>>                <list>
>>>>>                    <ref bean="commandsCompleter"/>
>>>>>                    <ref bean="aliasNameCompleter"/>
>>>>>                </list>
>>>>>            </property>
>>>>>            <property name="executor" ref="commandLineExecutor" />
>>>>>            <property name="history">
>>>>>                <bean
>>>>> class="org.apache.geronimo.gshell.wisdom.shell.HistoryImpl">
>>>>>                    <constructor-arg ref="application"/>
>>>>>                </bean>
>>>>>            </property>
>>>>>            <property name="prompter">
>>>>>                <bean
>>>>> class 
>>>>> ="org.apache.geronimo.gshell.wisdom.shell.ConsolePrompterImpl">
>>>>>                    <constructor-arg ref="application"/>
>>>>>                </bean>
>>>>>            </property>
>>>>>        </bean>
>>>>>    </property>
>>>>>    <property name="hostKeyProvider">
>>>>>        <bean  
>>>>> class="com.google.code.sshd.hostkeys.FileHostKeyProvider">
>>>>>            <constructor-arg>
>>>>>                <list>
>>>>>                    <value>${hostKey}</value>
>>>>>                </list>
>>>>>            </constructor-arg>
>>>>>        </bean>
>>>>>    </property>
>>>>>    <property name="passwordAuthenticator">
>>>>>        <!-- TODO: provide real authentication -->
>>>>>        <bean
>>>>>
>>>>>
>>>>> class 
>>>>> = 
>>>>> "org 
>>>>> .apache 
>>>>> .servicemix.kernel.gshell.core.sshd.BogusPasswordAuthenticator"
>>>>> />
>>>>>    </property>
>>>>>    <!-- Do not use public keys for now
>>>>>    <property name="publickeyAuthenticator">
>>>>>        <bean  
>>>>> class="com.google.code.sshd.BogusPublickeyAuthenticator"
>>>>> />
>>>>>    </property>
>>>>>    -->
>>>>>    <!-- Standard properties -->
>>>>>    <property name="channelFactories">
>>>>>        <list>
>>>>>            <bean
>>>>> class="com.google.code.sshd.channel.ChannelSession$Factory" />
>>>>>        </list>
>>>>>    </property>
>>>>>    <property name="cipherFactories">
>>>>>        <list>
>>>>>            <bean class="com.google.code.sshd.cipher.AES128CBC 
>>>>> $Factory"
>>>>> />
>>>>>            <bean
>>>>> class="com.google.code.sshd.cipher.TripleDESCBC$Factory" />
>>>>>            <bean
>>>>> class="com.google.code.sshd.cipher.BlowfishCBC$Factory" />
>>>>>            <bean class="com.google.code.sshd.cipher.AES192CBC 
>>>>> $Factory"
>>>>> />
>>>>>            <bean class="com.google.code.sshd.cipher.AES256CBC 
>>>>> $Factory"
>>>>> />
>>>>>        </list>
>>>>>    </property>
>>>>>    <property name="compressionFactories">
>>>>>        <list>
>>>>>            <bean
>>>>> class="com.google.code.sshd.compression.CompressionNone 
>>>>> $Factory" />
>>>>>        </list>
>>>>>    </property>
>>>>>    <property name="keyExchangeFactories">
>>>>>        <list>
>>>>>            <bean class="com.google.code.sshd.kex.DHG1$Factory" />
>>>>>        </list>
>>>>>    </property>
>>>>>    <property name="macFactories">
>>>>>        <list>
>>>>>            <bean  
>>>>> class="com.google.code.sshd.mac.HMACMD5$Factory" />
>>>>>            <bean  
>>>>> class="com.google.code.sshd.mac.HMACSHA1$Factory" />
>>>>>            <bean  
>>>>> class="com.google.code.sshd.mac.HMACMD596$Factory" />
>>>>>            <bean  
>>>>> class="com.google.code.sshd.mac.HMACSHA196$Factory" />
>>>>>        </list>
>>>>>    </property>
>>>>>    <property name="randomFactory">
>>>>>        <bean class="com.google.code.sshd.random.JceRandom 
>>>>> $Factory" />
>>>>>    </property>
>>>>>    <property name="userAuthFactories">
>>>>>        <list>
>>>>>            <bean
>>>>> class="com.google.code.sshd.auth.UserAuthPublicKey$Factory" />
>>>>>            <bean
>>>>> class="com.google.code.sshd.auth.UserAuthPassword$Factory" />
>>>>>        </list>
>>>>>    </property>
>>>>>    <property name="signatureFactories">
>>>>>        <list>
>>>>>            <bean
>>>>> class="com.google.code.sshd.signature.SignatureDSA$Factory" />
>>>>>            <bean
>>>>> class="com.google.code.sshd.signature.SignatureRSA$Factory" />
>>>>>        </list>
>>>>>    </property>
>>>>> </bean>
>>>>>
>>>>>
>>>>>
>>>>> ===================================================
>>>>> package org.apache.servicemix.kernel.gshell.core.sshd;
>>>>>
>>>>> import java.util.Map;
>>>>> import java.util.List;
>>>>> import java.io.OutputStream;
>>>>> import java.io.InputStream;
>>>>> import java.io.Closeable;
>>>>> import java.io.IOException;
>>>>>
>>>>> import com.google.code.sshd.ShellFactory;
>>>>> import com.google.code.sshd.shell.CrLfFilterInputStream;
>>>>> import org.apache.geronimo.gshell.shell.ShellContext;
>>>>> import org.apache.geronimo.gshell.io.IO;
>>>>> import org.apache.geronimo.gshell.command.Variables;
>>>>> import org.apache.geronimo.gshell.console.Console;
>>>>> import org.apache.geronimo.gshell.console.JLineConsole;
>>>>> import  
>>>>> org.apache.geronimo.gshell.console.completer.AggregateCompleter;
>>>>> import org.apache.geronimo.gshell.notification.ExitNotification;
>>>>> import org.apache.geronimo.gshell.notification.ErrorNotification;
>>>>> import org.apache.geronimo.gshell.application.model.Branding;
>>>>> import org.apache.geronimo.gshell.commandline.CommandLineExecutor;
>>>>> import org.apache.geronimo.gshell.ansi.AnsiRenderer;
>>>>> import org.slf4j.LoggerFactory;
>>>>> import org.slf4j.Logger;
>>>>> import jline.History;
>>>>> import jline.Completor;
>>>>>
>>>>> public class GShellShellFactory implements ShellFactory {
>>>>>
>>>>> private Logger logger = LoggerFactory.getLogger(getClass());
>>>>> private Branding branding;
>>>>> private Console.Prompter prompter;
>>>>> private CommandLineExecutor executor;
>>>>> private History history;
>>>>> private List<Completor> completers;
>>>>>
>>>>> public Branding getBranding() {
>>>>>    return branding;
>>>>> }
>>>>>
>>>>> public void setBranding(Branding branding) {
>>>>>    this.branding = branding;
>>>>> }
>>>>>
>>>>> public Console.Prompter getPrompter() {
>>>>>    return prompter;
>>>>> }
>>>>>
>>>>> public void setPrompter(Console.Prompter prompter) {
>>>>>    this.prompter = prompter;
>>>>> }
>>>>>
>>>>> public CommandLineExecutor getExecutor() {
>>>>>    return executor;
>>>>> }
>>>>>
>>>>> public void setExecutor(CommandLineExecutor executor) {
>>>>>    this.executor = executor;
>>>>> }
>>>>>
>>>>> public History getHistory() {
>>>>>    return history;
>>>>> }
>>>>>
>>>>> public void setHistory(History history) {
>>>>>    this.history = history;
>>>>> }
>>>>>
>>>>> public List<Completor> getCompleters() {
>>>>>    return completers;
>>>>> }
>>>>>
>>>>> public void setCompleters(List<Completor> completers) {
>>>>>    this.completers = completers;
>>>>> }
>>>>>
>>>>> public Shell createShell() {
>>>>>    return new ShellImpl();
>>>>> }
>>>>>
>>>>> public class ShellImpl implements ShellFactory.DirectShell,
>>>>> org.apache.geronimo.gshell.shell.Shell {
>>>>>
>>>>>    private InputStream in;
>>>>>    private OutputStream out;
>>>>>    private OutputStream err;
>>>>>    private IO io;
>>>>>    private Variables variables;
>>>>>    private ShellContext context;
>>>>>    private boolean closed;
>>>>>
>>>>>    public ShellImpl() {
>>>>>    }
>>>>>
>>>>>    public void setInputStream(InputStream in) {
>>>>>        this.in = in;
>>>>>    }
>>>>>
>>>>>    public void setOutputStream(OutputStream out) {
>>>>>        this.out = out;
>>>>>    }
>>>>>
>>>>>    public void setErrorStream(OutputStream err) {
>>>>>        this.err = err;
>>>>>    }
>>>>>
>>>>>    public void start(Map<String,String> env) throws Exception {
>>>>>        this.io = new IO(new CrLfFilterInputStream(in, "IN: ",  
>>>>> logger),
>>>>>                         new LfToCrLfFilterOutputStream(out,
>>>>> "OUT:", logger),
>>>>>                         new LfToCrLfFilterOutputStream(err,
>>>>> "ERR:", logger),
>>>>>                         false);
>>>>>        this.variables = new Variables((Map) env);
>>>>>        this.context = new ShellContext() {
>>>>>            public org.apache.geronimo.gshell.shell.Shell  
>>>>> getShell() {
>>>>>                return ShellImpl.this;
>>>>>            }
>>>>>            public IO getIo() {
>>>>>                return ShellImpl.this.io;
>>>>>            }
>>>>>            public Variables getVariables() {
>>>>>                return ShellImpl.this.variables;
>>>>>            }
>>>>>        };
>>>>>        new Thread() {
>>>>>            public void run() {
>>>>>                try {
>>>>>                    ShellImpl.this.run();
>>>>>                } catch (Exception e) {
>>>>>                    e.printStackTrace();
>>>>>                } finally {
>>>>>                    close();
>>>>>                }
>>>>>            }
>>>>>        }.start();
>>>>>    }
>>>>>
>>>>>    public boolean isAlive() {
>>>>>        return !closed;
>>>>>    }
>>>>>
>>>>>    public int exitValue() {
>>>>>        if (!closed) {
>>>>>            throw new IllegalThreadStateException();
>>>>>        }
>>>>>        return 0;
>>>>>    }
>>>>>
>>>>>    public void destroy() {
>>>>>        close();
>>>>>    }
>>>>>
>>>>>    public ShellContext getContext() {
>>>>>        return context;
>>>>>    }
>>>>>
>>>>>    public Object execute(String line) throws Exception {
>>>>>        return executor.execute(getContext(), line);
>>>>>    }
>>>>>
>>>>>    public Object execute(String command, Object[] args) throws
>>>>> Exception {
>>>>>        return executor.execute(getContext(), args);
>>>>>    }
>>>>>
>>>>>    public Object execute(Object... args) throws Exception {
>>>>>        return executor.execute(getContext(), args);
>>>>>    }
>>>>>
>>>>>    public boolean isOpened() {
>>>>>        return !closed;
>>>>>    }
>>>>>
>>>>>    public void close() {
>>>>>        closed = true;
>>>>>        close(in);
>>>>>        close(out);
>>>>>        close(err);
>>>>>    }
>>>>>
>>>>>    public boolean isInteractive() {
>>>>>        return false;
>>>>>    }
>>>>>
>>>>>    public void run(Object... args) throws Exception {
>>>>>        Console.Executor executor = new Console.Executor() {
>>>>>            public Result execute(final String line) throws  
>>>>> Exception {
>>>>>                assert line != null;
>>>>>                try {
>>>>>                    ShellImpl.this.execute(line);
>>>>>                }
>>>>>                catch (ExitNotification n) {
>>>>>                    return Result.STOP;
>>>>>                }
>>>>>                return Result.CONTINUE;
>>>>>            }
>>>>>        };
>>>>>
>>>>>        IO io = getContext().getIo();
>>>>>
>>>>>        // Setup the console runner
>>>>>        JLineConsole console = new JLineConsole(executor, io);
>>>>>        console.setPrompter(getPrompter());
>>>>>        console.setErrorHandler(new ConsoleErrorHandlerImpl(io));
>>>>>        console.setHistory(getHistory());
>>>>>        if (completers != null) {
>>>>>            // Have to use aggregate here to get the completion
>>>>> list to update properly
>>>>>            console.addCompleter(new  
>>>>> AggregateCompleter(completers));
>>>>>        }
>>>>>        console.run();
>>>>>    }
>>>>>
>>>>>    private void close(Closeable c) {
>>>>>        try {
>>>>>            c.close();
>>>>>        } catch (IOException e) {
>>>>>            // Ignore
>>>>>        }
>>>>>    }
>>>>>
>>>>> }
>>>>>
>>>>> public static class ConsoleErrorHandlerImpl implements
>>>>> Console.ErrorHandler {
>>>>>    private final Logger log = LoggerFactory.getLogger(getClass());
>>>>>
>>>>>    private final IO io;
>>>>>
>>>>>    private AnsiRenderer renderer = new AnsiRenderer();
>>>>>
>>>>>    public ConsoleErrorHandlerImpl(final IO io) {
>>>>>        assert io != null;
>>>>>        this.io = io;
>>>>>    }
>>>>>
>>>>>    public Result handleError(final Throwable error) {
>>>>>        assert error != null;
>>>>>
>>>>>        displayError(error);
>>>>>
>>>>>        return Result.CONTINUE;
>>>>>    }
>>>>>
>>>>>    private void displayError(final Throwable error) {
>>>>>        assert error != null;
>>>>>
>>>>>        // Decode any error notifications
>>>>>        Throwable cause = error;
>>>>>        if (error instanceof ErrorNotification) {
>>>>>            cause = error.getCause();
>>>>>        }
>>>>>
>>>>>        //
>>>>>        // TODO: Use the Render API
>>>>>        //
>>>>>
>>>>>        // Spit out the terse reason why we've failed
>>>>>        io.err.print("@|bold,red ERROR| ");
>>>>>        io.err.print(cause.getClass().getSimpleName());
>>>>>        io.err.println(": @|bold,red " + cause.getMessage() + "|");
>>>>>
>>>>>        // Determine if the stack trace flag is set
>>>>>        String stackTraceProperty =
>>>>> System.getProperty("gshell.show.stacktrace");
>>>>>        boolean stackTraceFlag = false;
>>>>>        if (stackTraceProperty != null) {
>>>>>            stackTraceFlag =  
>>>>> stackTraceProperty.trim().equals("true");
>>>>>        }
>>>>>
>>>>>        if (io.isDebug()) {
>>>>>            // If we have debug enabled then skip the fancy bits
>>>>> below, and log the full error, don't decode shit
>>>>>            log.debug(error.toString(), error);
>>>>>        }
>>>>>        else if (io.isVerbose() || stackTraceFlag) {
>>>>>            // Render a fancy ansi colored stack trace
>>>>>            StackTraceElement[] trace = cause.getStackTrace();
>>>>>            StringBuilder buff = new StringBuilder();
>>>>>
>>>>>            //
>>>>>            // TODO: Move this to helper in gshell-ansi
>>>>>            //
>>>>>
>>>>>            for (StackTraceElement e : trace) {
>>>>>                buff.append("        @|bold at| ").
>>>>>                    append(e.getClassName()).
>>>>>                    append(".").
>>>>>                    append(e.getMethodName()).
>>>>>                    append(" (@|bold ");
>>>>>
>>>>>                buff.append(e.isNativeMethod() ? "Native Method" :
>>>>>                        (e.getFileName() != null &&
>>>>> e.getLineNumber() != -1 ? e.getFileName() + ":" +  
>>>>> e.getLineNumber() :
>>>>>                            (e.getFileName() != null ?
>>>>> e.getFileName() : "Unknown Source")));
>>>>>
>>>>>                buff.append("|)");
>>>>>
>>>>>                //
>>>>>                // FIXME: This does not properly display the full
>>>>> exception detail when cause contains nested exceptions
>>>>>                //
>>>>>
>>>>>                io.err.println(buff);
>>>>>
>>>>>                buff.setLength(0);
>>>>>            }
>>>>>        }
>>>>>        io.err.flush();
>>>>>    }
>>>>> }
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> On Tue, Nov 11, 2008 at 8:07 AM, Jason Dillon <jason.dillon@gmail.com

>>>>> >
>>>>> wrote:
>>>>>>
>>>>>> How does one hook up GShell to use this stuff?
>>>>>>
>>>>>> --jason
>>>>>>
>>>>>>
>>>>>> On Nov 7, 2008, at 4:22 AM, Guillaume Nodet wrote:
>>>>>>
>>>>>>> Over the past days, I've been working on a implementing a SSH
 
>>>>>>> server
>>>>>>> in java to replace to gshell remoting bits.
>>>>>>> The project is currently hosted at google code:
>>>>>>> http://code.google.com/p/sshd/
>>>>>>>
>>>>>>> This project is based on Mina and the current status is that
 
>>>>>>> the ssh
>>>>>>> protocol is in a working state, but there are still a lots of
 
>>>>>>> things
>>>>>>> to iron.
>>>>>>> I've been able to connect using openssh 5.0 and 5.1 and also
 
>>>>>>> jsch
>>>>>>> (from which i borrowed from code btw) and launch an /bin/sh 

>>>>>>> shell and
>>>>>>> issue a few commands.
>>>>>>> I'd be happy if any committer is interested to work on that to
 
>>>>>>> give
>>>>>>> him commits rights on the project.
>>>>>>>
>>>>>>> --
>>>>>>> Cheers,
>>>>>>> Guillaume Nodet
>>>>>>> ------------------------
>>>>>>> Blog: http://gnodet.blogspot.com/
>>>>>>> ------------------------
>>>>>>> Open Source SOA
>>>>>>> http://fusesource.com
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Cheers,
>>>>> Guillaume Nodet
>>>>> ------------------------
>>>>> Blog: http://gnodet.blogspot.com/
>>>>> ------------------------
>>>>> Open Source SOA
>>>>> http://fusesource.com
>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Cheers,
>>> Guillaume Nodet
>>> ------------------------
>>> Blog: http://gnodet.blogspot.com/
>>> ------------------------
>>> Open Source SOA
>>> http://fusesource.com
>>
>>
>
>
>
> -- 
> Cheers,
> Guillaume Nodet
> ------------------------
> Blog: http://gnodet.blogspot.com/
> ------------------------
> Open Source SOA
> http://fusesource.com


Mime
View raw message