package password import ( "strings" "testing" ) func TestEncodeSSHA(t *testing.T) { const plain = "correct horse battery staple" encoded, err := EncodeSSHA(plain) if err != nil { t.Fatalf("编码失败: %v", err) } if !strings.HasPrefix(encoded, "{SSHA}") { t.Errorf("结果应以 {SSHA} 开头,实际: %q", encoded) } // 关键性质:明文绝不能出现在结果里。 // slapd 不会自动哈希 Modify 写入的 userPassword,因此这一步是 // 密码不落明文存储的唯一保障。 if strings.Contains(encoded, plain) { t.Errorf("编码结果中出现了明文密码: %q", encoded) } if !VerifySSHA(encoded, plain) { t.Errorf("正确密码校验失败: %q", encoded) } if VerifySSHA(encoded, plain+"x") { t.Errorf("错误密码不应通过校验") } } func TestEncodeSSHASaltIsRandom(t *testing.T) { const plain = "same-password" a, err := EncodeSSHA(plain) if err != nil { t.Fatalf("编码失败: %v", err) } b, err := EncodeSSHA(plain) if err != nil { t.Fatalf("编码失败: %v", err) } // 随机盐应让同一密码产生不同哈希,避免相同密码在目录中可被关联识别。 if a == b { t.Errorf("同一密码两次编码结果相同,说明盐未随机化: %q", a) } if !VerifySSHA(a, plain) || !VerifySSHA(b, plain) { t.Errorf("带随机盐的两个哈希都应能校验通过") } } func TestVerifySSHARejectsMalformed(t *testing.T) { cases := []struct { name string encoded string }{ {"空字符串", ""}, {"缺少前缀", "abcdef"}, {"前缀但非法 base64", "{SSHA}!!!not-base64!!!"}, {"长度不足以容纳哈希", "{SSHA}YWJj"}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { if VerifySSHA(c.encoded, "whatever") { t.Errorf("畸形输入 %q 不应校验通过", c.encoded) } }) } } func TestRandom(t *testing.T) { a, err := Random() if err != nil { t.Fatalf("生成失败: %v", err) } b, err := Random() if err != nil { t.Fatalf("生成失败: %v", err) } if a == b { t.Errorf("两次生成的随机密码相同: %q", a) } if len(a) < 20 { t.Errorf("随机密码过短(%d 字符),强度不足", len(a)) } }