feat(auth): implement user and device authentication
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cmroubao/backend-api/internal/platform/assetstore"
|
||||
"cmroubao/backend-api/internal/platform/database"
|
||||
@@ -210,6 +211,32 @@ func TestAdminAPIAssetAndTaskLifecycle(t *testing.T) {
|
||||
canceled,
|
||||
)
|
||||
}
|
||||
canceledDetailResponse := performAdminRequest(
|
||||
t,
|
||||
router,
|
||||
http.MethodGet,
|
||||
"/api/v1/tasks/"+taskID,
|
||||
"",
|
||||
nil,
|
||||
"",
|
||||
)
|
||||
var canceledDetail map[string]any
|
||||
decodeResponse(t, canceledDetailResponse, &canceledDetail)
|
||||
events, _ := canceledDetail["events"].([]any)
|
||||
if canceledDetailResponse.Code != http.StatusOK || len(events) != 2 {
|
||||
t.Fatalf(
|
||||
"canceled detail status/body = %d / %#v",
|
||||
canceledDetailResponse.Code,
|
||||
canceledDetail,
|
||||
)
|
||||
}
|
||||
for _, value := range events {
|
||||
event, _ := value.(map[string]any)
|
||||
if event["actor_user_id"] !=
|
||||
"00000000-0000-4000-8000-000000000099" {
|
||||
t.Fatalf("event actor = %#v", event)
|
||||
}
|
||||
}
|
||||
|
||||
secondCancel := performAdminRequest(
|
||||
t,
|
||||
@@ -229,7 +256,7 @@ func TestAdminAPIAssetAndTaskLifecycle(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminRoutesRejectNonLoopbackRequests(t *testing.T) {
|
||||
func TestAdminRoutesRejectRequestsWithoutAdminSession(t *testing.T) {
|
||||
router := newAdminIntegrationRouter(t)
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/tasks", nil)
|
||||
request.RemoteAddr = "192.0.2.10:3210"
|
||||
@@ -237,7 +264,7 @@ func TestAdminRoutesRejectNonLoopbackRequests(t *testing.T) {
|
||||
|
||||
router.ServeHTTP(response, request)
|
||||
|
||||
if response.Code != http.StatusForbidden {
|
||||
if response.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("status = %d, body = %s", response.Code, response.Body.String())
|
||||
}
|
||||
var body map[string]any
|
||||
@@ -275,7 +302,7 @@ func TestAdminAssetUploadRequiresIdempotencyKey(t *testing.T) {
|
||||
|
||||
type emptyAdminWeb struct{}
|
||||
|
||||
func (emptyAdminWeb) Register(gin.IRoutes) {}
|
||||
func (emptyAdminWeb) RegisterProtected(gin.IRoutes) {}
|
||||
|
||||
func newAdminIntegrationRouter(t *testing.T) http.Handler {
|
||||
t.Helper()
|
||||
@@ -292,6 +319,18 @@ func newAdminIntegrationRouter(t *testing.T) http.Handler {
|
||||
if _, err := runner.Up(ctx); err != nil {
|
||||
t.Fatalf("migration.Up() error = %v", err)
|
||||
}
|
||||
now := time.Now().UTC().Format(time.RFC3339Nano)
|
||||
if _, err := db.ExecContext(
|
||||
ctx,
|
||||
`INSERT INTO users (
|
||||
id, username, password_hash, role, is_active, created_at, updated_at
|
||||
) VALUES (?, 'admin', 'test-only-hash', 'ADMIN', 1, ?, ?)`,
|
||||
"00000000-0000-4000-8000-000000000099",
|
||||
now,
|
||||
now,
|
||||
); err != nil {
|
||||
t.Fatalf("seed admin user: %v", err)
|
||||
}
|
||||
repositories, err := repository.New(db)
|
||||
if err != nil {
|
||||
t.Fatalf("repository.New() error = %v", err)
|
||||
@@ -318,9 +357,11 @@ func newAdminIntegrationRouter(t *testing.T) http.Handler {
|
||||
t.Fatalf("NewAdminRouteRegistrar() error = %v", err)
|
||||
}
|
||||
router, err := NewRouter(RouterDependencies{
|
||||
Database: db,
|
||||
RegisterAdminRoutes: registrar,
|
||||
LogEvent: discardEvent,
|
||||
Database: db,
|
||||
RegisterPublicRoutes: discardRoutes,
|
||||
RegisterAdminRoutes: registrar,
|
||||
AdminSessions: allowAdminAuthenticator{},
|
||||
LogEvent: discardEvent,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NewRouter() error = %v", err)
|
||||
@@ -375,7 +416,18 @@ func performAdminRequest(
|
||||
) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
request := httptest.NewRequest(method, target, body)
|
||||
request.RemoteAddr = "127.0.0.1:3210"
|
||||
request.AddCookie(&http.Cookie{
|
||||
Name: "cmroubao_admin_session",
|
||||
Value: "test-session",
|
||||
})
|
||||
if method != http.MethodGet && method != http.MethodHead {
|
||||
const csrfToken = "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE"
|
||||
request.AddCookie(&http.Cookie{
|
||||
Name: "cmroubao_admin_csrf",
|
||||
Value: csrfToken,
|
||||
})
|
||||
request.Header.Set("X-CSRF-Token", csrfToken)
|
||||
}
|
||||
if contentType != "" {
|
||||
request.Header.Set("Content-Type", contentType)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user