fix(auth): restrict demo seed users to dev/test environments
Main no longer creates fixed-password demo accounts and legacy anonymous fallback is limited to explicit dev/test in-memory fixtures.
This commit is contained in:
@@ -29,6 +29,7 @@ func TestPasswordCrypto(t *testing.T) {
|
||||
|
||||
func TestAuthStoreMemory_Operations(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Env: "dev",
|
||||
AdminUsername: "superadmin",
|
||||
AdminPassword: "admin-test-pass-999",
|
||||
AuthRegistrationEnabled: true,
|
||||
|
||||
+38
-32
@@ -76,40 +76,46 @@ func NewMemoryStore(cfg *config.Config) *MemoryStore {
|
||||
}
|
||||
store.nextID = 2
|
||||
|
||||
// 2. 初始化标准测试用户 (统一初始密码: 123456)
|
||||
defaultPassHash, _ := HashPassword("123456")
|
||||
seedUsers := []struct {
|
||||
id int64
|
||||
username string
|
||||
name string
|
||||
roleID string
|
||||
position string
|
||||
dept string
|
||||
employeeID string
|
||||
}{
|
||||
{2, "zhanggong", "张工", "role-engineer", "方案工程师", "骨科耗材研发组", "RD-001"},
|
||||
{3, "lizhuguan", "李主管", "role-tech-lead", "技术主管", "骨科耗材研发组", "RD-002"},
|
||||
{4, "wangzong", "王总监", "role-director", "研发总监", "研发中心", "RD-003"},
|
||||
{5, "guest", "访客", "role-guest", "待指派", "外协中心", "EXT-999"},
|
||||
// 2. 标准测试用户仅 dev/test 环境种子化;生产不得携带固定密码演示账号
|
||||
env := ""
|
||||
if cfg != nil {
|
||||
env = cfg.Env
|
||||
}
|
||||
|
||||
for _, su := range seedUsers {
|
||||
store.users[su.id] = &UserAccount{
|
||||
ID: su.id,
|
||||
Username: su.username,
|
||||
Name: su.name,
|
||||
PasswordHash: defaultPassHash,
|
||||
Status: StatusActive,
|
||||
MustChangePassword: false,
|
||||
RoleID: su.roleID,
|
||||
Position: su.position,
|
||||
Department: su.dept,
|
||||
EmployeeID: su.employeeID,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
if env == "dev" || env == "test" || env == "" {
|
||||
defaultPassHash, _ := HashPassword("123456")
|
||||
seedUsers := []struct {
|
||||
id int64
|
||||
username string
|
||||
name string
|
||||
roleID string
|
||||
position string
|
||||
dept string
|
||||
employeeID string
|
||||
}{
|
||||
{2, "zhanggong", "张工", "role-engineer", "方案工程师", "骨科耗材研发组", "RD-001"},
|
||||
{3, "lizhuguan", "李主管", "role-tech-lead", "技术主管", "骨科耗材研发组", "RD-002"},
|
||||
{4, "wangzong", "王总监", "role-director", "研发总监", "研发中心", "RD-003"},
|
||||
{5, "guest", "访客", "role-guest", "待指派", "外协中心", "EXT-999"},
|
||||
}
|
||||
if su.id >= store.nextID {
|
||||
store.nextID = su.id + 1
|
||||
|
||||
for _, su := range seedUsers {
|
||||
store.users[su.id] = &UserAccount{
|
||||
ID: su.id,
|
||||
Username: su.username,
|
||||
Name: su.name,
|
||||
PasswordHash: defaultPassHash,
|
||||
Status: StatusActive,
|
||||
MustChangePassword: false,
|
||||
RoleID: su.roleID,
|
||||
Position: su.position,
|
||||
Department: su.dept,
|
||||
EmployeeID: su.employeeID,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
if su.id >= store.nextID {
|
||||
store.nextID = su.id + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/auth"
|
||||
"chat-agent-system/internal/config"
|
||||
)
|
||||
|
||||
func TestMemoryStore_DevEnvSeedsDemoUsers(t *testing.T) {
|
||||
cfg := &config.Config{Env: "dev", AdminPassword: "admin-test-pass-999"}
|
||||
store := auth.NewMemoryStore(cfg)
|
||||
ctx := context.Background()
|
||||
|
||||
user, err := store.GetUserByUsername(ctx, "zhanggong")
|
||||
if err != nil {
|
||||
t.Fatalf("expected zhanggong in dev env: %v", err)
|
||||
}
|
||||
if user.RoleID != "role-engineer" {
|
||||
t.Fatalf("unexpected role: %s", user.RoleID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemoryStore_MainEnvNoSeedUsers(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Env: "main",
|
||||
AdminPassword: "secure-main-admin-pass-xyz",
|
||||
}
|
||||
store := auth.NewMemoryStore(cfg)
|
||||
ctx := context.Background()
|
||||
|
||||
if _, err := store.GetUserByUsername(ctx, "zhanggong"); err == nil {
|
||||
t.Fatal("main env must not seed zhanggong demo user")
|
||||
}
|
||||
if _, err := store.GetUserByUsername(ctx, "guest"); err == nil {
|
||||
t.Fatal("main env must not seed guest demo user")
|
||||
}
|
||||
admin, err := store.GetUserByUsername(ctx, cfg.AdminUsername)
|
||||
if err != nil && cfg.AdminUsername == "" {
|
||||
admin, err = store.GetUserByUsername(ctx, "admin")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("admin account should still exist: %v", err)
|
||||
}
|
||||
if admin.RoleID != "role-admin" {
|
||||
t.Fatalf("expected role-admin, got %s", admin.RoleID)
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,14 @@ import (
|
||||
)
|
||||
|
||||
func (s *Server) allowLegacyTestPrincipal() bool {
|
||||
return s.cfg != nil && s.cfg.AllowInMemory && s.cfg.ContextDbHost == ""
|
||||
if s.cfg == nil {
|
||||
return false
|
||||
}
|
||||
env := s.cfg.Env
|
||||
if env != "dev" && env != "test" && env != "" {
|
||||
return false
|
||||
}
|
||||
return s.cfg.AllowInMemory && s.cfg.ContextDbHost == ""
|
||||
}
|
||||
|
||||
func isPublicRoute(method, path string) bool {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/auth"
|
||||
@@ -47,7 +46,7 @@ func withBearerAuth(req *http.Request, token string) {
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
|
||||
// withUserIDAuth 为请求附加 X-User-ID(用户必须已存在于 auth store)。
|
||||
func withUserIDAuth(req *http.Request, userID int64) {
|
||||
req.Header.Set("X-User-ID", strconv.FormatInt(userID, 10))
|
||||
// withBearerToken 为请求附加 Authorization Bearer Token(Phase 0:不再使用 X-User-ID)。
|
||||
func withBearerToken(req *http.Request, token string) {
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user