[MM-29296] model/user: add lock to source (#16054)

* model/user: add lock to source

* guard rand creation with locking

* use locked random

* remove assignment

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
This commit is contained in:
Ibrahim Serdar Acikgoz
2020-11-18 13:26:18 +03:00
committed by GitHub
parent 50e29cb47a
commit b30acfdee6
2 changed files with 31 additions and 9 deletions

View File

@@ -14,6 +14,7 @@ import (
"regexp"
"sort"
"strings"
"sync"
"time"
"unicode/utf8"
@@ -890,7 +891,22 @@ func UsersWithGroupsAndCountFromJson(data io.Reader) *UsersWithGroupsAndCount {
return uwg
}
var passwordRandomSource = rand.NewSource(time.Now().Unix())
type lockedRand struct {
mu sync.Mutex
rn *rand.Rand
}
func (r *lockedRand) Intn(n int) int {
r.mu.Lock()
m := r.rn.Intn(n)
r.mu.Unlock()
return m
}
var passwordRandom = lockedRand{
rn: rand.New(rand.NewSource(time.Now().Unix())),
}
var passwordSpecialChars = "!$%^&*(),."
var passwordNumbers = "0123456789"
var passwordUpperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -898,16 +914,14 @@ var passwordLowerCaseLetters = "abcdefghijklmnopqrstuvwxyz"
var passwordAllChars = passwordSpecialChars + passwordNumbers + passwordUpperCaseLetters + passwordLowerCaseLetters
func GeneratePassword(minimumLength int) string {
r := rand.New(passwordRandomSource)
// Make sure we are guaranteed at least one of each type to meet any possible password complexity requirements.
password := string([]rune(passwordUpperCaseLetters)[r.Intn(len(passwordUpperCaseLetters))]) +
string([]rune(passwordNumbers)[r.Intn(len(passwordNumbers))]) +
string([]rune(passwordLowerCaseLetters)[r.Intn(len(passwordLowerCaseLetters))]) +
string([]rune(passwordSpecialChars)[r.Intn(len(passwordSpecialChars))])
password := string([]rune(passwordUpperCaseLetters)[passwordRandom.Intn(len(passwordUpperCaseLetters))]) +
string([]rune(passwordNumbers)[passwordRandom.Intn(len(passwordNumbers))]) +
string([]rune(passwordLowerCaseLetters)[passwordRandom.Intn(len(passwordLowerCaseLetters))]) +
string([]rune(passwordSpecialChars)[passwordRandom.Intn(len(passwordSpecialChars))])
for len(password) < minimumLength {
i := r.Intn(len(passwordAllChars))
i := passwordRandom.Intn(len(passwordAllChars))
password = password + string([]rune(passwordAllChars)[i])
}

View File

@@ -353,7 +353,9 @@ func TestUserSlice(t *testing.T) {
}
func TestGeneratePassword(t *testing.T) {
passwordRandomSource = rand.NewSource(12345)
passwordRandom = lockedRand{
rn: rand.New(rand.NewSource(12345)),
}
t.Run("Should be the minimum length or 4, whichever is less", func(t *testing.T) {
password1 := GeneratePassword(5)
@@ -372,4 +374,10 @@ func TestGeneratePassword(t *testing.T) {
assert.Contains(t, []rune(passwordLowerCaseLetters), []rune(password)[2])
assert.Contains(t, []rune(passwordSpecialChars), []rune(password)[3])
})
t.Run("Should not fail on concurrent calls", func(t *testing.T) {
for i := 0; i < 10; i++ {
go GeneratePassword(10)
}
})
}