mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-12 16:35:52 +01:00
Merge pull request #2017 from kounoike/pr-secure-password
use PBKDF2 for password
This commit is contained in:
4
src/main/resources/update/gitbucket-core_4.25.xml
Normal file
4
src/main/resources/update/gitbucket-core_4.25.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<changeSet>
|
||||||
|
<modifyDataType columnName="PASSWORD" newDataType="varchar(200)" tableName="ACCOUNT"/>
|
||||||
|
</changeSet>
|
||||||
@@ -53,5 +53,6 @@ object GitBucketCoreModule
|
|||||||
new Version("4.23.0", new LiquibaseMigration("update/gitbucket-core_4.23.xml")),
|
new Version("4.23.0", new LiquibaseMigration("update/gitbucket-core_4.23.xml")),
|
||||||
new Version("4.23.1"),
|
new Version("4.23.1"),
|
||||||
new Version("4.24.0", new LiquibaseMigration("update/gitbucket-core_4.24.xml")),
|
new Version("4.24.0", new LiquibaseMigration("update/gitbucket-core_4.24.xml")),
|
||||||
new Version("4.24.1")
|
new Version("4.24.1"),
|
||||||
|
new Version("4.25.0", new LiquibaseMigration("update/gitbucket-core_4.25.xml"))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
account =>
|
account =>
|
||||||
updateAccount(
|
updateAccount(
|
||||||
account.copy(
|
account.copy(
|
||||||
password = form.password.map(sha1).getOrElse(account.password),
|
password = form.password.map(pbkdf2_sha256).getOrElse(account.password),
|
||||||
fullName = form.fullName,
|
fullName = form.fullName,
|
||||||
mailAddress = form.mailAddress,
|
mailAddress = form.mailAddress,
|
||||||
description = form.description,
|
description = form.description,
|
||||||
@@ -563,7 +563,7 @@ trait AccountControllerBase extends AccountManagementControllerBase {
|
|||||||
if (context.settings.allowAccountRegistration) {
|
if (context.settings.allowAccountRegistration) {
|
||||||
createAccount(
|
createAccount(
|
||||||
form.userName,
|
form.userName,
|
||||||
sha1(form.password),
|
pbkdf2_sha256(form.password),
|
||||||
form.fullName,
|
form.fullName,
|
||||||
form.mailAddress,
|
form.mailAddress,
|
||||||
false,
|
false,
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
|||||||
post("/admin/users/_newuser", newUserForm)(adminOnly { form =>
|
post("/admin/users/_newuser", newUserForm)(adminOnly { form =>
|
||||||
createAccount(
|
createAccount(
|
||||||
form.userName,
|
form.userName,
|
||||||
sha1(form.password),
|
pbkdf2_sha256(form.password),
|
||||||
form.fullName,
|
form.fullName,
|
||||||
form.mailAddress,
|
form.mailAddress,
|
||||||
form.isAdmin,
|
form.isAdmin,
|
||||||
@@ -457,7 +457,7 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
|
|||||||
|
|
||||||
updateAccount(
|
updateAccount(
|
||||||
account.copy(
|
account.copy(
|
||||||
password = form.password.map(sha1).getOrElse(account.password),
|
password = form.password.map(pbkdf2_sha256).getOrElse(account.password),
|
||||||
fullName = form.fullName,
|
fullName = form.fullName,
|
||||||
mailAddress = form.mailAddress,
|
mailAddress = form.mailAddress,
|
||||||
isAdmin = form.isAdmin,
|
isAdmin = form.isAdmin,
|
||||||
|
|||||||
@@ -33,7 +33,16 @@ trait AccountService {
|
|||||||
* Authenticate by internal database.
|
* Authenticate by internal database.
|
||||||
*/
|
*/
|
||||||
private def defaultAuthentication(userName: String, password: String)(implicit s: Session) = {
|
private def defaultAuthentication(userName: String, password: String)(implicit s: Session) = {
|
||||||
|
val pbkdf2re = """^\$pbkdf2-sha256\$(\d+)\$([0-9a-zA-Z+/=]+)\$([0-9a-zA-Z+/=]+)$""".r
|
||||||
getAccountByUserName(userName).collect {
|
getAccountByUserName(userName).collect {
|
||||||
|
case account if !account.isGroupAccount =>
|
||||||
|
account.password match {
|
||||||
|
case pbkdf2re(iter, salt, hash) if (pbkdf2_sha256(iter.toInt, salt, password) == hash) => Some(account)
|
||||||
|
case p if p == sha1(password) =>
|
||||||
|
updateAccount(account.copy(password = pbkdf2_sha256(password)))
|
||||||
|
Some(account)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
case account if (!account.isGroupAccount && account.password == sha1(password)) => Some(account)
|
case account if (!account.isGroupAccount && account.password == sha1(password)) => Some(account)
|
||||||
} getOrElse None
|
} getOrElse None
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package gitbucket.core.util
|
package gitbucket.core.util
|
||||||
|
|
||||||
import java.net.{URLDecoder, URLEncoder}
|
import java.net.{URLDecoder, URLEncoder}
|
||||||
|
import java.security.SecureRandom
|
||||||
import java.util.{Base64, UUID}
|
import java.util.{Base64, UUID}
|
||||||
|
|
||||||
import org.mozilla.universalchardet.UniversalDetector
|
import org.mozilla.universalchardet.UniversalDetector
|
||||||
import SyntaxSugars._
|
import SyntaxSugars._
|
||||||
|
import javax.crypto.SecretKeyFactory
|
||||||
|
import javax.crypto.spec.PBEKeySpec
|
||||||
import org.apache.commons.io.input.BOMInputStream
|
import org.apache.commons.io.input.BOMInputStream
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
|
|
||||||
@@ -16,6 +19,32 @@ object StringUtil {
|
|||||||
UUID.randomUUID().toString.substring(0, 16)
|
UUID.randomUUID().toString.substring(0, 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def base64Encode(value: Array[Byte]): String = {
|
||||||
|
Base64.getEncoder.encodeToString(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
def base64Decode(value: String): Array[Byte] = {
|
||||||
|
Base64.getDecoder.decode(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
def pbkdf2_sha256(iter: Int, salt: String, value: String): String = {
|
||||||
|
val keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
||||||
|
val ks = new PBEKeySpec(value.toCharArray, base64Decode(salt), iter, 256)
|
||||||
|
val s = keyFactory.generateSecret(ks)
|
||||||
|
base64Encode(s.getEncoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
def pbkdf2_sha256(value: String) = {
|
||||||
|
val keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
|
||||||
|
val secureRandom = new SecureRandom
|
||||||
|
val salt: Array[Byte] = new Array(32)
|
||||||
|
secureRandom.nextBytes(salt)
|
||||||
|
val iter = 100000
|
||||||
|
val ks = new PBEKeySpec(value.toCharArray, salt, iter, 256)
|
||||||
|
val s = keyFactory.generateSecret(ks)
|
||||||
|
s"""$$pbkdf2-sha256$$${iter}$$${base64Encode(salt)}$$${base64Encode(s.getEncoded)}"""
|
||||||
|
}
|
||||||
|
|
||||||
def sha1(value: String): String =
|
def sha1(value: String): String =
|
||||||
defining(java.security.MessageDigest.getInstance("SHA-1")) { md =>
|
defining(java.security.MessageDigest.getInstance("SHA-1")) { md =>
|
||||||
md.update(value.getBytes)
|
md.update(value.getBytes)
|
||||||
|
|||||||
Reference in New Issue
Block a user