fix: improve random handling

This commit is contained in:
Yang Luo
2026-04-05 09:42:52 +08:00
parent f6a3fb9455
commit 1e7a2d8dad
11 changed files with 88 additions and 89 deletions

View File

@@ -37,7 +37,6 @@ import (
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy" "github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/google/uuid"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
@@ -938,14 +937,7 @@ func (c *ApiController) Login() {
} }
if tmpUser != nil { if tmpUser != nil {
var uid uuid.UUID uidStr := strings.Split(util.GenerateUUID(), "-")
uid, err = uuid.NewRandom()
if err != nil {
c.ResponseError(err.Error())
return
}
uidStr := strings.Split(uid.String(), "-")
userInfo.Username = fmt.Sprintf("%s_%s", userInfo.Username, uidStr[1]) userInfo.Username = fmt.Sprintf("%s_%s", userInfo.Username, uidStr[1])
} }

View File

@@ -19,7 +19,6 @@ import (
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/google/uuid"
) )
// MfaSetupInitiate // MfaSetupInitiate
@@ -77,7 +76,7 @@ func (c *ApiController) MfaSetupInitiate() {
return return
} }
recoveryCode := uuid.NewString() recoveryCode := util.GenerateUUID()
mfaProps.RecoveryCodes = []string{recoveryCode} mfaProps.RecoveryCodes = []string{recoveryCode}
mfaProps.MfaRememberInHours = organization.MfaRememberInHours mfaProps.MfaRememberInHours = organization.MfaRememberInHours

View File

