mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-12-30 04:09:57 +01:00
(refs #1101)Authentication for Transfer API by one-time token
This commit is contained in:
@@ -4,7 +4,7 @@ import java.io.{File, FileInputStream, FileOutputStream}
|
||||
import java.text.MessageFormat
|
||||
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}
|
||||
|
||||
import gitbucket.core.util.{Directory, FileUtil}
|
||||
import gitbucket.core.util.{Directory, FileUtil, StringUtil}
|
||||
import org.apache.commons.io.{FileUtils, IOUtils}
|
||||
import org.json4s.jackson.Serialization._
|
||||
import org.apache.http.HttpStatus
|
||||
@@ -22,7 +22,7 @@ class GitLfsTransferServlet extends HttpServlet {
|
||||
|
||||
override protected def doGet(req: HttpServletRequest, res: HttpServletResponse): Unit = {
|
||||
for {
|
||||
oid <- getObjectId(req, res)
|
||||
oid <- getObjectId(req, res) if checkToken(req, oid)
|
||||
} yield {
|
||||
val file = new File(FileUtil.getLfsFilePath(oid))
|
||||
if(file.exists()){
|
||||
@@ -42,7 +42,7 @@ class GitLfsTransferServlet extends HttpServlet {
|
||||
|
||||
override protected def doPut(req: HttpServletRequest, res: HttpServletResponse): Unit = {
|
||||
for {
|
||||
oid <- getObjectId(req, res)
|
||||
oid <- getObjectId(req, res) if checkToken(req, oid)
|
||||
} yield {
|
||||
val file = new File(FileUtil.getLfsFilePath(oid))
|
||||
FileUtils.forceMkdir(file.getParentFile)
|
||||
@@ -53,6 +53,16 @@ class GitLfsTransferServlet extends HttpServlet {
|
||||
}
|
||||
}
|
||||
|
||||
private def checkToken(req: HttpServletRequest, oid: String): Boolean = {
|
||||
val token = req.getHeader("Authorization")
|
||||
if(token != null){
|
||||
val Array(expireAt, targetOid) = StringUtil.decodeBlowfish(token).split(" ")
|
||||
oid == targetOid && expireAt.toLong > System.currentTimeMillis
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private def getObjectId(req: HttpServletRequest, rsp: HttpServletResponse): Option[String] = {
|
||||
val info: String = req.getPathInfo
|
||||
val length: Int = 1 + LongObjectIdStringLength
|
||||
|
||||
@@ -74,6 +74,7 @@ class GitRepositoryServlet extends GitServlet with SystemSettingsService {
|
||||
throw new IllegalStateException("lfs.server_url is not configured.")
|
||||
|
||||
case Some(baseUrl) =>
|
||||
val timeout = System.currentTimeMillis + (60000 * 10) // 10 min.
|
||||
val batchResponse = batchRequest.operation match {
|
||||
case "upload" =>
|
||||
GitLfs.BatchUploadResponse("basic", batchRequest.objects.map { requestObject =>
|
||||
@@ -81,7 +82,8 @@ class GitRepositoryServlet extends GitServlet with SystemSettingsService {
|
||||
GitLfs.Actions(
|
||||
upload = Some(GitLfs.Action(
|
||||
href = baseUrl + "/git-lfs/" + requestObject.oid,
|
||||
expires_at = new Date(System.currentTimeMillis + 60000L)
|
||||
header = Map("Authorization" -> StringUtil.encodeBlowfish(timeout + " " + requestObject.oid)),
|
||||
expires_at = new Date(timeout)
|
||||
))
|
||||
)
|
||||
)
|
||||
@@ -92,7 +94,8 @@ class GitRepositoryServlet extends GitServlet with SystemSettingsService {
|
||||
GitLfs.Actions(
|
||||
download = Some(GitLfs.Action(
|
||||
href = baseUrl + "/git-lfs/" + requestObject.oid,
|
||||
expires_at = new Date(System.currentTimeMillis + 60000L)
|
||||
header = Map("Authorization" -> StringUtil.encodeBlowfish(timeout + " " + requestObject.oid)),
|
||||
expires_at = new Date(timeout)
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
package gitbucket.core.util
|
||||
|
||||
import java.net.{URLDecoder, URLEncoder}
|
||||
|
||||
import org.mozilla.universalchardet.UniversalDetector
|
||||
import ControlUtil._
|
||||
import org.apache.commons.io.input.BOMInputStream
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.apache.commons.codec.binary.{Base64, StringUtils}
|
||||
|
||||
import scala.util.control.Exception._
|
||||
|
||||
object StringUtil {
|
||||
|
||||
private lazy val BlowfishKey = {
|
||||
// last 4 numbers in current timestamp
|
||||
val time = System.currentTimeMillis.toString
|
||||
time.substring(time.length - 4)
|
||||
}
|
||||
|
||||
def sha1(value: String): String =
|
||||
defining(java.security.MessageDigest.getInstance("SHA-1")){ md =>
|
||||
md.update(value.getBytes)
|
||||
@@ -21,6 +30,20 @@ object StringUtil {
|
||||
md.digest.map(b => "%02x".format(b)).mkString
|
||||
}
|
||||
|
||||
def encodeBlowfish(value: String): String = {
|
||||
val spec = new javax.crypto.spec.SecretKeySpec(BlowfishKey.getBytes(), "Blowfish")
|
||||
val cipher = javax.crypto.Cipher.getInstance("Blowfish")
|
||||
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, spec)
|
||||
new String(Base64.encodeBase64(cipher.doFinal(value.getBytes("UTF-8"))), "UTF-8")
|
||||
}
|
||||
|
||||
def decodeBlowfish(value: String): String = {
|
||||
val spec = new javax.crypto.spec.SecretKeySpec(BlowfishKey.getBytes(), "Blowfish")
|
||||
val cipher = javax.crypto.Cipher.getInstance("Blowfish")
|
||||
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, spec)
|
||||
new String(cipher.doFinal(Base64.decodeBase64(value)), "UTF-8")
|
||||
}
|
||||
|
||||
def urlEncode(value: String): String = URLEncoder.encode(value, "UTF-8").replace("+", "%20")
|
||||
|
||||
def urlDecode(value: String): String = URLDecoder.decode(value, "UTF-8")
|
||||
|
||||
Reference in New Issue
Block a user