src/main/java/com/gitblit/transport/ssh/SshCommandFactory.java
@@ -34,7 +34,21 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.git.GitblitReceivePackFactory; import com.gitblit.git.GitblitUploadPackFactory; import com.gitblit.git.RepositoryResolver; import com.gitblit.manager.IGitblit; import com.gitblit.models.UserModel; import com.gitblit.transport.ssh.commands.AddKeyCommand; import com.gitblit.transport.ssh.commands.CreateRepository; import com.gitblit.transport.ssh.commands.DispatchCommand; import com.gitblit.transport.ssh.commands.Receive; import com.gitblit.transport.ssh.commands.RemoveKeyCommand; import com.gitblit.transport.ssh.commands.ReviewCommand; import com.gitblit.transport.ssh.commands.SetAccountCommand; import com.gitblit.transport.ssh.commands.Upload; import com.gitblit.transport.ssh.commands.VersionCommand; import com.gitblit.utils.IdGenerator; import com.gitblit.utils.WorkQueue; import com.google.common.util.concurrent.Atomics; @@ -44,18 +58,56 @@ * */ public class SshCommandFactory implements CommandFactory { private static final Logger logger = LoggerFactory .getLogger(SshCommandFactory.class); private static final Logger logger = LoggerFactory.getLogger(SshCommandFactory.class); private final IGitblit gitblit; private final PublicKeyAuthenticator keyAuthenticator; private final ScheduledExecutorService startExecutor; private DispatchCommand dispatcher; public SshCommandFactory(IGitblit gitblit, PublicKeyAuthenticator keyAuthenticator, IdGenerator idGenerator) { this.gitblit = gitblit; this.keyAuthenticator = keyAuthenticator; public SshCommandFactory( WorkQueue workQueue, DispatchCommand d) { this.dispatcher = d; int threads = 2;//cfg.getInt("sshd","commandStartThreads", 2); WorkQueue workQueue = new WorkQueue(idGenerator); startExecutor = workQueue.createQueue(threads, "SshCommandStart"); } /** * Creates the root dispatcher command which builds up the available commands. * * @param the client * @param the command line * @return the root dispatcher command */ protected DispatchCommand createRootDispatcher(SshDaemonClient client, String cmdLine) { final UserModel user = client.getUser(); DispatchCommand gitblitCmd = new DispatchCommand(); gitblitCmd.registerCommand(user, VersionCommand.class); gitblitCmd.registerCommand(user, AddKeyCommand.class); gitblitCmd.registerCommand(user, RemoveKeyCommand.class); gitblitCmd.registerCommand(user, ReviewCommand.class); gitblitCmd.registerCommand(user, CreateRepository.class); gitblitCmd.registerCommand(user, SetAccountCommand.class); DispatchCommand gitCmd = new DispatchCommand(); gitCmd.registerCommand(user, Upload.class); gitCmd.registerCommand(user, Receive.class); DispatchCommand root = new DispatchCommand(); root.registerDispatcher("gitblit", gitblitCmd); root.registerDispatcher("git", gitCmd); root.setRepositoryResolver(new RepositoryResolver<SshDaemonClient>(gitblit)); root.setUploadPackFactory(new GitblitUploadPackFactory<SshDaemonClient>(gitblit)); root.setReceivePackFactory(new GitblitReceivePackFactory<SshDaemonClient>(gitblit)); root.setAuthenticator(keyAuthenticator); root.setContext(new SshCommandContext(client, cmdLine)); return root; } @Override @@ -133,11 +185,10 @@ private void onStart() throws IOException { synchronized (this) { SshCommandContext ctx = new SshCommandContext(session.getAttribute(SshDaemonClient.KEY), cmdLine); SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY); try { cmd = dispatcher; cmd = createRootDispatcher(client, cmdLine); cmd.setArguments(argv); cmd.setContext(ctx); cmd.setInputStream(in); cmd.setOutputStream(out); cmd.setErrorStream(err); @@ -156,7 +207,7 @@ }); cmd.start(env); } finally { ctx = null; client = null; } } } src/main/java/com/gitblit/transport/ssh/SshDaemon.java
@@ -34,22 +34,9 @@ import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.git.GitblitReceivePackFactory; import com.gitblit.git.GitblitUploadPackFactory; import com.gitblit.git.RepositoryResolver; import com.gitblit.manager.IGitblit; import com.gitblit.transport.ssh.commands.AddKeyCommand; import com.gitblit.transport.ssh.commands.CreateRepository; import com.gitblit.transport.ssh.commands.DispatchCommand; import com.gitblit.transport.ssh.commands.Receive; import com.gitblit.transport.ssh.commands.RemoveKeyCommand; import com.gitblit.transport.ssh.commands.ReviewCommand; import com.gitblit.transport.ssh.commands.SetAccountCommand; import com.gitblit.transport.ssh.commands.Upload; import com.gitblit.transport.ssh.commands.VersionCommand; import com.gitblit.utils.IdGenerator; import com.gitblit.utils.StringUtils; import com.gitblit.utils.WorkQueue; import dagger.Module; import dagger.ObjectGraph; @@ -117,45 +104,19 @@ addr = new InetSocketAddress(bindInterface, port); } PublicKeyAuthenticator publickeyAuthenticator = new PublicKeyAuthenticator( keyManager, gitblit); PublicKeyAuthenticator keyAuthenticator = new PublicKeyAuthenticator(keyManager, gitblit); sshd = SshServer.setUpDefaultServer(); sshd.setPort(addr.getPort()); sshd.setHost(addr.getHostName()); sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider(new File( gitblit.getBaseFolder(), HOST_KEY_STORE).getPath())); sshd.setPublickeyAuthenticator(publickeyAuthenticator); sshd.setPublickeyAuthenticator(keyAuthenticator); sshd.setPasswordAuthenticator(new UsernamePasswordAuthenticator(gitblit)); sshd.setSessionFactory(new SshServerSessionFactory()); sshd.setFileSystemFactory(new DisabledFilesystemFactory()); sshd.setTcpipForwardingFilter(new NonForwardingFilter()); DispatchCommand gitblitCmd = new DispatchCommand(); gitblitCmd.registerCommand(CreateRepository.class); gitblitCmd.registerCommand(VersionCommand.class); gitblitCmd.registerCommand(AddKeyCommand.class); gitblitCmd.registerCommand(RemoveKeyCommand.class); gitblitCmd.registerCommand(SetAccountCommand.class); gitblitCmd.registerCommand(ReviewCommand.class); DispatchCommand gitCmd = new DispatchCommand(); gitCmd.registerCommand(Upload.class); gitCmd.registerCommand(Receive.class); DispatchCommand root = new DispatchCommand(); root.registerDispatcher("gitblit", gitblitCmd); root.registerDispatcher("git", gitCmd); root.setRepositoryResolver(new RepositoryResolver<SshDaemonClient>(gitblit)); root.setUploadPackFactory(new GitblitUploadPackFactory<SshDaemonClient>(gitblit)); root.setReceivePackFactory(new GitblitReceivePackFactory<SshDaemonClient>(gitblit)); root.setAuthenticator(publickeyAuthenticator); SshCommandFactory commandFactory = new SshCommandFactory( new WorkQueue(idGenerator), root); sshd.setCommandFactory(commandFactory); sshd.setCommandFactory(new SshCommandFactory(gitblit, keyAuthenticator, idGenerator)); run = new AtomicBoolean(false); } src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java
@@ -120,16 +120,6 @@ this.exit = callback; } protected void provideBaseStateTo(final Command cmd) { if (cmd instanceof BaseCommand) { ((BaseCommand) cmd).setContext(ctx); } cmd.setInputStream(in); cmd.setOutputStream(out); cmd.setErrorStream(err); cmd.setExitCallback(exit); } protected String getName() { return commandName; } src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
@@ -26,10 +26,13 @@ import org.apache.sshd.server.Command; import org.apache.sshd.server.Environment; import org.kohsuke.args4j.Argument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.git.GitblitReceivePackFactory; import com.gitblit.git.GitblitUploadPackFactory; import com.gitblit.git.RepositoryResolver; import com.gitblit.models.UserModel; import com.gitblit.transport.ssh.CommandMetaData; import com.gitblit.transport.ssh.PublicKeyAuthenticator; import com.gitblit.transport.ssh.SshDaemonClient; @@ -40,6 +43,8 @@ import com.google.common.collect.Sets; public class DispatchCommand extends BaseCommand { private Logger log = LoggerFactory.getLogger(getClass()); @Argument(index = 0, required = false, metaVar = "COMMAND", handler = SubcommandHandler.class) private String commandName; @@ -62,10 +67,21 @@ root.put(name, cmd); } public void registerCommand(Class<? extends Command> cmd) { /** * Registers a command as long as the user is permitted to execute it. * * @param user * @param cmd */ public void registerCommand(UserModel user, Class<? extends Command> cmd) { if (!cmd.isAnnotationPresent(CommandMetaData.class)) { throw new RuntimeException(MessageFormat.format("{0} must be annotated with {1}!", cmd.getName(), CommandMetaData.class.getName())); throw new RuntimeException(MessageFormat.format("{0} must be annotated with {1}!", cmd.getName(), CommandMetaData.class.getName())); } CommandMetaData meta = cmd.getAnnotation(CommandMetaData.class); if (meta.admin() && user.canAdmin()) { log.debug(MessageFormat.format("excluding admin command {} for {}", meta.name(), user.username)); return; } commands.add(cmd); } @@ -92,12 +108,6 @@ } Command cmd = getCommand(); if (cmd.getClass().isAnnotationPresent(CommandMetaData.class)) { CommandMetaData meta = cmd.getClass().getAnnotation(CommandMetaData.class); if (meta.admin() && !ctx.getClient().getUser().canAdmin()) { throw new UnloggedFailure(1, MessageFormat.format("{0} requires admin permissions", commandName)); } } if (cmd instanceof BaseCommand) { BaseCommand bc = (BaseCommand) cmd; if (getName().isEmpty()) { @@ -108,9 +118,7 @@ bc.setArguments(args.toArray(new String[args.size()])); } provideBaseStateTo(cmd); provideGitState(cmd); reset(); provideStateTo(cmd); //atomicCmd.set(cmd); cmd.start(env); @@ -131,9 +139,7 @@ } final Class<? extends Command> c = getMap().get(commandName); if (c == null) { String msg = (getName().isEmpty() ? "Gitblit" : getName()) + ": " + commandName + ": not found"; String msg = (getName().isEmpty() ? "Gitblit" : getName()) + ": " + commandName + ": not found"; throw new UnloggedFailure(1, msg); } @@ -167,15 +173,11 @@ final Class<? extends Command> c = m.get(name); CommandMetaData meta = c.getAnnotation(CommandMetaData.class); if (meta != null) { if (meta.admin() && !ctx.getClient().getUser().canAdmin()) { continue; } if (meta.hidden()) { continue; } usage.append(" "); usage.append(String.format(format, name, Strings.nullToEmpty(meta.description()))); usage.append(String.format(format, name, Strings.nullToEmpty(meta.description()))); } usage.append("\n"); } @@ -191,13 +193,15 @@ return usage.toString(); } // This is needed because we are not using provider or // clazz.newInstance() for DispatchCommand private void reset() { args = new ArrayList<String>(); protected void provideStateTo(final Command cmd) { if (cmd instanceof BaseCommand) { ((BaseCommand) cmd).setContext(ctx); } cmd.setInputStream(in); cmd.setOutputStream(out); cmd.setErrorStream(err); cmd.setExitCallback(exit); private void provideGitState(Command cmd) { if (cmd instanceof BaseGitCommand) { BaseGitCommand a = (BaseGitCommand) cmd; a.setRepositoryResolver(repositoryResolver); @@ -216,21 +220,25 @@ } private RepositoryResolver<SshDaemonClient> repositoryResolver; public void setRepositoryResolver(RepositoryResolver<SshDaemonClient> repositoryResolver) { this.repositoryResolver = repositoryResolver; } private GitblitUploadPackFactory<SshDaemonClient> gitblitUploadPackFactory; public void setUploadPackFactory(GitblitUploadPackFactory<SshDaemonClient> gitblitUploadPackFactory) { this.gitblitUploadPackFactory = gitblitUploadPackFactory; } private GitblitReceivePackFactory<SshDaemonClient> gitblitReceivePackFactory; public void setReceivePackFactory(GitblitReceivePackFactory<SshDaemonClient> gitblitReceivePackFactory) { this.gitblitReceivePackFactory = gitblitReceivePackFactory; } private PublicKeyAuthenticator authenticator; public void setAuthenticator(PublicKeyAuthenticator authenticator) { this.authenticator = authenticator; }