You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2013/07/23 17:09:53 UTC

git commit: [SSHD-241] Git/SSH command support

Updated Branches:
  refs/heads/master 8bfdf38cd -> a57eea5c3


[SSHD-241] Git/SSH command support

Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/a57eea5c
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/a57eea5c
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/a57eea5c

Branch: refs/heads/master
Commit: a57eea5c3900ec307cd28287e9716458942020e6
Parents: 8bfdf38
Author: Guillaume Nodet <gn...@apache.org>
Authored: Tue Jul 23 17:09:42 2013 +0200
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Tue Jul 23 17:09:42 2013 +0200

----------------------------------------------------------------------
 pom.xml                                         |   3 +
 sshd-git/README.txt                             |   4 +
 sshd-git/pom.xml                                | 134 ++++++++++++++
 .../java/org/apache/sshd/git/GitCommand.java    | 177 +++++++++++++++++++
 .../org/apache/sshd/git/GitCommandFactory.java  |  51 ++++++
 .../java/org/apache/sshd/git/GitServerTest.java |  49 +++++
 .../git/util/BogusPasswordAuthenticator.java    |  34 ++++
 .../apache/sshd/git/util/EchoShellFactory.java  | 115 ++++++++++++
 .../java/org/apache/sshd/git/util/Utils.java    |  58 ++++++
 sshd-git/src/test/resources/hostkey.pem         |  15 ++
 sshd-git/src/test/resources/log4j.properties    |  38 ++++
 11 files changed, 678 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index cfe03b9..b5357f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -251,6 +251,9 @@
         <module>sshd-core</module>
         <module>sshd-pam</module>
         <module>sshd-sftp</module>
