forked from baron/baron-sso
99 lines
2.2 KiB
Go
99 lines
2.2 KiB
Go
package handler
|
|
|
|
import (
|
|
"baron-sso-backend/internal/domain"
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"testing"
|
|
"unicode"
|
|
)
|
|
|
|
// 정책을 받아 필수 요구사항을 모두 포함하는 비밀번호를 생성한다.
|
|
func generatePasswordFromPolicy(policy *domain.PasswordPolicy) string {
|
|
minLen := policy.MinLength
|
|
if minLen < 8 {
|
|
minLen = 12 // 안전한 기본값
|
|
}
|
|
|
|
pwd := make([]rune, 0, minLen)
|
|
|
|
if policy.Lowercase {
|
|
pwd = append(pwd, 'a')
|
|
}
|
|
if policy.Uppercase {
|
|
pwd = append(pwd, 'B')
|
|
}
|
|
if policy.Number {
|
|
pwd = append(pwd, '3')
|
|
}
|
|
if policy.NonAlphanumeric {
|
|
pwd = append(pwd, '!')
|
|
}
|
|
|
|
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
|
for len(pwd) < minLen {
|
|
pwd = append(pwd, rune(charset[randomInt(len(charset))]))
|
|
}
|
|
|
|
// 섞어서 예측 가능성을 낮춘다.
|
|
for i := range pwd {
|
|
j := randomInt(len(pwd))
|
|
pwd[i], pwd[j] = pwd[j], pwd[i]
|
|
}
|
|
return string(pwd)
|
|
}
|
|
|
|
func randomInt(n int) int {
|
|
if n <= 0 {
|
|
return 0
|
|
}
|
|
var b [8]byte
|
|
if _, err := rand.Read(b[:]); err != nil {
|
|
return 0
|
|
}
|
|
return int(binary.BigEndian.Uint64(b[:]) % uint64(n))
|
|
}
|
|
|
|
func TestGeneratePasswordUsesNonAlphanumericRequirement(t *testing.T) {
|
|
policy := &domain.PasswordPolicy{
|
|
MinLength: 8,
|
|
Lowercase: true,
|
|
Uppercase: true,
|
|
Number: true,
|
|
NonAlphanumeric: true,
|
|
}
|
|
|
|
pwd := generatePasswordFromPolicy(policy)
|
|
|
|
if len(pwd) < policy.MinLength {
|
|
t.Fatalf("비밀번호 길이가 정책 최소 길이 미만: got %d, want >= %d", len(pwd), policy.MinLength)
|
|
}
|
|
|
|
var hasLower, hasUpper, hasNumber, hasSymbol bool
|
|
for _, r := range pwd {
|
|
switch {
|
|
case unicode.IsLower(r):
|
|
hasLower = true
|
|
case unicode.IsUpper(r):
|
|
hasUpper = true
|
|
case unicode.IsNumber(r):
|
|
hasNumber = true
|
|
case !unicode.IsLetter(r) && !unicode.IsNumber(r):
|
|
hasSymbol = true
|
|
}
|
|
}
|
|
|
|
if policy.Lowercase && !hasLower {
|
|
t.Fatalf("소문자 요구사항 미충족: %q", pwd)
|
|
}
|
|
if policy.Uppercase && !hasUpper {
|
|
t.Fatalf("대문자 요구사항 미충족: %q", pwd)
|
|
}
|
|
if policy.Number && !hasNumber {
|
|
t.Fatalf("숫자 요구사항 미충족: %q", pwd)
|
|
}
|
|
if policy.NonAlphanumeric && !hasSymbol {
|
|
t.Fatalf("비영문자 요구사항 미충족: %q", pwd)
|
|
}
|
|
}
|