(refs #115) Reorganize ssh sources

This commit is contained in:
Tomofumi Tanaka
2014-02-28 22:39:37 +09:00
parent 891ca70ade
commit ceab1d2fd2
5 changed files with 185 additions and 151 deletions

View File

@@ -1,150 +0,0 @@
package servlet
import javax.servlet.{ServletContextEvent, ServletContextListener}
import org.apache.sshd.SshServer
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider
import org.apache.sshd.server._
import org.apache.sshd.server.session.ServerSession
import java.io.{OutputStream, InputStream}
import org.slf4j.LoggerFactory
import org.eclipse.jgit.transport.{ReceivePack, UploadPack}
import org.eclipse.jgit.api.Git
import util.Directory._
import util.ControlUtil._
import org.apache.sshd.server.command.UnknownCommand
/*
* Start a SSH Service Daemon
*
* How to use ?
* git clone ssh://username@host_or_ip:29418/username/repository_name.git
*
*/
class SshServiceListener extends ServletContextListener {
// TODO SshServer should be controllable by admin view (start and stop)
// TODO Use Singleton object SshServer instance management
private val logger = LoggerFactory.getLogger(classOf[SshServiceListener])
val sshService = SshServer.setUpDefaultServer
// TODO allow to disable ssh feature(ssh feature requires many stability test)
val enableSsh = true
override def contextInitialized(sce: ServletContextEvent): Unit = {
if (!enableSsh) return
sshService.setPort(29418) // TODO must be configurable
// TODO PasswordAuthentication should be disable
// TODO Use PublicKeyAuthentication only => and It's stored db on account profile view
val authenticator = new MyPasswordAuthenticator
sshService.setPasswordAuthenticator(authenticator)
// TODO gitbucket.ser should be in GITBUCKET_HOME
sshService.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("gitbucket.ser"))
sshService.setCommandFactory(new CommandFactory {
override def createCommand(command: String): Command = {
logger.info(s"command: String -> ${command}")
command match {
case s if s.startsWith("git-upload-pack ") => new GitUploadPack(command)
case s if s.startsWith("git-receive-pack") => new GitReceivePack(command)
case _ => new UnknownCommand(command)
}
}
})
sshService.start()
}
override def contextDestroyed(sce: ServletContextEvent): Unit = {
sshService.stop(true)
}
}
// always true authenticator... TODO Implements PublicKeyAuthenticator
class MyPasswordAuthenticator extends PasswordAuthenticator {
private val logger = LoggerFactory.getLogger(classOf[MyPasswordAuthenticator])
override def authenticate(username: String, password: String, session: ServerSession): Boolean = {
logger.info("noop authenticate!!!")
true
}
}
abstract class GitCommand(val command: String) extends Command {
private val logger = LoggerFactory.getLogger(classOf[GitCommand])
val (gitCommand, owner, repositoryName) = parseCommand
var err: OutputStream = null
var in: InputStream = null
var out: OutputStream = null
var callback: ExitCallback = null
def runnable: Runnable
override def start(env: Environment): Unit = {
logger.info(s"start command : ${command}")
logger.info(s"parsed command : ${gitCommand}, ${owner}, ${repositoryName}")
val thread = new Thread(runnable)
thread.start
}
override def destroy(): Unit = {
}
override def setExitCallback(callback: ExitCallback): Unit = {
this.callback = callback
}
override def setErrorStream(err: OutputStream): Unit = {
this.err = err
}
override def setOutputStream(out: OutputStream): Unit = {
this.out = out
}
override def setInputStream(in: InputStream): Unit = {
this.in = in
}
private def parseCommand: Tuple3[String, String, String] = {
// command sample: git-upload-pack '/username/repository_name.git'
// command sample: git-receive-pack '/username/repository_name.git'
// TODO This is not correct....
val splitted = command.split(" ")
val gitCommand = splitted(0)
val gitUser = splitted(1).substring(1, splitted(1).length - 5).split("/")(1)
val gitRepo = splitted(1).substring(1, splitted(1).length - 5).split("/")(2)
(gitCommand, gitUser, gitRepo)
}
}
class GitUploadPack(command: String) extends GitCommand(command: String) {
override val runnable = new Runnable {
override def run(): Unit = {
using(Git.open(getRepositoryDir(owner, repositoryName))) {
git =>
val repository = git.getRepository
val upload = new UploadPack(repository)
upload.upload(in, out, err)
callback.onExit(0)
}
}
}
}
class GitReceivePack(command: String) extends GitCommand(command: String) {
override val runnable = new Runnable {
override def run(): Unit = {
using(Git.open(getRepositoryDir(owner, repositoryName))) {
git =>
val repository = git.getRepository
val receive = new ReceivePack(repository)
// TODO ReceivePack has many options. Need more check.
receive.receive(in, out, err)
callback.onExit(0)
}
}
}
}

View File