+        <!--
+        <module>sshd-git</module>
+        -->
         <module>assembly</module>
     </modules>
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/README.txt
----------------------------------------------------------------------
diff --git a/sshd-git/README.txt b/sshd-git/README.txt
new file mode 100644
index 0000000..046f7c5
--- /dev/null
+++ b/sshd-git/README.txt
@@ -0,0 +1,4 @@
+This module contains an SSHD CommandFactory to support git through SSH.
+The git commands are provided by a modified version of jgit-pgm
+available at:
+  https://github.com/gnodet/jgit/tree/%23413522

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/pom.xml
----------------------------------------------------------------------
diff --git a/sshd-git/pom.xml b/sshd-git/pom.xml
new file mode 100644
index 0000000..3dcdc4a
--- /dev/null
+++ b/sshd-git/pom.xml
@@ -0,0 +1,134 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd</artifactId>
+        <version>0.9.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.sshd</groupId>
+    <artifactId>sshd-git</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+    <name>Apache Mina SSHD :: Git</name>
+    <packaging>jar</packaging>
+    <inceptionYear>2008</inceptionYear>
+
+    <properties>
+        <projectRoot>${basedir}/..</projectRoot>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.sshd</groupId>
+            <artifactId>sshd-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jgit</groupId>
+            <artifactId>org.eclipse.jgit</artifactId>
+            <version>3.1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jgit</groupId>
+            <artifactId>org.eclipse.jgit.pgm</artifactId>
+            <version>3.1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.jcraft</groupId>
+            <artifactId>jsch</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>bouncycastle</groupId>
+            <artifactId>bcprov-jdk15</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/filtered-resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>org.apache.sshd.git</Bundle-SymbolicName>
+                        <Import-Package>
+                            *
+                        </Import-Package>
+                        <Export-Package>
+                            org.apache.sshd.git*;version=${project.version};-noimport:=true
+                        </Export-Package>
+                        <_versionpolicy>[$(version;==;$(@)),$(version;+;$(@)))</_versionpolicy>
+                    </instructions>
+                    <unpackBundle>true</unpackBundle>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>bundle-manifest</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>manifest</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.1</version>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <redirectTestOutputToFile>true</redirectTestOutputToFile>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/src/main/java/org/apache/sshd/git/GitCommand.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/GitCommand.java b/sshd-git/src/main/java/org/apache/sshd/git/GitCommand.java
new file mode 100644
index 0000000..9a8684b
--- /dev/null
+++ b/sshd-git/src/main/java/org/apache/sshd/git/GitCommand.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sshd.common.channel.ChannelOutputStream;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.ExitCallback;
+import org.eclipse.jgit.pgm.EmbeddedCommandRunner;
+import org.eclipse.jgit.pgm.TextBuiltin;
+import org.eclipse.jgit.pgm.opt.SubcommandHandler;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class GitCommand implements Command, Runnable {
+
+    private String command;
+    private InputStream in;
+    private OutputStream out;
+    private OutputStream err;
+    private ExitCallback callback;
+
+    public GitCommand(String command) {
+        this.command = command;
+    }
+
+    public void setInputStream(InputStream in) {
+        this.in = in;
+    }
+
+    public void setOutputStream(OutputStream out) {
+        this.out = out;
+        if (out instanceof ChannelOutputStream) {
+            ((ChannelOutputStream) out).setNoDelay(true);
+        }
+    }
+
+    public void setErrorStream(OutputStream err) {
+        this.err = err;
+        if (err instanceof ChannelOutputStream) {
+            ((ChannelOutputStream) err).setNoDelay(true);
+        }
+    }
+
+    public void setExitCallback(ExitCallback callback) {
+        this.callback = callback;
+    }
+
+    public void start(Environment env) throws IOException {
+        new Thread(this).start();
+    }
+
+    public void run() {
+        try {
+            List<String> strs = parseDelimitedString(command, " ", true);
+            String[] args = strs.toArray(new String[strs.size()]);
+            for (int i = 0; i < args.length; i++) {
+                if (args[i].startsWith("'") && args[i].endsWith("'")) {
+                    args[i] = args[i].substring(1, args[i].length() - 1);
+                }
+                if (args[i].startsWith("\"") && args[i].endsWith("\"")) {
+                    args[i] = args[i].substring(1, args[i].length() - 1);
+                }
+            }
+            new EmbeddedCommandRunner().execute(args, in, out, err);
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+        if (callback != null) {
+            callback.onExit(0);
+        }
+    }
+
+    public void destroy() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    /**
+     * Parses delimited string and returns an array containing the tokens. This
+     * parser obeys quotes, so the delimiter character will be ignored if it is
+     * inside of a quote. This method assumes that the quote character is not
+     * included in the set of delimiter characters.
+     *
+     * @param value the delimited string to parse.
+     * @param delim the characters delimiting the tokens.
+     * @return a list of string or an empty list if there are none.
+     */
+    private static List<String> parseDelimitedString(String value, String delim, boolean trim) {
+        if (value == null) {
+            value = "";
+        }
+
+        List<String> list = new ArrayList<String>();
+
+        int CHAR = 1;
+        int DELIMITER = 2;
+        int STARTQUOTE = 4;
+        int ENDQUOTE = 8;
+
+        StringBuilder sb = new StringBuilder();
+
+        int expecting = (CHAR | DELIMITER | STARTQUOTE);
+
+        boolean isEscaped = false;
+        for (int i = 0; i < value.length(); i++) {
+            char c = value.charAt(i);
+
+            boolean isDelimiter = (delim.indexOf(c) >= 0);
+
+            if (!isEscaped && (c == '\\')) {
+                isEscaped = true;
+                continue;
+            }
+
+            if (isEscaped) {
+                sb.append(c);
+            } else if (isDelimiter && ((expecting & DELIMITER) > 0)) {
+                if (trim) {
+                    list.add(sb.toString().trim());
+                } else {
+                    list.add(sb.toString());
+                }
+                sb.delete(0, sb.length());
+                expecting = (CHAR | DELIMITER | STARTQUOTE);
+            } else if ((c == '"') && ((expecting & STARTQUOTE) > 0)) {
+                sb.append(c);
+                expecting = CHAR | ENDQUOTE;
+            } else if ((c == '"') && ((expecting & ENDQUOTE) > 0)) {
+                sb.append(c);
+                expecting = (CHAR | STARTQUOTE | DELIMITER);
+            } else if ((expecting & CHAR) > 0) {
+                sb.append(c);
+            } else {
+                throw new IllegalArgumentException("Invalid delimited string: " + value);
+            }
+
+            isEscaped = false;
+        }
+
+        if (sb.length() > 0) {
+            if (trim) {
+                list.add(sb.toString().trim());
+            } else {
+                list.add(sb.toString());
+            }
+        }
+
+        return list;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/src/main/java/org/apache/sshd/git/GitCommandFactory.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/GitCommandFactory.java b/sshd-git/src/main/java/org/apache/sshd/git/GitCommandFactory.java
new file mode 100644
index 0000000..3148202
--- /dev/null
+++ b/sshd-git/src/main/java/org/apache/sshd/git/GitCommandFactory.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git;
+
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.command.UnknownCommand;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class GitCommandFactory implements CommandFactory {
+
+    private CommandFactory delegate;
+
+    public GitCommandFactory() {
+    }
+
+    public GitCommandFactory(CommandFactory delegate) {
+        this.delegate = delegate;
+    }
+
+    public Command createCommand(String command) {
+        if (command.startsWith("git-")) {
+            return new GitCommand(command.substring("git-".length()));
+        } else if (delegate != null) {
+            return delegate.createCommand(command);
+        } else {
+            return new UnknownCommand(command);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/src/test/java/org/apache/sshd/git/GitServerTest.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/java/org/apache/sshd/git/GitServerTest.java b/sshd-git/src/test/java/org/apache/sshd/git/GitServerTest.java
new file mode 100644
index 0000000..d0c2626
--- /dev/null
+++ b/sshd-git/src/test/java/org/apache/sshd/git/GitServerTest.java
@@ -0,0 +1,49 @@
+package org.apache.sshd.git;
+
+import java.util.Arrays;
+
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.git.util.BogusPasswordAuthenticator;
+import org.apache.sshd.git.util.EchoShellFactory;
+import org.apache.sshd.git.util.Utils;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.command.UnknownCommand;
+import org.apache.sshd.server.sftp.SftpSubsystem;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ */
+public class GitServerTest {
+
+    @Test
+    @Ignore
+    public void testGit() {
+
+    }
+
+    public static void main(String[] args) throws Exception {
+        SshServer sshd = SshServer.setUpDefaultServer();
+        sshd.getProperties().put(SshServer.IDLE_TIMEOUT, "10000");
+        sshd.setPort(8001);
+        sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+        sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
+        sshd.setShellFactory(new EchoShellFactory());
+//        sshd.setCommandFactory(new ScpCommandFactory());
+        sshd.setCommandFactory(new CommandFactory() {
+            public Command createCommand(String command) {
+                if (command.startsWith("git-")) {
+                    return new GitCommand(command.substring("git-".length()));
+                } else {
+                    return new UnknownCommand(command);
+                }
+            }
+        });
+        sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+        sshd.start();
+        Thread.sleep(100000);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/src/test/java/org/apache/sshd/git/util/BogusPasswordAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/java/org/apache/sshd/git/util/BogusPasswordAuthenticator.java b/sshd-git/src/test/java/org/apache/sshd/git/util/BogusPasswordAuthenticator.java
new file mode 100644
index 0000000..8cc3de3
--- /dev/null
+++ b/sshd-git/src/test/java/org/apache/sshd/git/util/BogusPasswordAuthenticator.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.util;
+
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class BogusPasswordAuthenticator implements PasswordAuthenticator {
+
+    public boolean authenticate(String username, String password, ServerSession session) {
+        return username != null && username.equals(password);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/src/test/java/org/apache/sshd/git/util/EchoShellFactory.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/java/org/apache/sshd/git/util/EchoShellFactory.java b/sshd-git/src/test/java/org/apache/sshd/git/util/EchoShellFactory.java
new file mode 100644
index 0000000..2faa6eb
--- /dev/null
+++ b/sshd-git/src/test/java/org/apache/sshd/git/util/EchoShellFactory.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.ExitCallback;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class EchoShellFactory implements Factory<Command> {
+
+    public Command create() {
+        return new EchoShell();
+    }
+
+    public static class EchoShell implements Command, Runnable {
+
+        private InputStream in;
+        private OutputStream out;
+        private OutputStream err;
+        private ExitCallback callback;
+        private Environment environment;
+        private Thread thread;
+
+        public InputStream getIn() {
+            return in;
+        }
+
+        public OutputStream getOut() {
+            return out;
+        }
+
+        public OutputStream getErr() {
+            return err;
+        }
+
+        public Environment getEnvironment() {
+            return environment;
+        }
+
+        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 setExitCallback(ExitCallback callback) {
+            this.callback = callback;
+        }
+
+        public void start(Environment env) throws IOException {
+            environment = env;
+            thread = new Thread(this, "EchoShell");
+            thread.start();
+        }
+
+        public void destroy() {
+            thread.interrupt();
+        }
+
+        public void run() {
+            BufferedReader r = new BufferedReader(new InputStreamReader(in));
+            try {
+                for (;;) {
+                    String s = r.readLine();
+                    if (s == null) {
+                        return;
+                    }
+                    out.write((s + "\n").getBytes());
+                    out.flush();
+                    if ("exit".equals(s)) {
+                        return;
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                callback.onExit(0);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java b/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
new file mode 100644
index 0000000..2558d9c
--- /dev/null
+++ b/sshd-git/src/test/java/org/apache/sshd/git/util/Utils.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.git.util;
+
+import java.io.File;
+import java.net.ServerSocket;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+
+public class Utils {
+
+    public static FileKeyPairProvider createTestHostKeyProvider() {
+        return createTestKeyPairProvider("hostkey.pem");
+    }
+
+    public static FileKeyPairProvider createTestKeyPairProvider(String resource) {
+        return new FileKeyPairProvider(new String[] { getFile(resource) });
+    }
+
+    public static int getFreePort() throws Exception {
+        ServerSocket s = new ServerSocket(0);
+        try {
+            return s.getLocalPort();
+        } finally {
+            s.close();
+        }
+    }
+
+    private static String getFile(String resource) {
+        URL url = Utils.class.getClassLoader().getResource(resource);
+        File f;
+        try {
+            f = new File(url.toURI());
+        } catch(URISyntaxException e) {
+            f = new File(url.getPath());
+        }
+        return f.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/src/test/resources/hostkey.pem
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/resources/hostkey.pem b/sshd-git/src/test/resources/hostkey.pem
new file mode 100644
index 0000000..6b6974c
--- /dev/null
+++ b/sshd-git/src/test/resources/hostkey.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDdfIWeSV4o68dRrKSzFd/Bk51E65UTmmSrmW0O1ohtzi6HzsDP
+jXgCtlTt3FqTcfFfI92IlTr4JWqC9UK1QT1ZTeng0MkPQmv68hDANHbt5CpETZHj
+W5q4OOgWhVvj5IyOC2NZHtKlJBkdsMAa15ouOOJLzBvAvbqOR/yUROsEiQIDAQAB
+AoGBANG3JDW6NoP8rF/zXoeLgLCj+tfVUPSczhGFVrQkAk4mWfyRkhN0WlwHFOec
+K89MpkV1ij/XPVzU4MNbQ2yod1KiDylzvweYv+EaEhASCmYNs6LS03punml42SL9
+97tOmWfVJXxlQoLiY6jHPU97vTc65k8gL+gmmrpchsW0aqmZAkEA/c8zfmKvY37T
+cxcLLwzwsqqH7g2KZGTf9aRmx2ebdW+QKviJJhbdluDgl1TNNFj5vCLznFDRHiqJ
+wq0wkZ39cwJBAN9l5v3kdXj21UrurNPdlV0n2GZBt2vblooQC37XHF97r2zM7Ou+
+Lg6MyfJClyguhWL9dxnGbf3btQ0l3KDstxMCQCRaiEqjAfIjWVATzeNIXDWLHXso
+b1kf5cA+cwY+vdKdTy4IeUR+Y/DXdvPWDqpf0C11aCVMohdLCn5a5ikFUycCQDhV
+K/BuAallJNfmY7JxN87r00fF3ojWMJnT/fIYMFFrkQrwifXQWTDWE76BSDibsosJ
+u1TGksnm8zrDh2UVC/0CQFrHTiSl/3DHvWAbOJawGKg46cnlDcAhSyV8Frs8/dlP
+7YGG3eqkw++lsghqmFO6mRUTKsBmiiB2wgLGhL5pyYY=
+-----END RSA PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a57eea5c/sshd-git/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/sshd-git/src/test/resources/log4j.properties b/sshd-git/src/test/resources/log4j.properties
new file mode 100644
index 0000000..9172dc9
--- /dev/null
+++ b/sshd-git/src/test/resources/log4j.properties
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed  under the  License is distributed on an "AS IS" BASIS,
+# WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
+# implied.
+#
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, stdout
+#log4j.logger.org.apache.sshd=TRACE
+#log4j.logger.org.apache.sshd.common.channel.Window=DEBUG
+
+# CONSOLE appender
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/servicemix-test.log
+log4j.appender.out.append=true