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 <[EMAIL PROTECTED]> 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 <[EMAIL PROTECTED]> >> 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 <[EMAIL PROTECTED]> >>>> 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