* @author Eric Myrhe
*
*/
-public class CachingPublicKeyAuthenticator implements PublickeyAuthenticator,
- SessionListener {
+public class CachingPublicKeyAuthenticator implements PublickeyAuthenticator, SessionListener {
protected final Logger log = LoggerFactory.getLogger(getClass());
protected final IAuthenticationManager authManager;
- private final Map<ServerSession, Map<PublicKey, Boolean>> cache =
- new ConcurrentHashMap<ServerSession, Map<PublicKey, Boolean>>();
+ private final Map<ServerSession, Map<PublicKey, Boolean>> cache = new ConcurrentHashMap<ServerSession, Map<PublicKey, Boolean>>();
- public CachingPublicKeyAuthenticator(IPublicKeyManager keyManager,
- IAuthenticationManager authManager) {
+ public CachingPublicKeyAuthenticator(IPublicKeyManager keyManager, IAuthenticationManager authManager) {
this.keyManager = keyManager;
this.authManager = authManager;
}
@Override
- public boolean authenticate(String username, PublicKey key,
- ServerSession session) {
+ public boolean authenticate(String username, PublicKey key, ServerSession session) {
Map<PublicKey, Boolean> map = cache.get(session);
if (map == null) {
map = new HashMap<PublicKey, Boolean>();
return result;
}
- private boolean doAuthenticate(String username, PublicKey suppliedKey,
- ServerSession session) {
+ private boolean doAuthenticate(String username, PublicKey suppliedKey, ServerSession session) {
SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY);
Preconditions.checkState(client.getUser() == null);
username = username.toLowerCase(Locale.US);
List<SshKey> keys = keyManager.getKeys(username);
- if (keys == null || keys.isEmpty()) {
- log.info("{} has not added any public keys for ssh authentication",
- username);
+ if (keys.isEmpty()) {
+ log.info("{} has not added any public keys for ssh authentication", username);
return false;
}
+ SshKey pk = new SshKey(suppliedKey);
+ log.debug("auth supplied {}", pk.getFingerprint());
+
for (SshKey key : keys) {
+ log.debug("auth compare to {}", key.getFingerprint());
if (key.equals(suppliedKey)) {
UserModel user = authManager.authenticate(username, key);
if (user != null) {
}
}
- log.warn("could not authenticate {} for SSH using the supplied public key",
- username);
+ log.warn("could not authenticate {} for SSH using the supplied public key", username);
return false;
}
@Override
protected List<SshKey> getKeysImpl(String username) {
try {
- log.info("loading keystore for {}", username);
+ log.info("loading ssh keystore for {}", username);
File keystore = getKeystore(username);
if (!keystore.exists()) {
return null;
return list;
}
} catch (IOException e) {
- throw new RuntimeException("Canot read ssh keys", e);
+ throw new RuntimeException("Cannot read ssh keys", e);
}
return null;
}
package com.gitblit.transport.ssh;
import java.text.MessageFormat;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
.build(new CacheLoader<String, List<SshKey>>() {
@Override
public List<SshKey> load(String username) {
- return getKeysImpl(username);
+ List<SshKey> keys = getKeysImpl(username);
+ if (keys == null) {
+ return Collections.emptyList();
+ }
+ return Collections.unmodifiableList(keys);
}
});
*/
public class MemoryKeyManager extends IPublicKeyManager {
- Map<String, List<SshKey>> keys;
+ final Map<String, List<SshKey>> keys;
public MemoryKeyManager() {
keys = new HashMap<String, List<SshKey>>();
@Override
protected boolean isStale(String username) {
- return false;
+ // always return true so we gets keys from our hashmap
+ return true;
}
@Override
if (!keys.containsKey(id)) {
keys.put(id, new ArrayList<SshKey>());
}
+ log.info("added {} key {}", username, key.getFingerprint());
return keys.get(id).add(key);
}
public boolean removeKey(String username, SshKey key) {
String id = username.toLowerCase();
if (!keys.containsKey(id)) {
+ log.info("can't remove keys for {}", username);
return false;
}
- return keys.get(id).remove(key);
+ List<SshKey> list = keys.get(id);
+ boolean success = list.remove(key);
+ if (success) {
+ log.info("removed {} key {}", username, key.getFingerprint());
+ }
+
+ if (list.isEmpty()) {
+ keys.remove(id);
+ log.info("no {} keys left, removed {}", username, username);
+ }
+ return success;
}
@Override
public boolean removeAllKeys(String username) {
String id = username.toLowerCase();
keys.remove(id.toLowerCase());
+ log.info("removed all keys for {}", username);
return true;
}
}
final byte [] bin = Base64.decodeBase64(Constants.encodeASCII(parts[1]));
hash = StringUtils.getMD5(bin);
} else {
- // TODO get hash from publickey
- hash = "todo";
+ // TODO calculate the correct hash from a PublicKey instance
+ hash = StringUtils.getMD5(getPublicKey().getEncoded());
}
for (int i = 0; i < hash.length(); i += 2) {
sb.append(hash.charAt(i)).append(hash.charAt(i + 1)).append(':');
@Override
protected AbstractSession createSession(final IoSession io) throws Exception {
- log.info("connection accepted on " + io);
+ log.info("creating ssh session from {}", io.getRemoteAddress());
if (io instanceof MinaSession) {
if (((MinaSession) io).getSession().getConfig() instanceof SocketSessionConfig) {
session.addCloseSessionListener(new SshFutureListener<CloseFuture>() {
@Override
public void operationComplete(CloseFuture future) {
- log.info("connection closed on " + io);
+ log.info("closed ssh session from {}", io.getRemoteAddress());
}
});
return session;
protected final Logger log = LoggerFactory.getLogger(getClass());
- @Argument(metaVar = "<KEY>", usage = "the key(s) to add")
+ @Argument(metaVar = "<STDIN>", usage = "the key to add")
private List<String> addKeys = new ArrayList<String>();
@Option(name = "--permission", aliases = { "-p" }, metaVar = "PERMISSION", usage = "set the key access permission")
}
@Override
- public void run() throws IOException, UnloggedFailure {
+ public void run() throws IOException, Failure {
String username = getContext().getClient().getUsername();
List<String> keys = readKeys(addKeys);
for (String key : keys) {
try {
sshKey.setPermission(ap);
} catch (IllegalArgumentException e) {
- throw new UnloggedFailure(1, e.getMessage());
+ throw new Failure(1, e.getMessage());
}
}
}
private final String ALL = "ALL";
- @Argument(metaVar = "<INDEX>|<KEY>|ALL", usage = "the key to remove", required = true)
- private List<String> removeKeys = new ArrayList<String>();
+ @Argument(metaVar = "<INDEX>|ALL", usage = "the key to remove", required = true)
+ private List<String> keyParameters = new ArrayList<String>();
@Override
- public void run() throws IOException, UnloggedFailure {
+ public void run() throws IOException, Failure {
String username = getContext().getClient().getUsername();
// remove a key that has been piped to the command
// or remove all keys
- List<SshKey> currentKeys = getKeyManager().getKeys(username);
- if (currentKeys == null || currentKeys.isEmpty()) {
+ List<SshKey> registeredKeys = new ArrayList<SshKey>(getKeyManager().getKeys(username));
+ if (registeredKeys.isEmpty()) {
throw new UnloggedFailure(1, "There are no registered keys!");
}
- List<String> keys = readKeys(removeKeys);
- if (keys.contains(ALL)) {
+ if (keyParameters.contains(ALL)) {
if (getKeyManager().removeAllKeys(username)) {
stdout.println("Removed all keys.");
log.info("removed all SSH public keys from {}", username);
log.warn("failed to remove all SSH public keys from {}", username);
}
} else {
- for (String key : keys) {
+ for (String keyParameter : keyParameters) {
try {
// remove a key by it's index (1-based indexing)
- int index = Integer.parseInt(key);
- if (index > keys.size()) {
- if (keys.size() == 1) {
- throw new UnloggedFailure(1, "Invalid index specified. There is only 1 registered key.");
+ int index = Integer.parseInt(keyParameter);
+ if (index > registeredKeys.size()) {
+ if (keyParameters.size() == 1) {
+ throw new Failure(1, "Invalid index specified. There is only 1 registered key.");
}
- throw new UnloggedFailure(1, String.format("Invalid index specified. There are %d registered keys.", keys.size()));
+ throw new Failure(1, String.format("Invalid index specified. There are %d registered keys.", registeredKeys.size()));
}
- SshKey sshKey = currentKeys.get(index - 1);
+ SshKey sshKey = registeredKeys.get(index - 1);
if (getKeyManager().removeKey(username, sshKey)) {
stdout.println(String.format("Removed %s", sshKey.getFingerprint()));
} else {
- throw new UnloggedFailure(1, String.format("failed to remove #%s: %s", key, sshKey.getFingerprint()));
- }
- } catch (Exception e) {
- // remove key by raw key data
- SshKey sshKey = parseKey(key);
- if (getKeyManager().removeKey(username, sshKey)) {
- stdout.println(String.format("Removed %s", sshKey.getFingerprint()));
- log.info("removed SSH public key {} from {}", sshKey.getFingerprint(), username);
- } else {
- log.warn("failed to remove SSH public key {} from {}", sshKey.getFingerprint(), username);
- throw new UnloggedFailure(1, String.format("failed to remove %s", sshKey.getFingerprint()));
+ throw new Failure(1, String.format("failed to remove #%s: %s", keyParameter, sshKey.getFingerprint()));
}
+ } catch (NumberFormatException e) {
+ log.warn("failed to remove SSH public key {} from {}", keyParameter, username);
+ throw new Failure(1, String.format("failed to remove key %s", keyParameter));
}
}
}
private List<String> values = new ArrayList<String>();
@Override
- public void run() throws UnloggedFailure {
+ public void run() throws Failure {
final String username = getContext().getClient().getUsername();
IPublicKeyManager keyManager = getContext().getGitblit().getPublicKeyManager();
List<SshKey> keys = keyManager.getKeys(username);
if (keyManager.addKey(username, key)) {
stdout.println(String.format("Updated the comment for key #%d.", index));
} else {
- throw new UnloggedFailure(1, String.format("Failed to update the comment for key #%d!", index));
+ throw new Failure(1, String.format("Failed to update the comment for key #%d!", index));
}
}
#log4j.logger.net=INFO
#log4j.logger.com.gitblit=DEBUG
-log4j.logger.org.apache.sshd=ERROR
+log4j.logger.com.gitblit.transport.ssh.SshServerSession=WARN
+log4j.logger.org.apache.sshd=WARN
+log4j.logger.org.apache.mina=WARN
log4j.logger.org.apache.wicket=INFO
log4j.logger.org.apache.wicket.RequestListenerInterface=WARN
SshDaemonTest.class, GroovyScriptTest.class, LuceneExecutorTest.class, RepositoryModelTest.class,\r
FanoutServiceTest.class, Issue0259Test.class, Issue0271Test.class, HtpasswdAuthenticationTest.class,\r
ModelUtilsTest.class, JnaUtilsTest.class, LdapSyncServiceTest.class, FileTicketServiceTest.class,
- BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class })
+ BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class,\r
+ SshKeysDispatcherTest.class })
public class GitBlitSuite {\r
\r
public static final File BASEFOLDER = new File("data");\r
Executors.newSingleThreadExecutor().execute(new Runnable() {\r
@Override\r
public void run() {\r
- GitBlitServer.main("--httpPort", "" + port, "--httpsPort", "0", "--shutdownPort",\r
- "" + shutdownPort, "--gitPort", "" + gitPort, "--repositoriesFolder",\r
- "\"" + GitBlitSuite.REPOSITORIES.getAbsolutePath() + "\"", "--userService",\r
- GitBlitSuite.USERSCONF.getAbsolutePath(), "--settings", GitBlitSuite.SETTINGS.getAbsolutePath(),\r
- "--baseFolder", "data", "--sshPort", "" + sshPort);\r
+ GitBlitServer.main(\r
+ "--httpPort", "" + port,\r
+ "--httpsPort", "0",\r
+ "--shutdownPort", "" + shutdownPort,\r
+ "--gitPort", "" + gitPort,\r
+ "--sshPort", "" + sshPort,\r
+ "--repositoriesFolder", GitBlitSuite.REPOSITORIES.getAbsolutePath(),\r
+ "--userService", GitBlitSuite.USERSCONF.getAbsolutePath(),\r
+ "--settings", GitBlitSuite.SETTINGS.getAbsolutePath(),\r
+ "--baseFolder", "data");\r
}\r
});\r
\r
*/
package com.gitblit.tests;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.security.KeyPair;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.io.File;
+import java.text.MessageFormat;
+import java.util.List;
-import org.apache.sshd.ClientChannel;
import org.apache.sshd.ClientSession;
import org.apache.sshd.SshClient;
-import org.apache.sshd.common.KeyPairProvider;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
+import org.eclipse.jgit.api.CloneCommand;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
+import org.eclipse.jgit.util.FileUtils;
import org.junit.Test;
import com.gitblit.Constants;
-import com.gitblit.transport.ssh.IPublicKeyManager;
-import com.gitblit.transport.ssh.MemoryKeyManager;
-import com.gitblit.transport.ssh.SshKey;
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AuthorizationControl;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.utils.JGitUtils;
-public class SshDaemonTest extends GitblitUnitTest {
+public class SshDaemonTest extends SshUnitTest {
- private static final AtomicBoolean started = new AtomicBoolean(false);
- private static KeyPair pair;
+ static File ticgitFolder = new File(GitBlitSuite.REPOSITORIES, "working/ticgit");
- @BeforeClass
- public static void startGitblit() throws Exception {
- started.set(GitBlitSuite.startGitblit());
- pair = SshUtils.createTestHostKeyProvider().loadKey(KeyPairProvider.SSH_RSA);
- }
-
- @AfterClass
- public static void stopGitblit() throws Exception {
- if (started.get()) {
- GitBlitSuite.stopGitblit();
- }
- }
-
- protected MemoryKeyManager getKeyManager() {
- IPublicKeyManager mgr = gitblit().getPublicKeyManager();
- if (mgr instanceof MemoryKeyManager) {
- return (MemoryKeyManager) gitblit().getPublicKeyManager();
- } else {
- throw new RuntimeException("unexpected key manager type " + mgr.getClass().getName());
- }
- }
-
- @Before
- public void prepare() {
- MemoryKeyManager keyMgr = getKeyManager();
- keyMgr.addKey("admin", new SshKey(pair.getPublic()));
- }
-
- @After
- public void tearDown() {
- MemoryKeyManager keyMgr = getKeyManager();
- keyMgr.removeAllKeys("admin");
- }
+ String url = GitBlitSuite.sshDaemonUrl;
@Test
public void testPublicKeyAuthentication() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("localhost", GitBlitSuite.sshPort).await().getSession();
- pair.getPublic().getEncoded();
- assertTrue(session.authPublicKey("admin", pair).await().isSuccess());
+ SshClient client = getClient();
+ ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).await().getSession();
+ session.addPublicKeyIdentity(rwKeyPair);
+ assertTrue(session.auth().await().isSuccess());
}
@Test
public void testVersionCommand() throws Exception {
- SshClient client = SshClient.setUpDefaultClient();
- client.start();
- ClientSession session = client.connect("localhost", GitBlitSuite.sshPort).await().getSession();
- pair.getPublic().getEncoded();
- assertTrue(session.authPublicKey("admin", pair).await().isSuccess());
-
- ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_EXEC, "version");
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- Writer w = new OutputStreamWriter(baos);
- w.close();
- channel.setIn(new ByteArrayInputStream(baos.toByteArray()));
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ByteArrayOutputStream err = new ByteArrayOutputStream();
- channel.setOut(out);
- channel.setErr(err);
- channel.open();
-
- channel.waitFor(ClientChannel.CLOSED, 0);
+ String result = testSshCommand("version");
+ assertEquals(Constants.getGitBlitVersion(), result);
+ }
- String result = out.toString().trim();
- channel.close(false);
- client.stop();
+ @Test
+ public void testCloneCommand() throws Exception {
+ if (ticgitFolder.exists()) {
+ GitBlitSuite.close(ticgitFolder);
+ FileUtils.delete(ticgitFolder, FileUtils.RECURSIVE);
+ }
- assertEquals(Constants.getGitBlitVersion(), result);
- }
+ // set clone restriction
+ RepositoryModel model = repositories().getRepositoryModel("ticgit.git");
+ model.accessRestriction = AccessRestrictionType.CLONE;
+ model.authorizationControl = AuthorizationControl.NAMED;
+ repositories().updateRepositoryModel(model.name, model, false);
+
+ JschConfigTestSessionFactory sessionFactory = new JschConfigTestSessionFactory(roKeyPair);
+ SshSessionFactory.setInstance(sessionFactory);
+
+ CloneCommand clone = Git.cloneRepository();
+ clone.setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, password));
+ clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
+ clone.setDirectory(ticgitFolder);
+ clone.setBare(false);
+ clone.setCloneAllBranches(true);
+ Git git = clone.call();
+ List<RevCommit> commits = JGitUtils.getRevLog(git.getRepository(), 10);
+ GitBlitSuite.close(git);
+ assertEquals(10, commits.size());
+
+ // restore anonymous repository access
+ model.accessRestriction = AccessRestrictionType.NONE;
+ model.authorizationControl = AuthorizationControl.NAMED;
+ repositories().updateRepositoryModel(model.name, model, false);
+ }
}
--- /dev/null
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed 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 com.gitblit.tests;
+
+import java.security.KeyPair;
+import java.util.List;
+
+import org.junit.Test;
+import org.parboiled.common.StringUtils;
+
+import com.gitblit.Constants.AccessPermission;
+import com.gitblit.transport.ssh.SshKey;
+
+/**
+ * Tests the Keys Dispatcher and it's commands.
+ *
+ * @author James Moger
+ *
+ */
+public class SshKeysDispatcherTest extends SshUnitTest {
+
+ @Test
+ public void testKeysListCommand() throws Exception {
+ String result = testSshCommand("keys ls -L");
+ List<SshKey> keys = getKeyManager().getKeys(username);
+ assertEquals(String.format("There are %d keys!", keys.size()), 2, keys.size());
+ assertEquals(keys.get(0).getRawData() + "\n" + keys.get(1).getRawData(), result);
+ }
+
+ @Test
+ public void testKeysWhichCommand() throws Exception {
+ String result = testSshCommand("keys which -L");
+ List<SshKey> keys = getKeyManager().getKeys(username);
+ assertEquals(String.format("There are %d keys!", keys.size()), 2, keys.size());
+ assertEquals(keys.get(0).getRawData(), result);
+ }
+
+ @Test
+ public void testKeysRmCommand() throws Exception {
+ testSshCommand("keys rm 2");
+ String result = testSshCommand("keys ls -L");
+ List<SshKey> keys = getKeyManager().getKeys(username);
+ assertEquals(String.format("There are %d keys!", keys.size()), 1, keys.size());
+ assertEquals(keys.get(0).getRawData(), result);
+ }
+
+ @Test
+ public void testKeysRmAllByIndexCommand() throws Exception {
+ testSshCommand("keys rm 1 2");
+ List<SshKey> keys = getKeyManager().getKeys(username);
+ assertEquals(String.format("There are %d keys!", keys.size()), 0, keys.size());
+ try {
+ testSshCommand("keys ls -L");
+ assertTrue("Authentication worked without a public key?!", false);
+ } catch (AssertionError e) {
+ assertTrue(true);
+ }
+ }
+
+ @Test
+ public void testKeysRmAllCommand() throws Exception {
+ testSshCommand("keys rm ALL");
+ List<SshKey> keys = getKeyManager().getKeys(username);
+ assertEquals(String.format("There are %d keys!", keys.size()), 0, keys.size());
+ try {
+ testSshCommand("keys ls -L");
+ assertTrue("Authentication worked without a public key?!", false);
+ } catch (AssertionError e) {
+ assertTrue(true);
+ }
+ }
+
+ @Test
+ public void testKeysAddCommand() throws Exception {
+ KeyPair kp = generator.generateKeyPair();
+ SshKey key = new SshKey(kp.getPublic());
+ testSshCommand("keys add --permission R", key.getRawData());
+ List<SshKey> keys = getKeyManager().getKeys(username);
+ assertEquals(String.format("There are %d keys!", keys.size()), 3, keys.size());
+ assertEquals(AccessPermission.CLONE, keys.get(2).getPermission());
+
+ String result = testSshCommand("keys ls -L");
+ StringBuilder sb = new StringBuilder();
+ for (SshKey sk : keys) {
+ sb.append(sk.getRawData());
+ sb.append('\n');
+ }
+ sb.setLength(sb.length() - 1);
+ assertEquals(sb.toString(), result);
+ }
+
+ @Test
+ public void testKeysCommentCommand() throws Exception {
+ List<SshKey> keys = getKeyManager().getKeys(username);
+ assertTrue(StringUtils.isEmpty(keys.get(0).getComment()));
+ String comment = "this is my comment";
+ testSshCommand(String.format("keys comment 1 %s", comment));
+
+ keys = getKeyManager().getKeys(username);
+ assertEquals(comment, keys.get(0).getComment());
+ }
+}
--- /dev/null
+/*
+ * Copyright 2014 gitblit.com.
+ *
+ * Licensed 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 com.gitblit.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.SocketAddress;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import com.gitblit.Constants.AccessPermission;
+import com.gitblit.transport.ssh.IPublicKeyManager;
+import com.gitblit.transport.ssh.MemoryKeyManager;
+import com.gitblit.transport.ssh.SshKey;
+
+/**
+ * Base class for SSH unit tests.
+ */
+public abstract class SshUnitTest extends GitblitUnitTest {
+
+ protected static final AtomicBoolean started = new AtomicBoolean(false);
+ protected static KeyPairGenerator generator;
+ protected KeyPair rwKeyPair;
+ protected KeyPair roKeyPair;
+ protected String username = "admin";
+ protected String password = "admin";
+
+ @BeforeClass
+ public static void startGitblit() throws Exception {
+ generator = SecurityUtils.getKeyPairGenerator("RSA");
+ started.set(GitBlitSuite.startGitblit());
+ }
+
+ @AfterClass
+ public static void stopGitblit() throws Exception {
+ if (started.get()) {
+ GitBlitSuite.stopGitblit();
+ }
+ }
+
+ protected MemoryKeyManager getKeyManager() {
+ IPublicKeyManager mgr = gitblit().getPublicKeyManager();
+ if (mgr instanceof MemoryKeyManager) {
+ return (MemoryKeyManager) gitblit().getPublicKeyManager();
+ } else {
+ throw new RuntimeException("unexpected key manager type " + mgr.getClass().getName());
+ }
+ }
+
+ @Before
+ public void prepare() {
+ rwKeyPair = generator.generateKeyPair();
+
+ MemoryKeyManager keyMgr = getKeyManager();
+ keyMgr.addKey(username, new SshKey(rwKeyPair.getPublic()));
+
+ roKeyPair = generator.generateKeyPair();
+ SshKey sshKey = new SshKey(roKeyPair.getPublic());
+ sshKey.setPermission(AccessPermission.CLONE);
+ keyMgr.addKey(username, sshKey);
+ }
+
+ @After
+ public void tearDown() {
+ MemoryKeyManager keyMgr = getKeyManager();
+ keyMgr.removeAllKeys(username);
+ }
+
+ protected SshClient getClient() {
+ SshClient client = SshClient.setUpDefaultClient();
+ client.setServerKeyVerifier(new ServerKeyVerifier() {
+ @Override
+ public boolean verifyServerKey(ClientSession sshClientSession, SocketAddress remoteAddress, PublicKey serverKey) {
+ return true;
+ }
+ });
+ client.start();
+ return client;
+ }
+
+ protected String testSshCommand(String cmd) throws IOException, InterruptedException {
+ return testSshCommand(cmd, null);
+ }
+
+ protected String testSshCommand(String cmd, String stdin) throws IOException, InterruptedException {
+ SshClient client = getClient();
+ ClientSession session = client.connect(username, "localhost", GitBlitSuite.sshPort).await().getSession();
+ session.addPublicKeyIdentity(rwKeyPair);
+ assertTrue(session.auth().await().isSuccess());
+
+ ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_EXEC, cmd);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ if (stdin != null) {
+ Writer w = new OutputStreamWriter(baos);
+ w.write(stdin);
+ w.close();
+ }
+ channel.setIn(new ByteArrayInputStream(baos.toByteArray()));
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+ channel.setOut(out);
+ channel.setErr(err);
+ channel.open();
+
+ channel.waitFor(ClientChannel.CLOSED, 0);
+
+ String result = out.toString().trim();
+ channel.close(false);
+ client.stop();
+ return result;
+ }
+}
+++ /dev/null
-/*
- * 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 com.gitblit.tests;
-
-import java.io.File;
-import java.net.ServerSocket;
-import java.net.URISyntaxException;
-import java.net.URL;
-
-import org.apache.sshd.common.KeyPairProvider;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
-import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
-
-public class SshUtils {
-
- public static KeyPairProvider createTestHostKeyProvider() {
- return new SimpleGeneratorHostKeyProvider("target/hostkey.rsa", "RSA");
- }
-
- 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 = SshUtils.class.getClassLoader().getResource(resource);
- File f;
- try {
- f = new File(url.toURI());
- } catch(URISyntaxException e) {
- f = new File(url.getPath());
- }
- return f.toString();
- }
-
- public static void deleteRecursive(File file) {
- if (file != null) {
- if (file.isDirectory()) {
- File[] children = file.listFiles();
- if (children != null) {
- for (File child : children) {
- deleteRecursive(child);
- }
- }
- }
- file.delete();
- }
- }
-
-}