Ir al contenido

Arquitectura interna de Summit Auth

Esta página describe la implementación actual de Summit Auth. Es una referencia para mantenedores: los nombres de clases y tablas pueden cambiar y no sustituyen los contratos públicos documentados en las demás páginas de Summit Auth.

Summit Auth combina ASP.NET Core Identity para usuarios, roles y sesiones con OpenIddict para OAuth 2.0 y OpenID Connect. Entity Framework Core persiste el estado en PostgreSQL.

AuthorizationController implementa los flujos de autorización, token, UserInfo y cierre de sesión. Sobre esa base operan tres subsistemas relacionados:

  • Billing administra productos, planes, funcionalidades, suscripciones y pagos.
  • Organizations administra organizaciones, tenants, membresías y roles propios de cada organización.
  • ProductAccess representa el acceso efectivo de un usuario a un producto, ya sea personal o procedente de una organización.

El catálogo de permisos se almacena en PermissionDefinitions. Cada permiso se construye a partir de un subject y una acción y usa un valor estable con el formato {module}.{subject}.{action}, por ejemplo auth.users.read o api.billing.sync.

Las páginas y controladores protegidos usan esos valores mediante [Authorize(Policy = SummitPermissions.X)]. El PermissionAuthorizationPolicyProvider resuelve la política y valida los permisos activos del usuario. La portada del panel administrativo conserva la política AdminOnly; las áreas funcionales emplean permisos granulares.

Los permisos de roles Identity no se copian en la cookie de sesión. Se resuelven contra el almacenamiento de roles y se mantienen temporalmente en caché para evitar cookies demasiado grandes.

Los permisos organizacionales siguen una ruta distinta. Cada BillingOrganizationMembership referencia un OrganizationRole, y ese rol posee su propio conjunto de permisos mediante OrganizationRolePermission.

OrganizationAccessService.GetAccessAsync es la comprobación central. Solo devuelve acceso cuando la membresía y la organización están activas. Los servicios de organizaciones consultan este resultado directamente; no confían en permisos organizacionales copiados al access token.

La jerarquía comercial es:

BillingProduct
-> BillingPlan
-> BillingPlanFeature -> BillingFeature
-> BillingSubscription
-> ProductAccessAssignment
-> BillingProductGroup -> BillingProductGroupApplication (vía BillingProductClient)

BillingFeature es un catálogo global de funcionalidades. Un plan las incluye mediante BillingPlanFeature, que puede almacenar Value y Unit para cuotas como 50 GB; ambos quedan vacíos para funcionalidades binarias.

Un producto también puede poseer BillingProductGroup, un agrupador de autorización que se expone como claim groups a las aplicaciones cliente vinculadas al producto y al grupo. Las asignaciones del grupo a un usuario se guardan en UserProductGroupAssignment; las de una organización y las de una membresía en OrganizationProductGroupAssignment y OrganizationMemberProductGroupAssignment. EffectiveProductGroupService resuelve el conjunto efectivo de grupos durante la emisión de tokens.

Una suscripción puede pertenecer a un usuario o a una organización. El servicio BillingSubscriptionAccessSyncService reconcilia la suscripción y sus asignaciones hacia ProductAccess, que es el modelo de lectura usado durante la emisión y validación de tokens.

Un producto con RequiresOrganization solo acepta acceso procedente de una organización activa. Un otorgamiento personal puede seguir almacenado, pero no satisface el requisito de acceso de la aplicación.

Los pagos se coordinan mediante PaymentOrderService y la abstracción IPaymentGatewayProvider. La implementación disponible para PayPhone vive en PayPhonePaymentGatewayProvider. Las credenciales y respuestas completas del proveedor no deben registrarse en auditoría.

OrganizationsController ofrece lecturas autenticadas para aplicaciones cliente:

Endpoint Resultado
GET /api/organizations/{id} Datos de la organización, rol y permisos actuales del caller.
GET /api/organizations/{id}/products Suscripciones, producto, plan, funcionalidades y uso de puestos.
GET /api/organizations/{id}/products/{subscriptionId}/assignments Asignaciones por miembro para una suscripción.

El caller debe ser miembro activo. Una organización inexistente y una organización a la que el caller no pertenece producen 404, evitando revelar identificadores ajenos. En el endpoint de asignaciones, un miembro sin permisos administrativos solo puede consultar su propia fila.

Consulta APIs internas para los cuerpos de respuesta y los endpoints de sincronización.

La identidad se completa en AuthorizationController:

Responsabilidad Claims principales
Perfil given_name, family_name, preferred_username, picture, locale, zoneinfo y otros datos OIDC.
Roles role.
Acceso personal plan, product_access, product_plan.
Acceso organizacional organization_product_access.
Contexto de organización organization_id, tenant_id, organization_role.
Grupos de producto groups, resuelto por EffectiveProductGroupService para la aplicación cliente autenticada.
Sesión sid.

Los claims permission y organization_permission no se emiten en los tokens. Se calculan en /connect/userinfo, lo que evita que access tokens y cookies crezcan con el número de permisos asignados.

summit_email indica si el dominio del correo del usuario coincide con el dominio configurado en alguna organización activa donde mantiene una membresía activa. No identifica por sí solo la organización seleccionada.

Consulta Claims y permisos para el contrato que deben consumir las aplicaciones.

El panel separa lectura y administración mediante permisos granulares. Sus áreas principales administran:

  • clientes OpenIddict, scopes, autorizaciones y tokens;
  • usuarios, roles y definiciones de claims;
  • subjects, acciones y definiciones de permisos;
  • accesos manuales a productos;
  • productos, funcionalidades, planes, suscripciones y organizaciones;
  • registros de auditoría.

Las altas y modificaciones privilegiadas deben llamar a AuditLogger.LogAsync. Los payloads de auditoría nunca deben contener contraseñas, secretos de cliente, tokens, códigos de autorización ni códigos de recuperación.

AuditValueRedactor enmascara valores sensibles al mostrar el detalle de un evento, pero no sustituye la disciplina del punto de escritura: un secreto no debe llegar al registro original.

  • La exigencia global de PKCE en OpenIddict no reemplaza la configuración y validación individual de cada cliente; verifica ambas antes de asumir que todos los flujos lo requieren.
  • Los destinos de claims dependen de ClaimDefinitions y de los scopes solicitados. Una definición incorrecta puede exponer u omitir un claim.
  • ProductAccess es un modelo efectivo y aplanado. La procedencia personal u organizacional se determina desde ProductAccessAssignment.
  • Las funcionalidades se resuelven desde el plan vigente; cambiar la relación BillingPlanFeature cambia las respuestas posteriores sin copiar datos a la suscripción.
  • Las APIs internas son superficie privilegiada. Conserva autenticación Bearer, permisos específicos, idempotencia y auditoría sin secretos al modificarlas.