@@ -26,7 +26,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/google/uuid" "github.com/casdoor/casdoor/util"
) )
const ( const (
@@ -141,7 +141,7 @@ func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddr
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("repeatability-request-id", uuid.New().String()) req.Header.Set("repeatability-request-id", util.GenerateUUID())
req.Header.Set("repeatability-first-sent", time.Now().UTC().Format(http.TimeFormat)) req.Header.Set("repeatability-first-sent", time.Now().UTC().Format(http.TimeFormat))
client := &http.Client{} client := &http.Client{}

View File

@@ -21,7 +21,7 @@ import (
"time" "time"
"github.com/casdoor/casdoor/notification" "github.com/casdoor/casdoor/notification"
"github.com/google/uuid" "github.com/casdoor/casdoor/util"
) )
type PushMfa struct { type PushMfa struct {
@@ -111,7 +111,7 @@ func (mfa *PushMfa) sendPushNotification(title string, message string) error {
// Generate a unique challenge ID for this notification // Generate a unique challenge ID for this notification
// Note: In a full implementation, this would be stored in a cache/database // Note: In a full implementation, this would be stored in a cache/database
// to validate callbacks from the mobile app // to validate callbacks from the mobile app
mfa.challengeId = uuid.NewString() mfa.challengeId = util.GenerateUUID()
mfa.challengeExp = time.Now().Add(5 * time.Minute) // Challenge expires in 5 minutes mfa.challengeExp = time.Now().Add(5 * time.Minute) // Challenge expires in 5 minutes
// Get the notification provider // Get the notification provider

View File

@@ -31,8 +31,8 @@ import (
"time" "time"
"github.com/beevik/etree" "github.com/beevik/etree"
"github.com/casdoor/casdoor/util"
"github.com/golang-jwt/jwt/v5" "github.com/golang-jwt/jwt/v5"
"github.com/google/uuid"
saml "github.com/russellhaering/gosaml2" saml "github.com/russellhaering/gosaml2"
dsig "github.com/russellhaering/goxmldsig" dsig "github.com/russellhaering/goxmldsig"
) )
@@ -50,7 +50,7 @@ func NewSamlResponse(application *Application, user *User, host string, certific
samlResponse.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") samlResponse.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")
samlResponse.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") samlResponse.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
samlResponse.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") samlResponse.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema")
arId := uuid.New() arId := util.GenerateUUID()
samlResponse.CreateAttr("ID", fmt.Sprintf("_%s", arId)) samlResponse.CreateAttr("ID", fmt.Sprintf("_%s", arId))
samlResponse.CreateAttr("Version", "2.0") samlResponse.CreateAttr("Version", "2.0")
@@ -65,7 +65,7 @@ func NewSamlResponse(application *Application, user *User, host string, certific
assertion.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") assertion.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")
assertion.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") assertion.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
assertion.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") assertion.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema")
assertion.CreateAttr("ID", fmt.Sprintf("_%s", uuid.New())) assertion.CreateAttr("ID", fmt.Sprintf("_%s", util.GenerateUUID()))
assertion.CreateAttr("Version", "2.0") assertion.CreateAttr("Version", "2.0")
assertion.CreateAttr("IssueInstant", now) assertion.CreateAttr("IssueInstant", now)
assertion.CreateElement("saml:Issuer").SetText(host) assertion.CreateElement("saml:Issuer").SetText(host)
@@ -100,7 +100,7 @@ func NewSamlResponse(application *Application, user *User, host string, certific
} }
authnStatement := assertion.CreateElement("saml:AuthnStatement") authnStatement := assertion.CreateElement("saml:AuthnStatement")
authnStatement.CreateAttr("AuthnInstant", now) authnStatement.CreateAttr("AuthnInstant", now)
authnStatement.CreateAttr("SessionIndex", fmt.Sprintf("_%s", uuid.New())) authnStatement.CreateAttr("SessionIndex", fmt.Sprintf("_%s", util.GenerateUUID()))
authnStatement.CreateAttr("SessionNotOnOrAfter", expireTime) authnStatement.CreateAttr("SessionNotOnOrAfter", expireTime)
authnStatement.CreateElement("saml:AuthnContext").CreateElement("saml:AuthnContextClassRef").SetText("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport") authnStatement.CreateElement("saml:AuthnContext").CreateElement("saml:AuthnContextClassRef").SetText("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")
@@ -460,7 +460,7 @@ func NewSamlResponse11(application *Application, user *User, requestID string, h
samlResponse.CreateAttr("MajorVersion", "1") samlResponse.CreateAttr("MajorVersion", "1")
samlResponse.CreateAttr("MinorVersion", "1") samlResponse.CreateAttr("MinorVersion", "1")
responseID := uuid.New() responseID := util.GenerateUUID()
samlResponse.CreateAttr("ResponseID", fmt.Sprintf("_%s", responseID)) samlResponse.CreateAttr("ResponseID", fmt.Sprintf("_%s", responseID))
samlResponse.CreateAttr("InResponseTo", requestID) samlResponse.CreateAttr("InResponseTo", requestID)
@@ -476,7 +476,7 @@ func NewSamlResponse11(application *Application, user *User, requestID string, h
assertion.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:1.0:assertion") assertion.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:1.0:assertion")
assertion.CreateAttr("MajorVersion", "1") assertion.CreateAttr("MajorVersion", "1")
assertion.CreateAttr("MinorVersion", "1") assertion.CreateAttr("MinorVersion", "1")
assertion.CreateAttr("AssertionID", uuid.New().String()) assertion.CreateAttr("AssertionID", util.GenerateUUID())
assertion.CreateAttr("Issuer", host) assertion.CreateAttr("Issuer", host)
assertion.CreateAttr("IssueInstant", now) assertion.CreateAttr("IssueInstant", now)

View File

@@ -16,9 +16,7 @@ package object
import ( import (
"fmt" "fmt"
"math/rand"
"strings" "strings"
"time"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/xorm-io/core" "github.com/xorm-io/core"
@@ -234,8 +232,7 @@ func (site *Site) GetChallengeMap() map[string]string {
func (site *Site) GetHost() string { func (site *Site) GetHost() string {
if len(site.Hosts) != 0 { if len(site.Hosts) != 0 {
rand.Seed(time.Now().UnixNano()) return site.Hosts[util.RandomIntn(len(site.Hosts))]
return site.Hosts[rand.Intn(len(site.Hosts))]
} }
if site.Host != "" { if site.Host != "" {

View File

@@ -21,7 +21,7 @@ import (
"encoding/pem" "encoding/pem"
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"math/rand" "math"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -273,7 +273,7 @@ func GenerateCasToken(userId string, service string) (string, error) {
} }
} }
st := fmt.Sprintf("ST-%d", rand.Int()) st := fmt.Sprintf("ST-%d", util.RandomIntn(math.MaxInt))
stToServiceResponse.Store(st, &CasAuthenticationSuccessWrapper{ stToServiceResponse.Store(st, &CasAuthenticationSuccessWrapper{
AuthenticationSuccess: &authenticationSuccess, AuthenticationSuccess: &authenticationSuccess,
Service: service, Service: service,

View File

@@ -28,7 +28,6 @@ import (
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/google/uuid"
"github.com/xorm-io/core" "github.com/xorm-io/core"
) )
@@ -742,12 +741,7 @@ func createGuestUserToken(application *Application, clientSecret string, verifie
// generateGuestUsername generates a unique username for guest users // generateGuestUsername generates a unique username for guest users
func generateGuestUsername() string { func generateGuestUsername() string {
uid, err := uuid.NewRandom() return fmt.Sprintf("guest_%s", util.GenerateUUID())
if err != nil {
// Fallback to a timestamp-based unique ID if UUID generation fails
return fmt.Sprintf("guest_%d", time.Now().UnixNano())
}
return fmt.Sprintf("guest_%s", uid.String())
} }
// GetAuthorizationCodeToken // GetAuthorizationCodeToken

View File

@@ -15,10 +15,11 @@
package object package object
import ( import (
"crypto/rand"
"errors" "errors"
"fmt" "fmt"
"math" "math"
"math/rand" "math/big"
"net/url" "net/url"
"regexp" "regexp"
"strconv" "strconv"
@@ -476,10 +477,13 @@ func GetVerifyType(username string) (verificationCodeType string) {
var stdNums = []byte("0123456789") var stdNums = []byte("0123456789")
func getRandomCode(length int) string { func getRandomCode(length int) string {
var result []byte result := make([]byte, length)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
result = append(result, stdNums[r.Intn(len(stdNums))]) n, err := rand.Int(rand.Reader, big.NewInt(int64(len(stdNums))))
if err != nil {
panic(err)
}
result[i] = stdNums[n.Int64()]
} }
return string(result) return string(result)
} }

View File

@@ -14,7 +14,13 @@
package util package util
import "github.com/thanhpk/randstr" import (
"crypto/rand"
"math/big"
"github.com/google/uuid"
"github.com/thanhpk/randstr"
)
func GenerateClientId() string { func GenerateClientId() string {
return randstr.Hex(10) return randstr.Hex(10)
@@ -27,3 +33,57 @@ func GenerateClientSecret() string {
func GeneratePasswordSalt() string { func GeneratePasswordSalt() string {
return randstr.Hex(10) return randstr.Hex(10)
} }
// RandomIntn returns a cryptographically secure random int in [0, n).
func RandomIntn(n int) int {
val, err := rand.Int(rand.Reader, big.NewInt(int64(n)))
if err != nil {
panic(err)
}
return int(val.Int64())
}
// GenerateUUID returns a random UUID v4 string.
func GenerateUUID() string {
return uuid.NewString()
}
// RandomStringFromCharset returns a cryptographically secure random string
// of the given length drawn from charset.
func RandomStringFromCharset(charset string, length int) string {
result := make([]byte, length)
for i := range result {
result[i] = charset[RandomIntn(len(charset))]
}
return string(result)
}
func GetRandomName() string {
return RandomStringFromCharset("0123456789abcdefghijklmnopqrstuvwxyz", 6)
}
func generateRandomString(length int) (string, error) {
return RandomStringFromCharset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", length), nil
}
func GenerateTwoUniqueRandomStrings() (string, string, error) {
len1 := 16 + int(big.NewInt(17).Int64())
len2 := 16 + int(big.NewInt(17).Int64())
str1, err := generateRandomString(len1)
if err != nil {
return "", "", err
}
str2, err := generateRandomString(len2)
if err != nil {
return "", "", err
}
for str1 == str2 {
str2, err = generateRandomString(len2)
if err != nil {
return "", "", err
}
}
return str1, str2, nil
}

View File

@@ -20,8 +20,6 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"math/big"
"math/rand"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
@@ -30,7 +28,6 @@ import (
"time" "time"
"unicode" "unicode"
"github.com/google/uuid"
"github.com/nyaruka/phonenumbers" "github.com/nyaruka/phonenumbers"
) )
@@ -167,7 +164,7 @@ func GetSharedOrgFromApp(rawName string) (name string, organization string) {
} }
func GenerateId() string { func GenerateId() string {
return uuid.NewString() return GenerateUUID()
} }
func GenerateTimeId() string { func GenerateTimeId() string {
@@ -175,7 +172,7 @@ func GenerateTimeId() string {
tm := time.Unix(timestamp, 0) tm := time.Unix(timestamp, 0)
t := tm.Format("20060102_150405") t := tm.Format("20060102_150405")
random := uuid.NewString()[0:7] random := GenerateUUID()[0:7]
res := fmt.Sprintf("%s_%s", t, random) res := fmt.Sprintf("%s_%s", t, random)
return res return res
@@ -189,16 +186,6 @@ func GenerateSimpleTimeId() string {
return t return t
} }
func GetRandomName() string {
rand.Seed(time.Now().UnixNano())
const charset = "0123456789abcdefghijklmnopqrstuvwxyz"
result := make([]byte, 6)
for i := range result {
result[i] = charset[rand.Intn(len(charset))]
}
return string(result)
}
func GetId(owner, name string) string { func GetId(owner, name string) string {
return fmt.Sprintf("%s/%s", owner, name) return fmt.Sprintf("%s/%s", owner, name)
} }
@@ -355,7 +342,7 @@ func GetValueFromDataSourceName(key string, dataSourceName string) string {
func GetUsernameFromEmail(email string) string { func GetUsernameFromEmail(email string) string {
tokens := strings.Split(email, "@") tokens := strings.Split(email, "@")
if len(tokens) == 0 { if len(tokens) == 0 {
return uuid.NewString() return GenerateUUID()
} else { } else {
return tokens[0] return tokens[0]
} }
@@ -394,37 +381,3 @@ func StringToInterfaceArray2d(arrays [][]string) [][]interface{} {
} }
return interfaceArrays return interfaceArrays
} }
func generateRandomString(length int) (string, error) {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := range b {
var c byte
index := rand.Intn(len(charset))
c = charset[index]
b[i] = c
}
return string(b), nil
}
func GenerateTwoUniqueRandomStrings() (string, string, error) {
len1 := 16 + int(big.NewInt(17).Int64())
len2 := 16 + int(big.NewInt(17).Int64())
str1, err := generateRandomString(len1)
if err != nil {
return "", "", err
}
str2, err := generateRandomString(len2)
if err != nil {
return "", "", err
}
for str1 == str2 {
str2, err = generateRandomString(len2)
if err != nil {
return "", "", err
}
}
return str1, str2, nil
}