@@ -0,0 +1,92 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"veyra/services/api/internal/identity/domain"
|
||||
"veyra/services/api/internal/platform/apperror"
|
||||
)
|
||||
|
||||
type testRepository struct {
|
||||
user domain.User
|
||||
credential domain.Credential
|
||||
session domain.Session
|
||||
createdSessions int
|
||||
}
|
||||
|
||||
func (r *testRepository) CreateUser(_ context.Context, u domain.User, c domain.Credential) (domain.User, error) {
|
||||
r.user = u
|
||||
r.credential = c
|
||||
return u, nil
|
||||
}
|
||||
func (r *testRepository) FindCredential(_ context.Context, login string) (domain.User, domain.Credential, error) {
|
||||
if login != r.credential.LoginName {
|
||||
return domain.User{}, domain.Credential{}, apperror.ErrNotFound
|
||||
}
|
||||
return r.user, r.credential, nil
|
||||
}
|
||||
func (r *testRepository) CreateSession(_ context.Context, s domain.Session) error {
|
||||
r.session = s
|
||||
r.createdSessions++
|
||||
return nil
|
||||
}
|
||||
func (r *testRepository) FindSessionUser(_ context.Context, _, _ string, _ time.Time) (domain.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) ([]domain.User, error) {
|
||||
return []domain.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: domain.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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user