package nl.minicom.gitolite.manager.integration; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.transport.JschConfigSessionFactory; import org.eclipse.jgit.transport.OpenSshConfig; import org.eclipse.jgit.transport.OpenSshConfig.Host; import org.eclipse.jgit.transport.SshSessionFactory; import org.eclipse.jgit.util.FS; import org.junit.After; import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Strings; import com.google.common.io.Files; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.KeyPair; import com.jcraft.jsch.Session; import nl.minicom.gitolite.manager.models.Config; import nl.minicom.gitolite.manager.models.ConfigManager; import nl.minicom.gitolite.manager.models.Group; import nl.minicom.gitolite.manager.models.Permission; import nl.minicom.gitolite.manager.models.Repository; import nl.minicom.gitolite.manager.models.User; @RunWith(Parameterized.class) public class TestUsernameCharacters { private static final Logger log = LoggerFactory.getLogger(TestUsernameCharacters.class); private static final String CLONE_URL = "https://github.com/devhub-tud/Java-Gitolite-Manager.git"; private static String baseUrl; private static String gitUri; private static String adminUsername; @BeforeClass public static void beforeClass() { Assume.assumeTrue(Strings.isNullOrEmpty(System.getProperty("skipIntegrationTests"))); baseUrl = System.getProperty("gitUri", "ssh://git@localhost:2222/"); gitUri = baseUrl.concat("gitolite-admin"); adminUsername = System.getProperty("gitAdmin", "git"); } @Parameters(name = "{index}: testUsername({0})") public static Collection<Object[]> data() { return Arrays.asList(new Object[][] { { "Username" }, { "User-name" }, { "Username-" }, { "User+name" }, { "Username+" }, { "User.name" }, { "Username." }, { "User_name" }, { "Username_" } }); } private ConfigManager manager; private File stagingDirectory; @Before public void setUp() throws Exception { resetSshSessionFactory(); manager = ConfigManager.create(gitUri); stagingDirectory = Files.createTempDir(); clearEverything(); } @After public void tearDown() throws Exception { resetSshSessionFactory(); clearEverything(); stagingDirectory.delete(); } private final String username; public TestUsernameCharacters(final String username) { this.username = username; } private void clearEverything() throws Exception { Config config = manager.get(); for (User user : config.getUsers()) { if (!adminUsername.equals(user.getName())) { config.removeUser(user); } } for (Group group : config.getGroups()) { config.removeGroup(group); } for (Repository repo : config.getRepositories()) { if (!"gitolite-admin".equals(repo.getName())) { config.removeRepository(repo); } } manager.apply(config); } @Test public void testUsername() throws Exception { final KeyPair keyPair = KeyPair.genKeyPair( new JSch(), KeyPair.RSA); Config config = manager.get(); User user = config.createUser(username); String keyContents = getPublicKeyContents(keyPair); user.setKey("Key1", keyContents); Repository repository = config.createRepository("bliep"); repository.setPermission(user, Permission.READ_WRITE); manager.apply(config); Git repo = Git.cloneRepository() .setBare(false) .setDirectory(stagingDirectory) .setURI(CLONE_URL) .setProgressMonitor(new LogProgressMonitor("cloning from " + CLONE_URL)) .call(); setKeyForSsh(keyPair); String repoUrl = baseUrl + repository.getName(); repo.push() .setRemote(repoUrl) .setPushAll() .setPushTags() .setProgressMonitor(new LogProgressMonitor("pushing to " + baseUrl)) .call(); } private void resetSshSessionFactory() { SshSessionFactory.setInstance(new DefaultSshSessionFactory()); } private void setKeyForSsh(KeyPair keyPair) { SshSessionFactory.setInstance(new PublicKeySessionFactory(keyPair)); } private static String getPublicKeyContents(final KeyPair keypair) { try(ByteArrayOutputStream out = new ByteArrayOutputStream()) { keypair.writePublicKey(out, ""); return out.toString(); } catch (IOException e) { throw new RuntimeException(e); } } static class DefaultSshSessionFactory extends JschConfigSessionFactory { @Override protected void configure(Host hc, Session session) { } } static class PublicKeySessionFactory extends DefaultSshSessionFactory { private final KeyPair keyPair; public PublicKeySessionFactory(final KeyPair keyPair) { this.keyPair = keyPair; } @Override protected JSch getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException { JSch jSch = super.getJSch(hc, fs); jSch.removeAllIdentity(); try (ByteArrayOutputStream bas = new ByteArrayOutputStream(); ByteArrayOutputStream bis = new ByteArrayOutputStream()) { keyPair.writePrivateKey(bas); keyPair.writePublicKey(bis, ""); jSch.addIdentity("another", bas.toByteArray(), bis.toByteArray(), (byte[]) null); } catch (Exception e){ log.warn(e.getMessage(), e); throw new RuntimeException(e); } return jSch; } } static class LogProgressMonitor implements ProgressMonitor { private final String task; public LogProgressMonitor(final String task) { this.task = task; } @Override public void start(int totalTasks) { log.info("Starting {} with {} tasks", task, totalTasks); } @Override public void beginTask(String title, int totalWork) {} @Override public void update(int completed) {} @Override public void endTask() { log.info("Finished {}", task); } @Override public boolean isCancelled() { return false; } } }