|
| 1 | +# ADR-0077: Frontera de Autorizacion para Gestion del Portal del Tenant y Politica de Scope |
| 2 | + |
| 3 | +**Estado:** Accepted |
| 4 | +**Fecha:** 2026-06-02 |
| 5 | +**Decision Owner:** Architecture |
| 6 | +**Relacionados:** |
| 7 | +- [ADR-0071: Motor de Grafo de Autorizacion](./0071-auth-graph-engine.es.md) |
| 8 | +- [ADR-0072: Resolucion Dinamica del Metodo de Autenticacion](./0072-dynamic-auth-method-resolution.es.md) |
| 9 | +- [ADR-0060: Estrategia de AOP para Concerns Transversales](./0060-aop-cross-cutting-concern-strategy.es.md) |
| 10 | +- [ADR-0075: Bandeja de Aprobacion de Onboarding y Autorizacion por Alcance](./0075-onboarding-approval-inbox-and-scope-based-authorization.es.md) |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## Contexto |
| 15 | + |
| 16 | +UMS debe soportar dos responsabilidades de autorizacion distintas que pueden confundirse facilmente si se implementan con el mismo mecanismo: |
| 17 | + |
| 18 | +| Flujo | Proposito | Regla rectora | |
| 19 | +|---|---|---| |
| 20 | +| Gestion del portal | Un usuario del tenant inicia sesion en el portal de UMS para ver o administrar sus propios datos permitidos | Debe autorizarse por scope de tenant, roles, permisos y `Tenant.IsManagementOwner` | |
| 21 | +| API publica externa | Un cliente downstream se autentica contra la API publica de autenticacion | Debe respetar el metodo de autenticacion configurado del tenant y el grafo de autorizacion | |
| 22 | + |
| 23 | +Historicamente, el AOP transversal ha parecido un lugar conveniente para imponer checks de acceso porque ya esta unido a los command handlers. Esa es la frontera equivocada para una decision de seguridad. La autorizacion es critica para el negocio, debe permanecer explicita y debe ser facil de inspeccionar en tests y code reviews. |
| 24 | + |
| 25 | +Por eso el flujo del portal necesita una frontera interna de gestion separada del flujo de autenticacion de la API publica. La frontera de gestion debe ser consciente del tenant, leer el flag de propiedad del tenant desde el modelo de dominio y evitar que cualquier tenant opere fuera de su scope. |
| 26 | + |
| 27 | +--- |
| 28 | + |
| 29 | +## Decision |
| 30 | + |
| 31 | +UMS tratara la autorizacion de gestion del portal como una politica explicita de aplicacion, no como una preocupacion de AOP. |
| 32 | + |
| 33 | +| Area de Decision | Eleccion | |
| 34 | +|---|---| |
| 35 | +| Scope del portal | Introducir `AuthAccessScope.PortalManagement` para el acceso al portal y `AuthAccessScope.ExternalApi` para la API publica de autenticacion. | |
| 36 | +| Regla de gestion interna | Usar `ITenantScopePolicy` para validar propiedad del tenant y scope antes de ejecutar comandos mutantes del portal. | |
| 37 | +| Propiedad del tenant | Usar `Tenant.IsManagementOwner` como el flag autoritativo que habilita acciones de gestion interna para un tenant. | |
| 38 | +| Autenticacion API externa | Mantener `IAuthMethodResolver.ResolveAsync(tenantId, scope)` como el resolvedor explicito para la API publica de autenticacion. | |
| 39 | +| Uso de AOP | Reservar AOP para logging, tracing, enrichment de auditoria y otros concerns transversales. Nunca usarlo como frontera principal de autorizacion. | |
| 40 | +| Scope de consultas | Permitir que los query handlers usen la policy para resolver el scope visible, pero mantener la autorizacion de escritura explicita en el boundary del comando. | |
| 41 | + |
| 42 | +--- |
| 43 | + |
| 44 | +## Modelo de Arquitectura |
| 45 | + |
| 46 | +```mermaid |
| 47 | +flowchart TB |
| 48 | + subgraph Presentation["Presentation"] |
| 49 | + P1["AuthEndpoints"] |
| 50 | + P2["ClientAuthEndpoints"] |
| 51 | + P3["Endpoints de gestion"] |
| 52 | + P4["GraphQL / Middleware"] |
| 53 | + end |
| 54 | +
|
| 55 | + subgraph Application["Application"] |
| 56 | + A1["AuthMethodResolverService"] |
| 57 | + A2["TenantScopePolicy"] |
| 58 | + A3["Command handlers"] |
| 59 | + A4["Query handlers"] |
| 60 | + A5["Aspectos AOP de logging"] |
| 61 | + end |
| 62 | +
|
| 63 | + subgraph Domain["Domain"] |
| 64 | + D1["Tenant"] |
| 65 | + D2["AuthAccessScope"] |
| 66 | + D3["AuthorizationGraph"] |
| 67 | + D4["Invariantes de negocio"] |
| 68 | + end |
| 69 | +
|
| 70 | + subgraph Infrastructure["Infrastructure"] |
| 71 | + I1["TenantRepository"] |
| 72 | + I2["Proveedores de configuracion"] |
| 73 | + I3["Seeders / migraciones"] |
| 74 | + end |
| 75 | +
|
| 76 | + P1 --> A1 |
| 77 | + P2 --> A1 |
| 78 | + P3 --> A2 |
| 79 | + P3 --> A3 |
| 80 | + P4 --> A4 |
| 81 | + A1 --> D2 |
| 82 | + A2 --> D1 |
| 83 | + A3 --> D1 |
| 84 | + A4 --> D1 |
| 85 | + A1 --> I2 |
| 86 | + A2 --> I1 |
| 87 | + I1 --> D1 |
| 88 | + I2 --> A1 |
| 89 | + A5 -. solo concern transversal .-> A3 |
| 90 | + A5 -. solo concern transversal .-> A4 |
| 91 | + A3 --> D3 |
| 92 | +``` |
| 93 | + |
| 94 | +```mermaid |
| 95 | +sequenceDiagram |
| 96 | + participant User as Usuario del portal |
| 97 | + participant Portal as Portal UMS |
| 98 | + participant Handler as Command handler |
| 99 | + participant Policy as TenantScopePolicy |
| 100 | + participant Tenant as Agregado Tenant |
| 101 | +
|
| 102 | + User->>Portal: Inicia sesion en el portal de UMS |
| 103 | + Portal->>Handler: AuthenticateUserCommand(PortalManagement) |
| 104 | + Handler-->>Portal: Sesion + grafo |
| 105 | +
|
| 106 | + User->>Portal: Crea o modifica un recurso del tenant |
| 107 | + Portal->>Handler: Comando mutante |
| 108 | + Handler->>Policy: EnsureManagementOwnerScopeAsync(tenantId) |
| 109 | + Policy->>Tenant: Cargar el tenant e inspeccionar IsManagementOwner |
| 110 | + Tenant-->>Policy: true / false |
| 111 | + Policy-->>Handler: Permitido / denegado |
| 112 | + Handler-->>Portal: Resultado |
| 113 | +``` |
| 114 | + |
| 115 | +--- |
| 116 | + |
| 117 | +## Por Que Esta Decision |
| 118 | + |
| 119 | +1. Mantiene las decisiones de seguridad explicitas en la capa de aplicacion. |
| 120 | +2. Evita convertir AOP en un motor de autorizacion oculto. |
| 121 | +3. Alinea la gestion del portal con la propiedad del tenant en vez de mezclarla con el flujo publico de resolucion de IDP. |
| 122 | +4. Preserva la testabilidad porque las decisiones de scope pueden cubrirse con pruebas unitarias directas. |
| 123 | +5. Mantiene intacto el flujo de la API externa para clientes downstream. |
| 124 | +6. Reduce el riesgo de que el acceso al portal y la autenticacion externa se influyan accidentalmente. |
| 125 | + |
| 126 | +--- |
| 127 | + |
| 128 | +## Alternativas Consideradas |
| 129 | + |
| 130 | +| Alternativa | Decision | Motivo | |
| 131 | +|---|---|---| |
| 132 | +| Hacer cumplir el acceso al tenant en aspectos AOP | Rechazada | Las reglas de seguridad quedarian implicitas y mas dificiles de auditar. | |
| 133 | +| Hacer cumplir el acceso al tenant solo en middleware | Rechazada | Middleware es demasiado temprano y demasiado grueso para varias reglas de negocio. | |
| 134 | +| Mezclar la gestion del portal y la autenticacion externa en un solo flujo | Rechazada | Los dos casos de uso tienen fronteras de confianza y reglas de negocio distintas. | |
| 135 | +| Guardar la capacidad de gestion fuera de `Tenant` | Rechazada | La propiedad del tenant debe ser la fuente de verdad para el scope de gestion interna. | |
| 136 | + |
| 137 | +--- |
| 138 | + |
| 139 | +## Consecuencias |
| 140 | + |
| 141 | +### Positivas |
| 142 | + |
| 143 | +- Las reglas de acceso del portal son faciles de encontrar en la capa de aplicacion. |
| 144 | +- Las pruebas de autorizacion siguen siendo enfocadas y legibles. |
| 145 | +- La propiedad de gestion del tenant es visible en el modelo de dominio. |
| 146 | +- La API externa sigue respetando la configuracion de IDP especifica del tenant. |
| 147 | + |
| 148 | +### Compromisos |
| 149 | + |
| 150 | +- Algunos handlers deben llamar explicitamente a la policy en vez de depender de un interceptor global. |
| 151 | +- La base de codigo necesita disciplina para mantener AOP limitado a concerns transversales. |
| 152 | +- Un tenant marcado como management owner sigue requiriendo checks de rol y permiso para cada operacion. |
| 153 | + |
| 154 | +--- |
| 155 | + |
| 156 | +## Notas de Implementacion |
| 157 | + |
| 158 | +| Area | Guia | |
| 159 | +|---|---| |
| 160 | +| Commands | Los comandos mutantes del portal deben validar `ITenantScopePolicy` antes de cualquier escritura. | |
| 161 | +| Queries | Los query handlers pueden usar la policy para resolver el scope visible, pero nunca para saltarse la autorizacion. | |
| 162 | +| Auth | Usar `AuthAccessScope.PortalManagement` para el login del portal y `AuthAccessScope.ExternalApi` para la API publica de autenticacion. | |
| 163 | +| Domain | Mantener `Tenant.IsManagementOwner` como la fuente de verdad para la capacidad de gestion interna. | |
| 164 | +| AOP | Usar `LoggerAspect` y aspectos relacionados solo para instrumentacion, no para conceder acceso. | |
| 165 | +| Trazabilidad | Enlazar este ADR desde historias funcionales y documentacion de dominio que hablen de gestion del portal del tenant. | |
| 166 | + |
| 167 | +--- |
| 168 | + |
0 commit comments