@@ -0,0 +1,101 @@
package ssh
import org.apache.sshd.server.{CommandFactory, Environment, ExitCallback, Command}
import org.slf4j.LoggerFactory
import java.io.{InputStream, OutputStream}
import util.ControlUtil._
import org.eclipse.jgit.api.Git
import util.Directory._
import org.eclipse.jgit.transport.{ReceivePack, UploadPack}
import org.apache.sshd.server.command.UnknownCommand
class GitCommandFactory extends CommandFactory {
private val logger = LoggerFactory.getLogger(classOf[GitCommandFactory])
override def createCommand(command: String): Command = {
logger.info(s"command: String -> " + command)
command match {
// TODO MUST use regular expression and UnitTest
case s if s.startsWith("git-upload-pack") => new GitUploadPack(command)
case s if s.startsWith("git-receive-pack") => new GitReceivePack(command)
case _ => new UnknownCommand(command)
}
}
}
abstract class GitCommand(val command: String) extends Command {
private val logger = LoggerFactory.getLogger(classOf[GitCommand])
protected val (gitCommand, owner, repositoryName) = parseCommand
protected var err: OutputStream = null
protected var in: InputStream = null
protected var out: OutputStream = null
protected var callback: ExitCallback = null
protected def runnable: Runnable
override def start(env: Environment): Unit = {
logger.info(s"start command : " + command)
logger.info(s"parsed command : $gitCommand, $owner, $repositoryName")
val thread = new Thread(runnable)
thread.start()
}
override def destroy(): Unit = {
}
override def setExitCallback(callback: ExitCallback): Unit = {
this.callback = callback
}
override def setErrorStream(err: OutputStream): Unit = {
this.err = err
}
override def setOutputStream(out: OutputStream): Unit = {
this.out = out
}
override def setInputStream(in: InputStream): Unit = {
this.in = in
}
private def parseCommand: (String, String, String) = {
// command sample: git-upload-pack '/username/repository_name.git'
// command sample: git-receive-pack '/username/repository_name.git'
// TODO This is not correct....
val split = command.split(" ")
val gitCommand = split(0)
val gitUser = split(1).substring(1, split(1).length - 5).split("/")(1)
val gitRepo = split(1).substring(1, split(1).length - 5).split("/")(2)
(gitCommand, gitUser, gitRepo)
}
}
class GitUploadPack(command: String) extends GitCommand(command: String) {
override def runnable = new Runnable {
override def run(): Unit = {
using(Git.open(getRepositoryDir(owner, repositoryName))) { git =>
val repository = git.getRepository
val upload = new UploadPack(repository)
upload.upload(in, out, err)
callback.onExit(0)
}
}
}
}
class GitReceivePack(command: String) extends GitCommand(command: String) {
override def runnable = new Runnable {
override def run(): Unit = {
using(Git.open(getRepositoryDir(owner, repositoryName))) { git =>
val repository = git.getRepository
// TODO hook commit
val receive = new ReceivePack(repository)
receive.receive(in, out, err)
callback.onExit(0)
}
}
}
}

View File

@@ -0,0 +1,24 @@
package ssh
import org.apache.sshd.server.{PublickeyAuthenticator, PasswordAuthenticator}
import org.slf4j.LoggerFactory
import org.apache.sshd.server.session.ServerSession
import java.security.PublicKey
class PublicKeyAuthenticator extends PublickeyAuthenticator {
override def authenticate(username: String, key: PublicKey, session: ServerSession): Boolean = {
// TODO Implements PublicKeyAuthenticator
true
}
}
// always true authenticator...
class MyPasswordAuthenticator extends PasswordAuthenticator {
private val logger = LoggerFactory.getLogger(classOf[MyPasswordAuthenticator])
override def authenticate(username: String, password: String, session: ServerSession): Boolean = {
logger.info("noop authenticate!!!")
true
}
}

View File

@@ -0,0 +1,59 @@
package ssh
import javax.servlet.{ServletContextEvent, ServletContextListener}
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider
import org.slf4j.LoggerFactory
object SshServer {
private val logger = LoggerFactory.getLogger(SshServer.getClass)
val DEFAULT_PORT: Int = 29418 // TODO read from config
val SSH_SERVICE_ENABLE = true
private val server = org.apache.sshd.SshServer.setUpDefaultServer()
private def configure() = {
server.setPort(DEFAULT_PORT)
// TODO not password use PublicKeyAuthenticator
val authenticator = new MyPasswordAuthenticator
server.setPasswordAuthenticator(authenticator)
// TODO gitbucket.ser should be in GITBUCKET_HOME
server.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("gitbucket.ser"))
server.setCommandFactory(new GitCommandFactory)
}
def start() = {
if (SSH_SERVICE_ENABLE) {
configure()
server.start()
}
}
def stop() = {
server.stop(true)
}
}
/*
* Start a SSH Service Daemon
*
* How to use ?
* git clone ssh://username@host_or_ip:29418/username/repository_name.git
*
*/
class SshServerListener extends ServletContextListener {
override def contextInitialized(sce: ServletContextEvent): Unit = {
SshServer.start
}
override def contextDestroyed(sce: ServletContextEvent): Unit = {
SshServer.stop
}
}

View File

@@ -30,7 +30,7 @@
<!-- SSH Daemon initialized --> <!-- SSH Daemon initialized -->
<!-- ===================================================================== --> <!-- ===================================================================== -->
<listener> <listener>
<listener-class>servlet.SshServiceListener</listener-class> <listener-class>ssh.SshServerListener</listener-class>
</listener> </listener>
<!-- ===================================================================== --> <!-- ===================================================================== -->