1
0
Fork 0
forked from forgejo/forgejo

Revert "[GITEA] rework long-term authentication"

This reverts commit 8d2dab94a6.
This commit is contained in:
Earl Warren 2024-01-16 14:11:28 +00:00
parent fd098cf75b
commit d694579bdf
No known key found for this signature in database
GPG key ID: 0579CB2928A78A00
17 changed files with 156 additions and 367 deletions

View file

@ -4,14 +4,16 @@
package context
import (
"crypto/sha256"
"encoding/hex"
"net/http"
"strings"
auth_model "code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web/middleware"
"golang.org/x/crypto/pbkdf2"
)
const CookieNameFlash = "gitea_flash"
@ -44,13 +46,41 @@ func (ctx *Context) GetSiteCookie(name string) string {
return middleware.GetSiteCookie(ctx.Req, name)
}
// SetLTACookie will generate a LTA token and add it as an cookie.
func (ctx *Context) SetLTACookie(u *user_model.User) error {
days := 86400 * setting.LogInRememberDays
lookup, validator, err := auth_model.GenerateAuthToken(ctx, u.ID, timeutil.TimeStampNow().Add(int64(days)))
if err != nil {
return err
}
ctx.SetSiteCookie(setting.CookieRememberName, lookup+":"+validator, days)
return nil
// GetSuperSecureCookie returns given cookie value from request header with secret string.
func (ctx *Context) GetSuperSecureCookie(secret, name string) (string, bool) {
val := ctx.GetSiteCookie(name)
return ctx.CookieDecrypt(secret, val)
}
// CookieDecrypt returns given value from with secret string.
func (ctx *Context) CookieDecrypt(secret, val string) (string, bool) {
if val == "" {
return "", false
}
text, err := hex.DecodeString(val)
if err != nil {
return "", false
}
key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
text, err = util.AESGCMDecrypt(key, text)
return string(text), err == nil
}
// SetSuperSecureCookie sets given cookie value to response header with secret string.
func (ctx *Context) SetSuperSecureCookie(secret, name, value string, maxAge int) {
text := ctx.CookieEncrypt(secret, value)
ctx.SetSiteCookie(name, text, maxAge)
}
// CookieEncrypt encrypts a given value using the provided secret
func (ctx *Context) CookieEncrypt(secret, value string) string {
key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
text, err := util.AESGCMEncrypt(key, []byte(value))
if err != nil {
panic("error encrypting cookie: " + err.Error())
}
return hex.EncodeToString(text)
}

View file

@ -19,6 +19,7 @@ var (
SecretKey string
InternalToken string // internal access token
LogInRememberDays int
CookieUserName string
CookieRememberName string
ReverseProxyAuthUser string
ReverseProxyAuthEmail string
@ -103,6 +104,7 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
sec := rootCfg.Section("security")
InstallLock = HasInstallLock(rootCfg)
LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt(7)
CookieUserName = sec.Key("COOKIE_USERNAME").MustString("gitea_awesome")
SecretKey = loadSecret(sec, "SECRET_KEY_URI", "SECRET_KEY")
if SecretKey == "" {
// FIXME: https://github.com/go-gitea/gitea/issues/16832

View file

@ -4,6 +4,10 @@
package util
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"io"
"os"
)
@ -36,3 +40,52 @@ func CopyFile(src, dest string) error {
}
return os.Chmod(dest, si.Mode())
}
// AESGCMEncrypt (from legacy package): encrypts plaintext with the given key using AES in GCM mode. should be replaced.
func AESGCMEncrypt(key, plaintext []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, gcm.NonceSize())
if _, err := rand.Read(nonce); err != nil {
return nil, err
}
ciphertext := gcm.Seal(nil, nonce, plaintext, nil)
return append(nonce, ciphertext...), nil
}
// AESGCMDecrypt (from legacy package): decrypts ciphertext with the given key using AES in GCM mode. should be replaced.
func AESGCMDecrypt(key, ciphertext []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
size := gcm.NonceSize()
if len(ciphertext)-size <= 0 {
return nil, errors.New("ciphertext is empty")
}
nonce := ciphertext[:size]
ciphertext = ciphertext[size:]
plainText, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
}
return plainText, nil
}

View file

@ -4,6 +4,8 @@
package util
import (
"crypto/aes"
"crypto/rand"
"fmt"
"os"
"testing"
@ -35,3 +37,21 @@ func TestCopyFile(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, testContent, dstContent)
}
func TestAESGCM(t *testing.T) {
t.Parallel()
key := make([]byte, aes.BlockSize)
_, err := rand.Read(key)
assert.NoError(t, err)
plaintext := []byte("this will be encrypted")
ciphertext, err := AESGCMEncrypt(key, plaintext)
assert.NoError(t, err)
decrypted, err := AESGCMDecrypt(key, ciphertext)
assert.NoError(t, err)
assert.Equal(t, plaintext, decrypted)
}