d1f7b3805b
feat(domain): V008 migration + Usuario with-methods + DomainException hierarchy [UDT-008]
2026-04-15 17:36:46 -03:00
0218d8d371
feat(api): migrar controllers admin a RequirePermission [UDT-006]
2026-04-15 16:34:32 -03:00
4866c4f21f
feat(api): ForbiddenProblemDetailsHandler 403 shape [UDT-006]
2026-04-15 16:27:36 -03:00
58d0df601f
feat(api): RequirePermissionAttribute + PermissionAuthorizationHandler [UDT-006]
2026-04-15 16:26:30 -03:00
cdb8dcd03c
feat(api): login response permisos desde RolPermiso [UDT-006]
2026-04-15 16:24:21 -03:00
1a864e9f8b
fix(app): validar formato codigo rol en GetRolPermisos [UDT-005]
...
Agrega GetRolPermisosQueryValidator con regex ^[a-z][a-z0-9_]*$ para
rechazar codigos invalidos con 400 en GET /api/v1/roles/{codigo}/permisos.
2026-04-15 15:56:49 -03:00
4913a35d06
feat(api): BATCH 5 - PermisosController + tests HTTP [UDT-005]
2026-04-15 15:42:03 -03:00
be2257a9bf
feat(infra): BATCH 4 - Permiso/RolPermiso repos Dapper + tests integracion [UDT-005]
2026-04-15 15:39:25 -03:00
704794a2e2
feat(app): BATCH 3 - handlers permisos con TDD [UDT-005]
2026-04-15 15:31:26 -03:00
7ddb71c24c
feat(domain): BATCH 2 - Permiso entity + catalogo const [UDT-005]
2026-04-15 15:31:20 -03:00
6f999b8fcd
feat(api): UDT-004 controller de roles + refactor validator UDT-003 a lookup dinamico
...
- RolesController /api/v1/roles CRUD admin-only: GET list, GET {codigo}, POST, PUT, DELETE (soft-delete con guard 409)
- ExceptionFilter: mapea RolNotFound (404), RolAlreadyExists (409), RolInUse (409)
- DI: registra 5 handlers de Roles (Application) y IRolRepository/RolRepository (Infrastructure)
- CreateUsuarioCommandValidator: reemplaza whitelist hardcoded por IRolRepository.ExistsActiveByCodigoAsync via MustAsync; constructor recibe (AuthOptions, IRolRepository)
- Tests: 202 verdes (173 application + 29 api). Nuevas: RolesEndpointTests (13 integration), CreateUsuarioCommandValidatorTests reescrito con NSubstitute mock, CreateUsuario_WithInactiveRol_Returns400 en Api.Tests
- Fix: ApiIntegration pasa de IClassFixture (N factories) a ICollectionFixture (1 factory shared) — evitaba ObjectDisposedException sobre RSABCrypt al compartir coleccion con multiples test classes
- tests/tests.runsettings: MaxCpuCount=1 para evitar race entre assemblies sobre SIGCM2_Test
2026-04-15 12:50:24 -03:00
34b714750a
feat(api): UDT-004 dominio + repositorio + application roles (tdd)
...
- Migraciones V003 (tabla Rol + 8 seeds canonicos) y V004 (drop CK + FK Usuario.Rol)
- Dominio: Rol entity + 3 excepciones (RolNotFound/AlreadyExists/InUse)
- Infraestructura: RolRepository (Dapper) con List/Get/ExistsActive/Add/Update/HasActiveUsuarios
- Application: CRUD queries y commands (List, Get, Create, Update, Deactivate) + validators (codigo regex ^[a-z][a-z0-9_]*$)
- Validator UDT-003: whitelist alineada a codigos canonicos (full IRolRepository lookup diferido a Phase 5.1)
- Tests: 169 application + 15 api (todos verdes). Respawn configurado para re-seedear Rol canonical post-reset.
- Estricto TDD: RED/GREEN/TRIANGULATE en todos los handlers nuevos.
2026-04-15 12:31:29 -03:00
bce591e63c
fix(auth): preserve JWT claim names in bearer middleware
...
JwtBearerOptions.MapInboundClaims defaulted to true, which mapped the
'sub' claim to ClaimTypes.NameIdentifier in HttpContext.User. Logout
endpoint read User.FindFirst("sub") and got null, returning 401 for
any authenticated caller.
Fix: set MapInboundClaims=false and pin NameClaimType="name" so the
JWT claims land in the principal with their original names, aligning
with how JwtService.GetPrincipalFromExpiredToken (used by refresh)
already consumes them.
Unblocks Login_Refresh_Logout_FullFlow integration test (15/15 green).
2026-04-15 11:03:15 -03:00
3d598faffc
feat(api): UDT-003 registro de usuarios — backend completo (Phases 1-6)
...
- Domain: Usuario.ForCreation factory, UsernameAlreadyExistsException, IUsuarioRepository extendido
- Application: CreateUsuarioCommand/Validator/Handler, UsuarioCreatedDto, AuthOptions password policy
- Infrastructure: UsuarioRepository.ExistsByUsernameAsync + AddAsync (INSERT OUTPUT INSERTED.Id), RoleClaimType="rol" en TokenValidationParameters
- Api: UsuariosController POST api/v1/users [Authorize(Roles="admin")], ExceptionFilter mapea UsernameAlreadyExistsException + SqlException 2627 → 409
- Tests (unit): 43 tests — 33 validator + 10 handler (107 total, green)
- Tests (integration): 7 tests CreateUsuarioEndpoint — 401/403/400/201/409/race/e2e (green)
- Fix: TestWebAppFactory.ConfigureTestServices reemplaza SqlConnectionFactory singleton con CS de test correcto
2026-04-15 10:47:48 -03:00
fd2ff8a802
feat(api): map InvalidRefreshTokenException and TokenReuseDetectedException to generic 401
2026-04-14 13:28:45 -03:00
8768067fdd
feat(api): add /refresh [AllowAnonymous] and /logout [Authorize] endpoints to AuthController
2026-04-14 13:28:45 -03:00
aed26e3de9
feat(infra): register RefreshTokenRepository, RefreshTokenGenerator, ClientContext and handlers in DI
2026-04-14 13:28:36 -03:00
cb4250f7b3
feat(infra): implement ClientContext for IP and UserAgent from IHttpContextAccessor
2026-04-14 13:28:35 -03:00
19ac807500
feat(infra): add RefreshTokenDays to JwtOptions and AuthOptions config
2026-04-14 13:28:35 -03:00
0c809da633
feat(infra): implement RefreshTokenRepository with Dapper and add GetByIdAsync to UsuarioRepository
2026-04-14 13:28:29 -03:00
d326dd87e0
feat(infra): implement RefreshTokenGenerator with cryptographic random bytes
2026-04-14 13:28:24 -03:00
c910ff2fc5
feat(infra): implement GetPrincipalFromExpiredToken in JwtService
2026-04-14 13:28:20 -03:00
8bbd2b6f2a
feat(app): update LoginCommandHandler to persist hashed refresh token on login
2026-04-14 13:28:16 -03:00
6c02197369
feat(app): implement LogoutCommand handler with idempotent revocation
2026-04-14 13:28:10 -03:00
f5e67b78a5
feat(app): implement RefreshCommand handler with token rotation and chain revocation
2026-04-14 13:28:06 -03:00
971f6f572f
feat(app): add IClientContext abstraction for IP and UserAgent
2026-04-14 13:17:12 -03:00
84006776b6
feat(app): add IRefreshTokenGenerator abstraction
2026-04-14 13:17:12 -03:00
802c89ffe5
feat(app): add IRefreshTokenRepository abstraction
2026-04-14 13:17:11 -03:00
ba6dffb137
feat(app): extend IJwtService with GetPrincipalFromExpiredToken
2026-04-14 13:17:11 -03:00
83c6a95ee2
feat(domain): add InvalidRefreshTokenException and TokenReuseDetectedException
2026-04-14 13:16:44 -03:00
aacfd29673
feat(domain): add TokenHasher SHA-256 base64url helper
2026-04-14 13:16:43 -03:00
99bb3364c3
feat(domain): add RefreshToken entity with factory methods and IsActive logic
2026-04-14 13:16:38 -03:00
9891f96618
feat(udt-001): api layer with AuthController, Program.cs and Serilog
2026-04-13 21:36:08 -03:00
ca57ce33b5
feat(udt-001): infrastructure (Dapper, BCrypt, JWT RS256, dispatcher)
2026-04-13 21:36:02 -03:00
8c26cd3ac5
feat(udt-001): application layer with LoginCommandHandler and ports
2026-04-13 21:36:01 -03:00
2111070c77
feat(udt-001): domain layer with Usuario entity
2026-04-13 21:36:00 -03:00
88ecaa2c7f
chore(udt-001): RSA key generation script
2026-04-13 21:35:56 -03:00