geronimo-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Guillaume Nodet" <gno...@gmail.com>
Subject Re: [Heads up] SSH server in java
Date Sat, 22 Nov 2008 11:48:38 GMT
On Sat, Nov 22, 2008 at 7:32 AM, Jason Dillon <jason.dillon@gmail.com> wrote:
> Any idea what this means:
>
> <snip>
> Bliss:Applications jason$ ssh localhost -p 8081
> jason@localhost's password:
> channel_by_id: 1: bad id: channel free
> channel_input_success_failure: 1: unknown
> channel_by_id: 1: bad id: channel free
> channel_input_success_failure: 1: unknown
> </snip>
>
> This is from "OpenSSH_5.1p1, OpenSSL 0.9.7l 28 Sep 2006" on Mac OS X.  It
> does connect and seems to work well.  Though seems to not handle sending
> over exceptions, like when a command is not resolved.  But I might look into
> that some more later today.

Not sure what those lines mean.  When I connect using OpenSSH and
launch a bad command in ServiceMix, I can see the usual output from
gshell on stderr with the ansi colors.

> Whats the status of the SSH work, any release on the horizon?  I'm sold on
> this for the GShell remoting direction, and really this is what I wanted
> from the start.  So I'd like to drop the other whisper/remoting muck and
> just use this.

There are still lots of things to do, but i think i could release a
0.1 very soon.
Btw, this project should soon move into Apache as a Mina subproject,
but I will do a release before that at google so that we can embed it.

> Your thoughts?
>
> --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

Mime
View raw message