fix login

This commit is contained in:
David 2026-03-10 09:20:38 +01:00
parent b30c1147ea
commit 7dfb4e84f4
5 changed files with 51 additions and 42 deletions

View File

@ -132,7 +132,7 @@ pytest services/pii/tests/test_file.py::test_function
**Config override:** Any config key can be overridden via env var with the `VEYLANT_` prefix and `.``_` replacement. Example: `VEYLANT_SERVER_PORT=9090` overrides `server.port`. **Config override:** Any config key can be overridden via env var with the `VEYLANT_` prefix and `.``_` replacement. Example: `VEYLANT_SERVER_PORT=9090` overrides `server.port`.
**Auth config:** `auth.jwt_secret` (env: `VEYLANT_AUTH_JWT_SECRET`) and `auth.jwt_ttl_hours`. Login endpoint: `POST /v1/auth/login` (public). Dev credentials: `admin@veylant.dev` / `admin123`. Tokens are HS256-signed JWTs; users stored in `users` table with bcrypt password hashes (migration 000010). **Auth config:** `auth.jwt_secret` (env: `VEYLANT_AUTH_JWT_SECRET`) and `auth.jwt_ttl_hours`. Login endpoint: `POST /v1/auth/login` — public (no JWT required), CORS applied. Dev credentials: `admin@veylant.dev` / `admin123`. Tokens are HS256-signed JWTs; users stored in `users` table with bcrypt password hashes (migration 000010) and a `name TEXT` column (migration 000012). Login response includes `{token, user: {id, email, name, role, tenant_id, department}}`.
**Provider configs:** LLM provider API keys are stored encrypted (AES-256-GCM) in the `provider_configs` table (migration 000011). CRUD via `GET|POST /v1/admin/providers`, `PUT|DELETE|POST-test /v1/admin/providers/{id}`. Adapters hot-reload on save/update without proxy restart (`router.UpdateAdapter()` / `RemoveAdapter()`). **Provider configs:** LLM provider API keys are stored encrypted (AES-256-GCM) in the `provider_configs` table (migration 000011). CRUD via `GET|POST /v1/admin/providers`, `PUT|DELETE|POST-test /v1/admin/providers/{id}`. Adapters hot-reload on save/update without proxy restart (`router.UpdateAdapter()` / `RemoveAdapter()`).

View File

