(refs #464)Add authentication for plugin action

This commit is contained in:
Naoki Takezoe
2014-08-11 19:27:24 +09:00
parent dd809896c8
commit 4e652b5ccd
3 changed files with 64 additions and 29 deletions

View File

@@ -91,8 +91,8 @@ object PluginSystem {
case class PluginRepository(id: String, url: String) case class PluginRepository(id: String, url: String)
case class GlobalMenu(label: String, url: String, icon: String, condition: Context => Boolean) case class GlobalMenu(label: String, url: String, icon: String, condition: Context => Boolean)
case class RepositoryMenu(label: String, name: String, url: String, icon: String, condition: Context => Boolean) case class RepositoryMenu(label: String, name: String, url: String, icon: String, condition: Context => Boolean)
case class Action(path: String, function: (HttpServletRequest, HttpServletResponse) => Any) case class Action(path: String, security: String, function: (HttpServletRequest, HttpServletResponse) => Any)
case class RepositoryAction(path: String, function: (HttpServletRequest, HttpServletResponse, RepositoryInfo) => Any) case class RepositoryAction(path: String, security: String, function: (HttpServletRequest, HttpServletResponse, RepositoryInfo) => Any)
case class Button(label: String, href: String) case class Button(label: String, href: String)
case class JavaScript(filter: String => Boolean, script: String) case class JavaScript(filter: String => Boolean, script: String)

View File

@@ -34,12 +34,12 @@ class ScalaPlugin(val id: String, val version: String,
globalMenuList += GlobalMenu(label, url, icon, condition) globalMenuList += GlobalMenu(label, url, icon, condition)
} }
def addGlobalAction(path: String)(function: (HttpServletRequest, HttpServletResponse) => Any): Unit = { def addGlobalAction(path: String, security: String = "all")(function: (HttpServletRequest, HttpServletResponse) => Any): Unit = {
globalActionList += Action(path, function) globalActionList += Action(path, security, function)
} }
def addRepositoryAction(path: String)(function: (HttpServletRequest, HttpServletResponse, RepositoryInfo) => Any): Unit = { def addRepositoryAction(path: String, security: String = "all")(function: (HttpServletRequest, HttpServletResponse, RepositoryInfo) => Any): Unit = {
repositoryActionList += RepositoryAction(path, function) repositoryActionList += RepositoryAction(path, security, function)
} }
def addJavaScript(filter: String => Boolean, script: String): Unit = { def addJavaScript(filter: String => Boolean, script: String): Unit = {

View File

@@ -33,11 +33,18 @@ class PluginActionInvokeFilter extends Filter with SystemSettingsService with Re
private def processGlobalAction(path: String, request: HttpServletRequest, response: HttpServletResponse): Boolean = { private def processGlobalAction(path: String, request: HttpServletRequest, response: HttpServletResponse): Boolean = {
plugin.PluginSystem.globalActions.find(_.path == path).map { action => plugin.PluginSystem.globalActions.find(_.path == path).map { action =>
val result = action.function(request, response) val loginAccount = request.getSession.getAttribute(Keys.Session.LoginAccount).asInstanceOf[Account]
val systemSettings = loadSystemSettings() val systemSettings = loadSystemSettings()
result match { implicit val context = app.Context(systemSettings, Option(loginAccount), request)
case x: String => renderGlobalHtml(request, response, systemSettings, x)
case x: AnyRef => renderJson(request, response, x) if(filterAction(action.security, context)){
val result = action.function(request, response)
result match {
case x: String => renderGlobalHtml(request, response, context, x)
case x: AnyRef => renderJson(request, response, x)
}
} else {
// TODO NotFound or Error?
} }
true true
} getOrElse false } getOrElse false
@@ -50,18 +57,26 @@ class PluginActionInvokeFilter extends Filter with SystemSettingsService with Re
val owner = elements(1) val owner = elements(1)
val name = elements(2) val name = elements(2)
val remain = elements.drop(3).mkString("/", "/", "") val remain = elements.drop(3).mkString("/", "/", "")
val loginAccount = request.getSession.getAttribute(Keys.Session.LoginAccount).asInstanceOf[Account]
val systemSettings = loadSystemSettings() val systemSettings = loadSystemSettings()
implicit val context = app.Context(systemSettings, Option(loginAccount), request)
getRepository(owner, name, systemSettings.baseUrl(request)).flatMap { repository => getRepository(owner, name, systemSettings.baseUrl(request)).flatMap { repository =>
plugin.PluginSystem.repositoryActions.find(_.path == remain).map { action => plugin.PluginSystem.repositoryActions.find(_.path == remain).map { action =>
val result = try { if(filterAction(action.security, context)){
PluginConnectionHolder.threadLocal.set(session.conn) val result = try {
action.function(request, response, repository) PluginConnectionHolder.threadLocal.set(session.conn)
} finally { action.function(request, response, repository)
PluginConnectionHolder.threadLocal.remove() } finally {
} PluginConnectionHolder.threadLocal.remove()
result match { }
case x: String => renderRepositoryHtml(request, response, systemSettings, repository, x) result match {
case x: AnyRef => renderJson(request, response, x) case x: String => renderRepositoryHtml(request, response, context, repository, x)
case x: AnyRef => renderJson(request, response, x)
}
} else {
// TODO NotFound or Error?
} }
true true
} }
@@ -69,21 +84,41 @@ class PluginActionInvokeFilter extends Filter with SystemSettingsService with Re
} else false } else false
} }
private def renderGlobalHtml(request: HttpServletRequest, response: HttpServletResponse, private def filterAction(security: String, context: app.Context, repository: Option[RepositoryInfo] = None): Boolean = {
systemSettings: SystemSettings, body: String): Unit = { if(repository.isDefined){
if(repository.get.repository.isPrivate){
security match {
case "owner" => context.loginAccount.isDefined && context.loginAccount.get.userName == repository.get.owner // TODO for group repository
case "member" => false // TODO owner or collaborator
case "admin" => context.loginAccount.isDefined && context.loginAccount.get.isAdmin
}
} else {
security match {
case "all" => true
case "login" => context.loginAccount.isDefined
case "owner" => context.loginAccount.isDefined && context.loginAccount.get.userName == repository.get.owner // TODO for group repository
case "member" => false // TODO owner or collaborator
case "admin" => context.loginAccount.isDefined && context.loginAccount.get.isAdmin
}
}
} else {
security match {
case "all" => true
case "login" => context.loginAccount.isDefined
case "admin" => context.loginAccount.isDefined && context.loginAccount.get.isAdmin
}
}
}
private def renderGlobalHtml(request: HttpServletRequest, response: HttpServletResponse, context: app.Context, body: String): Unit = {
response.setContentType("text/html; charset=UTF-8") response.setContentType("text/html; charset=UTF-8")
val loginAccount = request.getSession.getAttribute(Keys.Session.LoginAccount).asInstanceOf[Account] val html = _root_.html.main("GitBucket", None)(Html(body))(context)
implicit val context = app.Context(systemSettings, Option(loginAccount), request)
val html = _root_.html.main("GitBucket", None)(Html(body))
IOUtils.write(html.toString.getBytes("UTF-8"), response.getOutputStream) IOUtils.write(html.toString.getBytes("UTF-8"), response.getOutputStream)
} }
private def renderRepositoryHtml(request: HttpServletRequest, response: HttpServletResponse, private def renderRepositoryHtml(request: HttpServletRequest, response: HttpServletResponse, context: app.Context, repository: RepositoryInfo, body: String): Unit = {
systemSettings: SystemSettings, repository: RepositoryInfo, body: String): Unit = {
response.setContentType("text/html; charset=UTF-8") response.setContentType("text/html; charset=UTF-8")
val loginAccount = request.getSession.getAttribute(Keys.Session.LoginAccount).asInstanceOf[Account] val html = _root_.html.main("GitBucket", None)(_root_.html.menu("", repository)(Html(body))(context))(context) // TODO specify active side menu
implicit val context = app.Context(systemSettings, Option(loginAccount), request)
val html = _root_.html.main("GitBucket", None)(_root_.html.menu("", repository)(Html(body))) // TODO specify active side menu
IOUtils.write(html.toString.getBytes("UTF-8"), response.getOutputStream) IOUtils.write(html.toString.getBytes("UTF-8"), response.getOutputStream)
} }