diff --git a/src/main/scala/gitbucket/core/plugin/GitRepositoryRouting.scala b/src/main/scala/gitbucket/core/plugin/GitRepositoryRouting.scala new file mode 100644 index 0000000..e7535b8 --- /dev/null +++ b/src/main/scala/gitbucket/core/plugin/GitRepositoryRouting.scala @@ -0,0 +1,16 @@ +package gitbucket.core.plugin + +import javax.servlet.http.{HttpServletResponse, HttpServletRequest} +import gitbucket.core.service.SystemSettingsService.SystemSettings + +case class GitRepositoryRouting(urlPattern: String, localPath: String, filter: GitRepositoryFilter){ + def this(urlPattern: String, localPath: String) = { + this(urlPattern, localPath, new GitRepositoryFilter(){ + def filter(request: HttpServletRequest, response: HttpServletResponse, settings: SystemSettings, isUpdating: Boolean): Boolean = true + }) + } +} + +trait GitRepositoryFilter { + def filter(request: HttpServletRequest, response: HttpServletResponse, settings: SystemSettings, isUpdating: Boolean): Boolean +} \ No newline at end of file diff --git a/src/main/scala/gitbucket/core/plugin/Plugin.scala b/src/main/scala/gitbucket/core/plugin/Plugin.scala index b9100cf..975791d 100644 --- a/src/main/scala/gitbucket/core/plugin/Plugin.scala +++ b/src/main/scala/gitbucket/core/plugin/Plugin.scala @@ -60,12 +60,12 @@ /** * Override to add git repository routings. */ - val repositoryRoutings: Seq[(String, String)] = Nil + val repositoryRoutings: Seq[GitRepositoryRouting] = Nil /** * Override to add git repository routings. */ - def repositoryRoutings(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[(String, String)] = Nil + def repositoryRoutings(registry: PluginRegistry, context: ServletContext, settings: SystemSettings): Seq[GitRepositoryRouting] = Nil /** * This method is invoked in initialization of plugin system. @@ -84,8 +84,8 @@ (renderers ++ renderers(registry, context, settings)).foreach { case (extension, renderer) => registry.addRenderer(extension, renderer) } - (repositoryRoutings ++ repositoryRoutings(registry, context, settings)).foreach { case (urlPath, localPath) => - registry.addRepositoryRouting(urlPath, localPath) + (repositoryRoutings ++ repositoryRoutings(registry, context, settings)).foreach { routing => + registry.addRepositoryRouting(routing) } } diff --git a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala index 1aacc4b..3bf3ee3 100644 --- a/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala +++ b/src/main/scala/gitbucket/core/plugin/PluginRegistory.scala @@ -28,7 +28,7 @@ renderers ++= Seq( "md" -> MarkdownRenderer, "markdown" -> MarkdownRenderer ) - private val repositoryRoutings = new ListBuffer[(String, String)] + private val repositoryRoutings = new ListBuffer[GitRepositoryRouting] def addPlugin(pluginInfo: PluginInfo): Unit = { plugins += pluginInfo @@ -62,7 +62,7 @@ addController(path, controller) } - def getControllers(): List[(ControllerBase, String)] = controllers.toList + def getControllers(): Seq[(ControllerBase, String)] = controllers.toSeq def addJavaScript(path: String, script: String): Unit = { javaScripts += ((path, script)) @@ -82,20 +82,19 @@ def renderableExtensions: Seq[String] = renderers.keys.toSeq - def addRepositoryRouting(urlPath: String, localPath: String): Unit = { - repositoryRoutings += ((urlPath, localPath)) + def addRepositoryRouting(routing: GitRepositoryRouting): Unit = { + repositoryRoutings += routing } - def getRepositoryRoutings(): Seq[(String, String)] = { + def getRepositoryRoutings(): Seq[GitRepositoryRouting] = { repositoryRoutings.toSeq } - def getRepositoryRouting(requestURI: String): Option[(String, String)] = { + def getRepositoryRouting(requestURI: String): Option[GitRepositoryRouting] = { val path = requestURI.replaceFirst("^/git/", "") PluginRegistry().getRepositoryRoutings().find { - case (urlPath, localPath) => { - println(urlPath) + case GitRepositoryRouting(urlPath, _, _) => { path.matches(urlPath + "(/.*)?") } } diff --git a/src/main/scala/gitbucket/core/servlet/BasicAuthenticationFilter.scala b/src/main/scala/gitbucket/core/servlet/BasicAuthenticationFilter.scala index 6576ced..f6e130f 100644 --- a/src/main/scala/gitbucket/core/servlet/BasicAuthenticationFilter.scala +++ b/src/main/scala/gitbucket/core/servlet/BasicAuthenticationFilter.scala @@ -2,12 +2,12 @@ import javax.servlet._ import javax.servlet.http._ -import gitbucket.core.plugin.PluginRegistry +import gitbucket.core.plugin.{GitRepositoryRouting, PluginRegistry} +import gitbucket.core.service.SystemSettingsService.SystemSettings import gitbucket.core.service.{RepositoryService, AccountService, SystemSettingsService} -import gitbucket.core.util.{ControlUtil, Keys, Implicits} +import gitbucket.core.util.{Keys, Implicits} import org.slf4j.LoggerFactory import Implicits._ -import ControlUtil._ /** * Provides BASIC Authentication for [[GitRepositoryServlet]]. @@ -21,7 +21,7 @@ def destroy(): Unit = {} def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = { - implicit val request = req.asInstanceOf[HttpServletRequest] + val request = req.asInstanceOf[HttpServletRequest] val response = res.asInstanceOf[HttpServletResponse] val wrappedResponse = new HttpServletResponseWrapper(response){ @@ -32,71 +32,16 @@ val settings = loadSystemSettings() try { - PluginRegistry().getRepositoryRouting(request.getRequestURI).map { case (urlPath, localPath) => + PluginRegistry().getRepositoryRouting(request.getRequestURI).map { case GitRepositoryRouting(_, _, f) => // served by plug-ins - chain.doFilter(req, wrappedResponse) + if(f.filter(request, wrappedResponse, settings, isUpdating)){ + pluginRepository(request, wrappedResponse, chain, settings, isUpdating) + } else { + requireAuth(response) + } }.getOrElse { // default repositories - defining(request.paths){ - case Array(_, repositoryOwner, repositoryName, _*) => - getRepository(repositoryOwner, repositoryName.replaceFirst("\\.wiki\\.git$|\\.git$", ""), "") match { - case Some(repository) => { - if(!isUpdating && !repository.repository.isPrivate && settings.allowAnonymousAccess){ - chain.doFilter(req, wrappedResponse) - } else { - // authentication is success then true, otherwise false - val passed = for { - auth <- Option(request.getHeader("Authorization")) - Array(username, password) = decodeAuthHeader(auth).split(":", 2) - account <- authenticate(settings, username, password) - } yield if(isUpdating || repository.repository.isPrivate){ - if(hasWritePermission(repository.owner, repository.name, Some(account))){ - request.setAttribute(Keys.Request.UserName, account.userName) - true - } else false - } else true - - if(passed.getOrElse(false)){ - chain.doFilter(req, wrappedResponse) - } else { - requireAuth(response) - } - -// request.getHeader("Authorization") match { -// case null => requireAuth(response) -// case auth => decodeAuthHeader(auth).split(":", 2) match { -// case Array(username, password) => { -// authenticate(settings, username, password) match { -// case Some(account) => { -// if (isUpdating || repository.repository.isPrivate) { -// if(hasWritePermission(repository.owner, repository.name, Some(account))){ -// request.setAttribute(Keys.Request.UserName, account.userName) -// chain.doFilter(req, wrappedResponse) -// } else { -// requireAuth(response) -// } -// } else { -// chain.doFilter(req, wrappedResponse) -// } -// } -// case _ => requireAuth(response) -// } -// } -// case _ => requireAuth(response) -// } -// } - } - } - case None => { - logger.debug(s"Repository ${repositoryOwner}/${repositoryName} is not found.") - response.sendError(HttpServletResponse.SC_NOT_FOUND) - } - } - case _ => { - logger.debug(s"Not enough path arguments: ${request.paths}") - response.sendError(HttpServletResponse.SC_NOT_FOUND) - } - } + defaultRepository(request, wrappedResponse, chain, settings, isUpdating) } } catch { case ex: Exception => { @@ -106,8 +51,70 @@ } } + private def pluginRepository(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain, + settings: SystemSettings, isUpdating: Boolean): Unit = { + implicit val r = request + if(!isUpdating && settings.allowAnonymousAccess){ + chain.doFilter(request, response) + } else { + val passed = for { + auth <- Option(request.getHeader("Authorization")) + Array(username, password) = decodeAuthHeader(auth).split(":", 2) + account <- authenticate(settings, username, password) + } yield { + request.setAttribute(Keys.Request.UserName, account.userName) + true + } + if(passed.getOrElse(false)){ + chain.doFilter(request, response) + } else { + requireAuth(response) + } + } + } + + private def defaultRepository(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain, + settings: SystemSettings, isUpdating: Boolean): Unit = { + implicit val r = request + + request.paths match { + case Array(_, repositoryOwner, repositoryName, _*) => + getRepository(repositoryOwner, repositoryName.replaceFirst("\\.wiki\\.git$|\\.git$", ""), "") match { + case Some(repository) => { + if(!isUpdating && !repository.repository.isPrivate && settings.allowAnonymousAccess){ + chain.doFilter(request, response) + } else { + val passed = for { + auth <- Option(request.getHeader("Authorization")) + Array(username, password) = decodeAuthHeader(auth).split(":", 2) + account <- authenticate(settings, username, password) + } yield if(isUpdating || repository.repository.isPrivate){ + if(hasWritePermission(repository.owner, repository.name, Some(account))){ + request.setAttribute(Keys.Request.UserName, account.userName) + true + } else false + } else true + + if(passed.getOrElse(false)){ + chain.doFilter(request, response) + } else { + requireAuth(response) + } + } + } + case None => { + logger.debug(s"Repository ${repositoryOwner}/${repositoryName} is not found.") + response.sendError(HttpServletResponse.SC_NOT_FOUND) + } + } + case _ => { + logger.debug(s"Not enough path arguments: ${request.paths}") + response.sendError(HttpServletResponse.SC_NOT_FOUND) + } + } + } private def requireAuth(response: HttpServletResponse): Unit = { response.setHeader("WWW-Authenticate", "BASIC realm=\"GitBucket\"") diff --git a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala index fdb03b3..68402bd 100644 --- a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala +++ b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala @@ -4,7 +4,7 @@ import gitbucket.core.api import gitbucket.core.model.Session -import gitbucket.core.plugin.PluginRegistry +import gitbucket.core.plugin.{GitRepositoryRouting, PluginRegistry} import gitbucket.core.service.IssuesService.IssueSearchCondition import gitbucket.core.service.WebHookService._ import gitbucket.core.service._ @@ -63,13 +63,13 @@ override def open(req: HttpServletRequest, name: String): Repository = { // Check routing which are provided by plug-in - val routing: Option[(String, String)] = PluginRegistry().getRepositoryRoutings().find { - case (urlPath, localPath) => name.matches(urlPath) + val routing = PluginRegistry().getRepositoryRoutings().find { + case GitRepositoryRouting(urlPattern, _, _) => name.matches(urlPattern) } // Rewrite repository path if routing is marched - routing.map { case (urlPath, localPath) => - val path = urlPath.r.replaceFirstIn(name, localPath) + routing.map { case GitRepositoryRouting(urlPattern, localPath, _) => + val path = urlPattern.r.replaceFirstIn(name, localPath) resolver.open(req, path) }.getOrElse { parent.open(req, name)