@ -293,53 +293,59 @@ func main() {
r.Get(cfg.Metrics.Path, promhttp.Handler().ServeHTTP) r.Get(cfg.Metrics.Path, promhttp.Handler().ServeHTTP)
} }
// Public login endpoint — must be registered before the auth middleware below.
loginHandler := auth.NewLoginHandler(db, cfg.Auth.JWTSecret, cfg.Auth.JWTTTLHours, logger) loginHandler := auth.NewLoginHandler(db, cfg.Auth.JWTSecret, cfg.Auth.JWTTTLHours, logger)
r.Post("/v1/auth/login", loginHandler.ServeHTTP)
r.Route("/v1", func(r chi.Router) { r.Route("/v1", func(r chi.Router) {
r.Use(middleware.CORS(cfg.Server.AllowedOrigins)) r.Use(middleware.CORS(cfg.Server.AllowedOrigins))
r.Use(middleware.Auth(jwtVerifier))
r.Use(middleware.RateLimit(rateLimiter))
r.Post("/chat/completions", proxyHandler.ServeHTTP)
// PII analyze endpoint for Playground (E8-11, Sprint 8). // Public — CORS applied, no auth required.
piiAnalyzeHandler := pii.NewAnalyzeHandler(piiClient, logger) r.Post("/auth/login", loginHandler.ServeHTTP)
r.Post("/pii/analyze", piiAnalyzeHandler.ServeHTTP)
// Admin API — routing policies + audit logs (Sprint 5 + Sprint 6) // Protected — JWT auth + tenant rate limit.
// + user management + provider status (Sprint 8). r.Group(func(r chi.Router) {
if routingEngine != nil { r.Use(middleware.Auth(jwtVerifier))
var adminHandler *admin.Handler r.Use(middleware.RateLimit(rateLimiter))
if auditLogger != nil {
adminHandler = admin.NewWithAudit( r.Post("/chat/completions", proxyHandler.ServeHTTP)
routing.NewPgStore(db, logger),
routingEngine.Cache(), // PII analyze endpoint for Playground (E8-11, Sprint 8).
auditLogger, piiAnalyzeHandler := pii.NewAnalyzeHandler(piiClient, logger)
logger, r.Post("/pii/analyze", piiAnalyzeHandler.ServeHTTP)
)
} else { // Admin API — routing policies + audit logs (Sprint 5 + Sprint 6)
adminHandler = admin.New( // + user management + provider status (Sprint 8).
routing.NewPgStore(db, logger), if routingEngine != nil {
routingEngine.Cache(), var adminHandler *admin.Handler
logger, if auditLogger != nil {
) adminHandler = admin.NewWithAudit(
routing.NewPgStore(db, logger),
routingEngine.Cache(),
auditLogger,
logger,
)
} else {
adminHandler = admin.New(
routing.NewPgStore(db, logger),
routingEngine.Cache(),
logger,
)
}
// Wire db, router, rate limiter, feature flags, and encryptor.
adminHandler.WithDB(db).WithRouter(providerRouter).WithRateLimiter(rateLimiter).WithFlagStore(flagStore).WithEncryptor(encryptor)
r.Route("/admin", adminHandler.Routes)
} }
// Wire db, router, rate limiter, feature flags, and encryptor.
adminHandler.WithDB(db).WithRouter(providerRouter).WithRateLimiter(rateLimiter).WithFlagStore(flagStore).WithEncryptor(encryptor)
r.Route("/admin", adminHandler.Routes)
}
// Compliance module — GDPR Art. 30 registry + AI Act classification + PDF reports (Sprint 9). // Compliance module — GDPR Art. 30 registry + AI Act classification + PDF reports (Sprint 9).
if db != nil { if db != nil {
compStore := compliance.NewPgStore(db, logger) compStore := compliance.NewPgStore(db, logger)
compHandler := compliance.New(compStore, logger). compHandler := compliance.New(compStore, logger).
WithAudit(auditLogger). WithAudit(auditLogger).
WithDB(db). WithDB(db).
WithTenantName(cfg.Server.TenantName) WithTenantName(cfg.Server.TenantName)
r.Route("/admin/compliance", compHandler.Routes) r.Route("/admin/compliance", compHandler.Routes)
logger.Info("compliance module started") logger.Info("compliance module started")
} }
})
}) })
// ── HTTP server ─────────────────────────────────────────────────────────── // ── HTTP server ───────────────────────────────────────────────────────────

View File

@ -70,7 +70,7 @@ func (h *LoginHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var u userInfo var u userInfo
var passwordHash string var passwordHash string
err := h.db.QueryRowContext(r.Context(), err := h.db.QueryRowContext(r.Context(),
`SELECT id, tenant_id, email, email, role, COALESCE(department,''), password_hash `SELECT id, tenant_id, email, COALESCE(name,''), role, COALESCE(department,''), password_hash
FROM users FROM users
WHERE email = $1 AND is_active = TRUE WHERE email = $1 AND is_active = TRUE
LIMIT 1`, LIMIT 1`,

View File

@ -1,6 +1,9 @@
-- Migration 000012: Add name column to users table. -- Migration 000012: Add name column to users table.
-- Migration 000001 created users without a name column; migration 000006 used -- Migration 000001 created users without a name column; migration 000006 used
-- CREATE TABLE IF NOT EXISTS which was a no-op since the table already existed. -- CREATE TABLE IF NOT EXISTS which was a no-op since the table already existed.
-- This migration adds the missing column retroactively. -- This migration adds the missing column retroactively and seeds existing users.
ALTER TABLE users ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT ''; ALTER TABLE users ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT '';
-- Seed name for the dev admin user created in migration 000001.
UPDATE users SET name = 'Admin Veylant' WHERE email = 'admin@veylant.dev' AND name = '';

BIN
proxy

Binary file not shown.