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 Mon, 24 Nov 2008 11:51:05 GMT
Yes, a vote is already going on to start the SSH subproject.

On Sun, Nov 23, 2008 at 8:19 AM, Jason Dillon <jason.dillon@gmail.com> wrote:
> On Nov 22, 2008, at 6:48 PM, Guillaume Nodet wrote:
>>>
>>> <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.
>
> I will investigate more... I did not see the exception spat out on the
> client when entering a bad command... perhaps that is because of the above
> msgs?
>
>> 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.
>
> Have you talked to the mina folks about it?  Anyways, I can't stop saying
> how thrilled I am about this.  You rock!  Needless to say next time we meet
> up I'm gonna buy you all the beer you can drink ;-)
>
> --jason
>
>
>>
>>> 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
>
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/
------------------------
Open Source SOA
http://fusesource.com

Mime
View raw message