diff --git a/lib/events/api.go b/lib/events/api.go index ad6fa69ac17a9..6e186be754862 100644 --- a/lib/events/api.go +++ b/lib/events/api.go @@ -790,6 +790,9 @@ const ( IntegrationDeleteEvent = "integration.delete" ) +// Add an entry to eventsMap in lib/events/events_test.go when you add +// a new event name here. + const ( // MaxChunkBytes defines the maximum size of a session stream chunk that // can be requested via AuditLog.GetSessionChunk(). Set to 5MB diff --git a/lib/events/codes.go b/lib/events/codes.go index 50f0d56147a93..7580518dc90bd 100644 --- a/lib/events/codes.go +++ b/lib/events/codes.go @@ -39,7 +39,8 @@ type Event struct { // - Suffix code with one of these letters: I (info), W (warn), E (error). // // After defining an event code, make sure to keep -// `web/packages/teleport/src/services/audit/types.ts` in sync. +// `web/packages/teleport/src/services/audit/types.ts` in sync and add an +// entry in the `eventsMap` in `lib/events/events_test.go`. const ( // UserLocalLoginCode is the successful local user login event code. UserLocalLoginCode = "T1000I" diff --git a/lib/events/dynamic.go b/lib/events/dynamic.go index bac9b583b46fc..f1f48a40dd5c2 100644 --- a/lib/events/dynamic.go +++ b/lib/events/dynamic.go @@ -385,24 +385,31 @@ func FromEventFields(fields EventFields) (events.AuditEvent, error) { case UnknownEvent: e = &events.Unknown{} - case CassandraBatchEventCode: + case DatabaseSessionCassandraBatchEvent: e = &events.CassandraBatch{} - case CassandraRegisterEventCode: + case DatabaseSessionCassandraRegisterEvent: e = &events.CassandraRegister{} - case CassandraPrepareEventCode: + case DatabaseSessionCassandraPrepareEvent: e = &events.CassandraPrepare{} - case CassandraExecuteEventCode: + case DatabaseSessionCassandraExecuteEvent: e = &events.CassandraExecute{} - case DiscoveryConfigCreateCode: + case DiscoveryConfigCreateEvent: e = &events.DiscoveryConfigCreate{} - case DiscoveryConfigUpdateCode: + case DiscoveryConfigUpdateEvent: e = &events.DiscoveryConfigUpdate{} - case DiscoveryConfigDeleteCode: + case DiscoveryConfigDeleteEvent: e = &events.DiscoveryConfigDelete{} - case DiscoveryConfigDeleteAllCode: + case DiscoveryConfigDeleteAllEvent: e = &events.DiscoveryConfigDeleteAll{} + case IntegrationCreateEvent: + e = &events.IntegrationCreate{} + case IntegrationUpdateEvent: + e = &events.IntegrationUpdate{} + case IntegrationDeleteEvent: + e = &events.IntegrationDelete{} + default: log.Errorf("Attempted to convert dynamic event of unknown type %q into protobuf event.", eventType) unknown := &events.Unknown{} diff --git a/lib/events/events_test.go b/lib/events/events_test.go index 4f8a9817a1dbd..2f6a240698897 100644 --- a/lib/events/events_test.go +++ b/lib/events/events_test.go @@ -20,6 +20,7 @@ package events import ( "encoding/json" + "fmt" "reflect" "testing" "time" @@ -30,6 +31,190 @@ import ( "github.com/gravitational/teleport/lib/utils" ) +// eventsMap maps event names to event types for testing. Be sure to update +// this map if you add a new event type. +var eventsMap = map[string]apievents.AuditEvent{ + SessionPrintEvent: &apievents.SessionPrint{}, + SessionStartEvent: &apievents.SessionStart{}, + SessionEndEvent: &apievents.SessionEnd{}, + SessionUploadEvent: &apievents.SessionUpload{}, + SessionJoinEvent: &apievents.SessionJoin{}, + SessionLeaveEvent: &apievents.SessionLeave{}, + SessionDataEvent: &apievents.SessionData{}, + ClientDisconnectEvent: &apievents.ClientDisconnect{}, + UserLoginEvent: &apievents.UserLogin{}, + UserDeleteEvent: &apievents.UserDelete{}, + UserCreateEvent: &apievents.UserCreate{}, + UserUpdatedEvent: &apievents.UserUpdate{}, + UserPasswordChangeEvent: &apievents.UserPasswordChange{}, + AccessRequestCreateEvent: &apievents.AccessRequestCreate{}, + AccessRequestReviewEvent: &apievents.AccessRequestCreate{}, + AccessRequestUpdateEvent: &apievents.AccessRequestCreate{}, + AccessRequestResourceSearch: &apievents.AccessRequestResourceSearch{}, + BillingCardCreateEvent: &apievents.BillingCardCreate{}, + BillingCardUpdateEvent: &apievents.BillingCardCreate{}, + BillingCardDeleteEvent: &apievents.BillingCardDelete{}, + BillingInformationUpdateEvent: &apievents.BillingInformationUpdate{}, + ResetPasswordTokenCreateEvent: &apievents.UserTokenCreate{}, + ExecEvent: &apievents.Exec{}, + SubsystemEvent: &apievents.Subsystem{}, + X11ForwardEvent: &apievents.X11Forward{}, + PortForwardEvent: &apievents.PortForward{}, + AuthAttemptEvent: &apievents.AuthAttempt{}, + SCPEvent: &apievents.SCP{}, + ResizeEvent: &apievents.Resize{}, + SessionCommandEvent: &apievents.SessionCommand{}, + SessionDiskEvent: &apievents.SessionDisk{}, + SessionNetworkEvent: &apievents.SessionNetwork{}, + RoleCreatedEvent: &apievents.RoleCreate{}, + RoleUpdatedEvent: &apievents.RoleUpdate{}, + RoleDeletedEvent: &apievents.RoleDelete{}, + TrustedClusterCreateEvent: &apievents.TrustedClusterCreate{}, + TrustedClusterDeleteEvent: &apievents.TrustedClusterDelete{}, + TrustedClusterTokenCreateEvent: &apievents.TrustedClusterTokenCreate{}, //nolint:staticcheck // SA1019. We want to test every event type, even if they're deprecated. + ProvisionTokenCreateEvent: &apievents.ProvisionTokenCreate{}, + GithubConnectorCreatedEvent: &apievents.GithubConnectorCreate{}, + GithubConnectorUpdatedEvent: &apievents.GithubConnectorUpdate{}, + GithubConnectorDeletedEvent: &apievents.GithubConnectorDelete{}, + OIDCConnectorCreatedEvent: &apievents.OIDCConnectorCreate{}, + OIDCConnectorUpdatedEvent: &apievents.OIDCConnectorUpdate{}, + OIDCConnectorDeletedEvent: &apievents.OIDCConnectorDelete{}, + SAMLConnectorCreatedEvent: &apievents.SAMLConnectorCreate{}, + SAMLConnectorUpdatedEvent: &apievents.SAMLConnectorUpdate{}, + SAMLConnectorDeletedEvent: &apievents.SAMLConnectorDelete{}, + SessionRejectedEvent: &apievents.SessionReject{}, + AppSessionStartEvent: &apievents.AppSessionStart{}, + AppSessionEndEvent: &apievents.AppSessionEnd{}, + AppSessionChunkEvent: &apievents.AppSessionChunk{}, + AppSessionRequestEvent: &apievents.AppSessionRequest{}, + AppSessionDynamoDBRequestEvent: &apievents.AppSessionDynamoDBRequest{}, + AppCreateEvent: &apievents.AppCreate{}, + AppUpdateEvent: &apievents.AppUpdate{}, + AppDeleteEvent: &apievents.AppDelete{}, + DatabaseCreateEvent: &apievents.DatabaseCreate{}, + DatabaseUpdateEvent: &apievents.DatabaseUpdate{}, + DatabaseDeleteEvent: &apievents.DatabaseDelete{}, + DatabaseSessionStartEvent: &apievents.DatabaseSessionStart{}, + DatabaseSessionEndEvent: &apievents.DatabaseSessionEnd{}, + DatabaseSessionQueryEvent: &apievents.DatabaseSessionQuery{}, + DatabaseSessionQueryFailedEvent: &apievents.DatabaseSessionQuery{}, + DatabaseSessionMalformedPacketEvent: &apievents.DatabaseSessionMalformedPacket{}, + DatabaseSessionPermissionsUpdateEvent: &apievents.DatabasePermissionUpdate{}, + DatabaseSessionUserCreateEvent: &apievents.DatabaseUserCreate{}, + DatabaseSessionUserDeactivateEvent: &apievents.DatabaseUserDeactivate{}, + DatabaseSessionPostgresParseEvent: &apievents.PostgresParse{}, + DatabaseSessionPostgresBindEvent: &apievents.PostgresBind{}, + DatabaseSessionPostgresExecuteEvent: &apievents.PostgresExecute{}, + DatabaseSessionPostgresCloseEvent: &apievents.PostgresClose{}, + DatabaseSessionPostgresFunctionEvent: &apievents.PostgresFunctionCall{}, + DatabaseSessionMySQLStatementPrepareEvent: &apievents.MySQLStatementPrepare{}, + DatabaseSessionMySQLStatementExecuteEvent: &apievents.MySQLStatementExecute{}, + DatabaseSessionMySQLStatementSendLongDataEvent: &apievents.MySQLStatementSendLongData{}, + DatabaseSessionMySQLStatementCloseEvent: &apievents.MySQLStatementClose{}, + DatabaseSessionMySQLStatementResetEvent: &apievents.MySQLStatementReset{}, + DatabaseSessionMySQLStatementFetchEvent: &apievents.MySQLStatementFetch{}, + DatabaseSessionMySQLStatementBulkExecuteEvent: &apievents.MySQLStatementBulkExecute{}, + DatabaseSessionMySQLInitDBEvent: &apievents.MySQLInitDB{}, + DatabaseSessionMySQLCreateDBEvent: &apievents.MySQLCreateDB{}, + DatabaseSessionMySQLDropDBEvent: &apievents.MySQLDropDB{}, + DatabaseSessionMySQLShutDownEvent: &apievents.MySQLShutDown{}, + DatabaseSessionMySQLProcessKillEvent: &apievents.MySQLProcessKill{}, + DatabaseSessionMySQLDebugEvent: &apievents.MySQLDebug{}, + DatabaseSessionMySQLRefreshEvent: &apievents.MySQLRefresh{}, + DatabaseSessionSQLServerRPCRequestEvent: &apievents.SQLServerRPCRequest{}, + DatabaseSessionElasticsearchRequestEvent: &apievents.ElasticsearchRequest{}, + DatabaseSessionOpenSearchRequestEvent: &apievents.OpenSearchRequest{}, + DatabaseSessionDynamoDBRequestEvent: &apievents.DynamoDBRequest{}, + KubeRequestEvent: &apievents.KubeRequest{}, + MFADeviceAddEvent: &apievents.MFADeviceAdd{}, + MFADeviceDeleteEvent: &apievents.MFADeviceDelete{}, + DeviceEvent: &apievents.DeviceEvent{}, + DeviceCreateEvent: &apievents.DeviceEvent2{}, + DeviceDeleteEvent: &apievents.DeviceEvent2{}, + DeviceUpdateEvent: &apievents.DeviceEvent2{}, + DeviceEnrollEvent: &apievents.DeviceEvent2{}, + DeviceAuthenticateEvent: &apievents.DeviceEvent2{}, + DeviceEnrollTokenCreateEvent: &apievents.DeviceEvent2{}, + DeviceWebTokenCreateEvent: &apievents.DeviceEvent2{}, + DeviceAuthenticateConfirmEvent: &apievents.DeviceEvent2{}, + LockCreatedEvent: &apievents.LockCreate{}, + LockDeletedEvent: &apievents.LockDelete{}, + RecoveryCodeGeneratedEvent: &apievents.RecoveryCodeGenerate{}, + RecoveryCodeUsedEvent: &apievents.RecoveryCodeUsed{}, + RecoveryTokenCreateEvent: &apievents.UserTokenCreate{}, + PrivilegeTokenCreateEvent: &apievents.UserTokenCreate{}, + WindowsDesktopSessionStartEvent: &apievents.WindowsDesktopSessionStart{}, + WindowsDesktopSessionEndEvent: &apievents.WindowsDesktopSessionEnd{}, + DesktopClipboardSendEvent: &apievents.DesktopClipboardSend{}, + DesktopClipboardReceiveEvent: &apievents.DesktopClipboardReceive{}, + SessionConnectEvent: &apievents.SessionConnect{}, + AccessRequestDeleteEvent: &apievents.AccessRequestDelete{}, + CertificateCreateEvent: &apievents.CertificateCreate{}, + RenewableCertificateGenerationMismatchEvent: &apievents.RenewableCertificateGenerationMismatch{}, + SFTPEvent: &apievents.SFTP{}, + UpgradeWindowStartUpdateEvent: &apievents.UpgradeWindowStartUpdate{}, + SessionRecordingAccessEvent: &apievents.SessionRecordingAccess{}, + SSMRunEvent: &apievents.SSMRun{}, + KubernetesClusterCreateEvent: &apievents.KubernetesClusterCreate{}, + KubernetesClusterUpdateEvent: &apievents.KubernetesClusterUpdate{}, + KubernetesClusterDeleteEvent: &apievents.KubernetesClusterDelete{}, + DesktopSharedDirectoryStartEvent: &apievents.DesktopSharedDirectoryStart{}, + DesktopSharedDirectoryReadEvent: &apievents.DesktopSharedDirectoryRead{}, + DesktopSharedDirectoryWriteEvent: &apievents.DesktopSharedDirectoryWrite{}, + BotJoinEvent: &apievents.BotJoin{}, + InstanceJoinEvent: &apievents.InstanceJoin{}, + BotCreateEvent: &apievents.BotCreate{}, + BotUpdateEvent: &apievents.BotUpdate{}, + BotDeleteEvent: &apievents.BotDelete{}, + LoginRuleCreateEvent: &apievents.LoginRuleCreate{}, + LoginRuleDeleteEvent: &apievents.LoginRuleDelete{}, + SAMLIdPAuthAttemptEvent: &apievents.SAMLIdPAuthAttempt{}, + SAMLIdPServiceProviderCreateEvent: &apievents.SAMLIdPServiceProviderCreate{}, + SAMLIdPServiceProviderUpdateEvent: &apievents.SAMLIdPServiceProviderUpdate{}, + SAMLIdPServiceProviderDeleteEvent: &apievents.SAMLIdPServiceProviderDelete{}, + SAMLIdPServiceProviderDeleteAllEvent: &apievents.SAMLIdPServiceProviderDeleteAll{}, + OktaGroupsUpdateEvent: &apievents.OktaResourcesUpdate{}, + OktaApplicationsUpdateEvent: &apievents.OktaResourcesUpdate{}, + OktaSyncFailureEvent: &apievents.OktaSyncFailure{}, + OktaAssignmentProcessEvent: &apievents.OktaAssignmentResult{}, + OktaAssignmentCleanupEvent: &apievents.OktaAssignmentResult{}, + OktaUserSyncEvent: &apievents.OktaUserSync{}, + OktaAccessListSyncEvent: &apievents.OktaAccessListSync{}, + AccessGraphAccessPathChangedEvent: &apievents.AccessPathChanged{}, + AccessListCreateEvent: &apievents.AccessListCreate{}, + AccessListUpdateEvent: &apievents.AccessListUpdate{}, + AccessListDeleteEvent: &apievents.AccessListDelete{}, + AccessListReviewEvent: &apievents.AccessListReview{}, + AccessListMemberCreateEvent: &apievents.AccessListMemberCreate{}, + AccessListMemberUpdateEvent: &apievents.AccessListMemberUpdate{}, + AccessListMemberDeleteEvent: &apievents.AccessListMemberDelete{}, + AccessListMemberDeleteAllForAccessListEvent: &apievents.AccessListMemberDeleteAllForAccessList{}, + SecReportsAuditQueryRunEvent: &apievents.AuditQueryRun{}, + SecReportsReportRunEvent: &apievents.SecurityReportRun{}, + ExternalAuditStorageEnableEvent: &apievents.ExternalAuditStorageEnable{}, + ExternalAuditStorageDisableEvent: &apievents.ExternalAuditStorageDisable{}, + CreateMFAAuthChallengeEvent: &apievents.CreateMFAAuthChallenge{}, + ValidateMFAAuthResponseEvent: &apievents.ValidateMFAAuthResponse{}, + SPIFFESVIDIssuedEvent: &apievents.SPIFFESVIDIssued{}, + AuthPreferenceUpdateEvent: &apievents.AuthPreferenceUpdate{}, + ClusterNetworkingConfigUpdateEvent: &apievents.ClusterNetworkingConfigUpdate{}, + SessionRecordingConfigUpdateEvent: &apievents.SessionRecordingConfigUpdate{}, + AccessGraphSettingsUpdateEvent: &apievents.AccessGraphSettingsUpdate{}, + DatabaseSessionSpannerRPCEvent: &apievents.SpannerRPC{}, + UnknownEvent: &apievents.Unknown{}, + DatabaseSessionCassandraBatchEvent: &apievents.CassandraBatch{}, + DatabaseSessionCassandraRegisterEvent: &apievents.CassandraRegister{}, + DatabaseSessionCassandraPrepareEvent: &apievents.CassandraPrepare{}, + DatabaseSessionCassandraExecuteEvent: &apievents.CassandraExecute{}, + DiscoveryConfigCreateEvent: &apievents.DiscoveryConfigCreate{}, + DiscoveryConfigUpdateEvent: &apievents.DiscoveryConfigUpdate{}, + DiscoveryConfigDeleteEvent: &apievents.DiscoveryConfigDelete{}, + DiscoveryConfigDeleteAllEvent: &apievents.DiscoveryConfigDeleteAll{}, + IntegrationCreateEvent: &apievents.IntegrationCreate{}, + IntegrationUpdateEvent: &apievents.IntegrationUpdate{}, + IntegrationDeleteEvent: &apievents.IntegrationDelete{}, +} + // TestJSON tests JSON marshal events func TestJSON(t *testing.T) { type testCase struct { @@ -776,3 +961,24 @@ func TestJSON(t *testing.T) { }) } } + +// TestEvents tests that all events can be converted and processed correctly. +func TestEvents(t *testing.T) { + t.Parallel() + + for eventName, eventType := range eventsMap { + t.Run(fmt.Sprintf("%s OneOf", eventName), func(t *testing.T) { + converted, err := apievents.ToOneOf(eventType) + require.NoError(t, err, "failed to convert event type to OneOf, is the event type added to api/types/events/oneof.go?") + auditEvent, err := apievents.FromOneOf(*converted) + require.NoError(t, err, "failed to convert OneOf back to an Audit event") + require.IsType(t, eventType, auditEvent, "FromOneOf did not convert the event type correctly") + }) + + t.Run(fmt.Sprintf("%s EventFields", eventName), func(t *testing.T) { + auditEvent, err := FromEventFields(EventFields{EventType: eventName}) + require.NoError(t, err, "failed to convert EventFields to an Audit event, is the event type added to lib/events/dynamic.go?") + require.IsType(t, eventType, auditEvent, "FromEventFields did not convert the event type correctly") + }) + } +}