mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-08 14:35:52 +01:00
Merge pull request #591 from marklacroix/anon-access
(refs #274) Add option to deny anonymous (i.e. unauthorized) access
This commit is contained in:
@@ -14,6 +14,7 @@ class ScalatraBootstrap extends LifeCycle {
|
||||
context.getFilterRegistration("basicAuthenticationFilter").addMappingForUrlPatterns(EnumSet.allOf(classOf[DispatcherType]), true, "/git/*")
|
||||
|
||||
// Register controllers
|
||||
context.mount(new AnonymousAccessController, "/*")
|
||||
context.mount(new IndexController, "/")
|
||||
context.mount(new SearchController, "/")
|
||||
context.mount(new FileUploadController, "/upload")
|
||||
|
||||
14
src/main/scala/app/AnonymousAccessController.scala
Normal file
14
src/main/scala/app/AnonymousAccessController.scala
Normal file
@@ -0,0 +1,14 @@
|
||||
package app
|
||||
|
||||
class AnonymousAccessController extends AnonymousAccessControllerBase
|
||||
|
||||
trait AnonymousAccessControllerBase extends ControllerBase {
|
||||
get(!context.settings.allowAnonymousAccess, context.loginAccount.isEmpty) {
|
||||
if(!context.currentPath.startsWith("/assets") && !context.currentPath.startsWith("/signin") &&
|
||||
!context.currentPath.startsWith("/register")) {
|
||||
Unauthorized()
|
||||
} else {
|
||||
pass()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ trait SystemSettingsControllerBase extends ControllerBase {
|
||||
"baseUrl" -> trim(label("Base URL", optional(text()))),
|
||||
"information" -> trim(label("Information", optional(text()))),
|
||||
"allowAccountRegistration" -> trim(label("Account registration", boolean())),
|
||||
"allowAnonymousAccess" -> trim(label("Anonymous access", boolean())),
|
||||
"isCreateRepoOptionPublic" -> trim(label("Default option to create a new repository", boolean())),
|
||||
"gravatar" -> trim(label("Gravatar", boolean())),
|
||||
"notification" -> trim(label("Notification", boolean())),
|
||||
|
||||
@@ -14,6 +14,7 @@ trait SystemSettingsService {
|
||||
settings.baseUrl.foreach(x => props.setProperty(BaseURL, x.replaceFirst("/\\Z", "")))
|
||||
settings.information.foreach(x => props.setProperty(Information, x))
|
||||
props.setProperty(AllowAccountRegistration, settings.allowAccountRegistration.toString)
|
||||
props.setProperty(AllowAnonymousAccess, settings.allowAnonymousAccess.toString)
|
||||
props.setProperty(IsCreateRepoOptionPublic, settings.isCreateRepoOptionPublic.toString)
|
||||
props.setProperty(Gravatar, settings.gravatar.toString)
|
||||
props.setProperty(Notification, settings.notification.toString)
|
||||
@@ -65,6 +66,7 @@ trait SystemSettingsService {
|
||||
getOptionValue[String](props, BaseURL, None).map(x => x.replaceFirst("/\\Z", "")),
|
||||
getOptionValue[String](props, Information, None),
|
||||
getValue(props, AllowAccountRegistration, false),
|
||||
getValue(props, AllowAnonymousAccess, true),
|
||||
getValue(props, IsCreateRepoOptionPublic, true),
|
||||
getValue(props, Gravatar, true),
|
||||
getValue(props, Notification, false),
|
||||
@@ -113,6 +115,7 @@ object SystemSettingsService {
|
||||
baseUrl: Option[String],
|
||||
information: Option[String],
|
||||
allowAccountRegistration: Boolean,
|
||||
allowAnonymousAccess: Boolean,
|
||||
isCreateRepoOptionPublic: Boolean,
|
||||
gravatar: Boolean,
|
||||
notification: Boolean,
|
||||
@@ -158,6 +161,7 @@ object SystemSettingsService {
|
||||
private val BaseURL = "base_url"
|
||||
private val Information = "information"
|
||||
private val AllowAccountRegistration = "allow_account_registration"
|
||||
private val AllowAnonymousAccess = "allow_anonymous_access"
|
||||
private val IsCreateRepoOptionPublic = "is_create_repository_option_public"
|
||||
private val Gravatar = "gravatar"
|
||||
private val Notification = "notification"
|
||||
|
||||
@@ -28,33 +28,45 @@ class BasicAuthenticationFilter extends Filter with RepositoryService with Accou
|
||||
override def setCharacterEncoding(encoding: String) = {}
|
||||
}
|
||||
|
||||
val isUpdating = request.getRequestURI.endsWith("/git-receive-pack") || "service=git-receive-pack".equals(request.getQueryString)
|
||||
|
||||
val settings = loadSystemSettings()
|
||||
|
||||
try {
|
||||
defining(request.paths){ case Array(_, repositoryOwner, repositoryName, _*) =>
|
||||
getRepository(repositoryOwner, repositoryName.replaceFirst("\\.wiki\\.git$|\\.git$", ""), "") match {
|
||||
case Some(repository) => {
|
||||
if(!request.getRequestURI.endsWith("/git-receive-pack") &&
|
||||
!"service=git-receive-pack".equals(request.getQueryString) && !repository.repository.isPrivate){
|
||||
chain.doFilter(req, wrappedResponse)
|
||||
} else {
|
||||
request.getHeader("Authorization") match {
|
||||
case null => requireAuth(response)
|
||||
case auth => decodeAuthHeader(auth).split(":") match {
|
||||
case Array(username, password) => getWritableUser(username, password, repository) match {
|
||||
case Some(account) => {
|
||||
request.setAttribute(Keys.Request.UserName, account.userName)
|
||||
chain.doFilter(req, wrappedResponse)
|
||||
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 {
|
||||
request.getHeader("Authorization") match {
|
||||
case null => requireAuth(response)
|
||||
case auth => decodeAuthHeader(auth).split(":") match {
|
||||
case Array(username, password) => {
|
||||
authenticate(settings, username, password) match {
|
||||
case Some(account) => {
|
||||
if(isUpdating && hasWritePermission(repository.owner, repository.name, Some(account))){
|
||||
request.setAttribute(Keys.Request.UserName, account.userName)
|
||||
}
|
||||
chain.doFilter(req, wrappedResponse)
|
||||
}
|
||||
case None => requireAuth(response)
|
||||
}
|
||||
}
|
||||
case None => requireAuth(response)
|
||||
case _ => requireAuth(response)
|
||||
}
|
||||
case _ => requireAuth(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
case None => {
|
||||
logger.debug(s"Repository ${repositoryOwner}/${repositoryName} is not found.")
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -65,13 +77,6 @@ class BasicAuthenticationFilter extends Filter with RepositoryService with Accou
|
||||
}
|
||||
}
|
||||
|
||||
private def getWritableUser(username: String, password: String, repository: RepositoryService.RepositoryInfo)
|
||||
(implicit session: Session): Option[Account] =
|
||||
authenticate(loadSystemSettings(), username, password) match {
|
||||
case x @ Some(account) if(hasWritePermission(repository.owner, repository.name, x)) => x
|
||||
case _ => None
|
||||
}
|
||||
|
||||
private def requireAuth(response: HttpServletResponse): Unit = {
|
||||
response.setHeader("WWW-Authenticate", "BASIC realm=\"GitBucket\"")
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
|
||||
|
||||
Reference in New Issue
Block a user