From 09ac5c8df5a49d5638f66a8efe5d1ea3587a5a4f Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Thu, 13 Nov 2025 21:27:32 -0300 Subject: [PATCH] Add user login and select organization audit logs --- .../ee/services/audit-log/audit-log-types.ts | 31 ++++++- .../src/services/auth/auth-login-service.ts | 82 +++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index f91692a14..2dc683b58 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -365,6 +365,8 @@ export enum EventType { LOAD_PROJECT_KMS_BACKUP = "load-project-kms-backup", ORG_ADMIN_ACCESS_PROJECT = "org-admin-accessed-project", ORG_ADMIN_BYPASS_SSO = "org-admin-bypassed-sso", + USER_LOGIN = "user-login", + USER_SELECT_ORGANIZATION = "user-select-organization", CREATE_CERTIFICATE_TEMPLATE = "create-certificate-template", UPDATE_CERTIFICATE_TEMPLATE = "update-certificate-template", DELETE_CERTIFICATE_TEMPLATE = "delete-certificate-template", @@ -2657,6 +2659,31 @@ interface OrgAdminBypassSSOEvent { metadata: Record; // no metadata yet } +interface UserLoginEvent { + type: EventType.USER_LOGIN; + metadata: { + email: string; + userAgent: string; + ipAddress: string; + authMethod: string; + organizationId?: string; + organizationName?: string; + authProvider?: string; + }; +} + +interface UserSelectOrganizationEvent { + type: EventType.USER_SELECT_ORGANIZATION; + metadata: { + email: string; + userAgent: string; + ipAddress: string; + organizationId: string; + organizationName: string; + authMethod: string; + }; +} + interface CreateCertificateTemplateEstConfig { type: EventType.CREATE_CERTIFICATE_TEMPLATE_EST_CONFIG; metadata: { @@ -4535,4 +4562,6 @@ export type Event = | UpdateCertificateRenewalConfigEvent | DisableCertificateRenewalConfigEvent | AutomatedRenewCertificate - | AutomatedRenewCertificateFailed; + | AutomatedRenewCertificateFailed + | UserLoginEvent + | UserSelectOrganizationEvent; diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts index b9c759703..1c06dcb96 100644 --- a/backend/src/services/auth/auth-login-service.ts +++ b/backend/src/services/auth/auth-login-service.ts @@ -454,6 +454,32 @@ export const authLoginServiceFactory = ({ }); } + if (organizationId) { + await auditLogService.createAuditLog({ + orgId: organizationId, + ipAddress: ip, + userAgent, + userAgentType: getUserAgentType(userAgent), + actor: { + type: ActorType.USER, + metadata: { + email: userEnc.email, + userId: userEnc.userId, + username: userEnc.username + } + }, + event: { + type: EventType.USER_LOGIN, + metadata: { + email, + userAgent, + ipAddress: ip, + authMethod + } + } + }); + } + return { tokens: { accessToken: token.access, @@ -646,6 +672,32 @@ export const authLoginServiceFactory = ({ } } + await auditLogService.createAuditLog({ + orgId: organizationId, + ipAddress, + userAgent, + userAgentType: getUserAgentType(userAgent), + actor: { + type: ActorType.USER, + metadata: { + email: user.email, + userId: user.id, + username: user.username + } + }, + event: { + type: EventType.USER_SELECT_ORGANIZATION, + metadata: { + email: user.email || "", + userAgent, + ipAddress, + organizationId, + organizationName: selectedOrg.name, + authMethod: decodedToken.authMethod + } + } + }); + return { ...tokens, user, @@ -1039,6 +1091,36 @@ export const authLoginServiceFactory = ({ organizationId }); + if (organizationId) { + await auditLogService.createAuditLog({ + orgId: organizationId, + ipAddress: ip, + userAgent, + userAgentType: getUserAgentType(userAgent), + actor: { + type: ActorType.USER, + metadata: { + email: userEnc.email, + userId: userEnc.userId, + username: userEnc.username + } + }, + event: { + type: EventType.USER_LOGIN, + metadata: { + email, + userAgent, + ipAddress: ip, + authMethod: decodedProviderToken.authMethod, + organizationId, + ...(isAuthMethodSaml(decodedProviderToken.authMethod) && { + authProvider: decodedProviderToken.authMethod + }) + } + } + }); + } + return { token, isMfaEnabled: false, user: userEnc, decodedProviderToken } as const; };