Checks / verify (push) Failing after 9m52s
统一单入口 Go 工程与前端依赖目录,增加后台供应商配置、候选审核、计划预算、成交冲正、持仓复盘和站内通知。接入策略版本、Python 回测、可配置 A 股公开行情及 zap 文件轮转日志,补充迁移、契约与验证。
93 lines
3.0 KiB
Go
93 lines
3.0 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.sundynix.cn/Blizzard/Veyra/internal/apperror"
|
|
"git.sundynix.cn/Blizzard/Veyra/internal/model"
|
|
)
|
|
|
|
type testRepository struct {
|
|
user model.User
|
|
credential model.Credential
|
|
session model.Session
|
|
createdSessions int
|
|
}
|
|
|
|
func (r *testRepository) CreateUser(_ context.Context, u model.User, c model.Credential) (model.User, error) {
|
|
r.user = u
|
|
r.credential = c
|
|
return u, nil
|
|
}
|
|
func (r *testRepository) FindCredential(_ context.Context, login string) (model.User, model.Credential, error) {
|
|
if login != r.credential.LoginName {
|
|
return model.User{}, model.Credential{}, apperror.ErrNotFound
|
|
}
|
|
return r.user, r.credential, nil
|
|
}
|
|
func (r *testRepository) CreateSession(_ context.Context, s model.Session, _ string) error {
|
|
r.session = s
|
|
r.createdSessions++
|
|
return nil
|
|
}
|
|
func (r *testRepository) FindSessionUser(_ context.Context, _, _ string, _ time.Time) (model.User, error) {
|
|
return r.user, nil
|
|
}
|
|
func (r *testRepository) RevokeSession(_ context.Context, _, _ string, _ time.Time) error { return nil }
|
|
func (r *testRepository) ListUsers(context.Context, int) ([]model.User, error) {
|
|
return []model.User{r.user}, nil
|
|
}
|
|
|
|
func TestPasswordAndSessionSecretsAreHashed(t *testing.T) {
|
|
ctx := context.Background()
|
|
repo := &testRepository{}
|
|
auth, err := NewAuthService(repo)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
password := "a-development-password"
|
|
if _, err := auth.ProvisionUser(ctx, " ADMIN ", password, "Admin", "ADMIN"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if repo.credential.PasswordHash == password || repo.credential.LoginName != "admin" {
|
|
t.Fatal("credential handling failed")
|
|
}
|
|
result, err := auth.Login(ctx, "admin", password, "admin")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(result.Token) != 43 || repo.session.TokenHash == result.Token || repo.session.TokenHash != TokenHash(result.Token) {
|
|
t.Fatal("raw session secret persisted")
|
|
}
|
|
if _, err := auth.Login(ctx, "admin", "incorrect-password", "admin"); !errors.Is(err, apperror.ErrUnauthenticated) {
|
|
t.Fatal("wrong password accepted")
|
|
}
|
|
if _, err := auth.Login(ctx, "admin", password, "app"); !errors.Is(err, apperror.ErrUnauthenticated) {
|
|
t.Fatal("admin credential used for app login")
|
|
}
|
|
if _, err := auth.Login(ctx, "missing", password, "admin"); !errors.Is(err, apperror.ErrUnauthenticated) {
|
|
t.Fatal("missing identity was disclosed")
|
|
}
|
|
if repo.createdSessions != 1 {
|
|
t.Fatal("failed login created a session")
|
|
}
|
|
repo.user.Status = "DISABLED"
|
|
if _, err := auth.Authenticate(ctx, result.Token, "admin"); !errors.Is(err, apperror.ErrUnauthenticated) {
|
|
t.Fatal("disabled user remained authenticated")
|
|
}
|
|
}
|
|
|
|
func TestUserCannotAuthenticateAsAdmin(t *testing.T) {
|
|
repo := &testRepository{user: model.User{Status: "ACTIVE", Role: "USER"}}
|
|
auth, err := NewAuthService(repo)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := auth.Authenticate(context.Background(), "1234567890123456789012345678901234567890123", "admin"); !errors.Is(err, apperror.ErrUnauthenticated) {
|
|
t.Fatal("user role passed admin authorization")
|
|
}
|
|
}
|