mirror of
https://dev.azure.com/schwarzit/schwarzit.stackit-public/_git/audit-go
synced 2026-02-08 00:57:24 +00:00
665 lines
24 KiB
Go
665 lines
24 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"buf.build/go/protovalidate"
|
|
"github.com/Azure/go-amqp"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"go.opentelemetry.io/otel"
|
|
|
|
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1"
|
|
internalAuditApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/internal/audit/api"
|
|
pkgAuditCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/audit/common"
|
|
pkgMessagingApi "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/api"
|
|
pkgMessagingCommon "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/common"
|
|
pkgMessagingTest "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/pkg/messaging/test"
|
|
)
|
|
|
|
func TestLegacyAuditApi(t *testing.T) {
|
|
|
|
// Specify test timeout
|
|
ctx, cancelFn := context.WithTimeout(context.Background(), 120*time.Second)
|
|
defer cancelFn()
|
|
|
|
// Start solace docker container
|
|
solaceContainer, err := pkgMessagingTest.NewSolaceContainer(context.Background())
|
|
assert.NoError(t, err)
|
|
defer solaceContainer.Stop()
|
|
|
|
// Instantiate the messaging api
|
|
amqpApi, err := pkgMessagingApi.NewAmqpApi(pkgMessagingCommon.AmqpConnectionPoolConfig{
|
|
Parameters: pkgMessagingCommon.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
|
PoolSize: 1,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
// Validator
|
|
validator, err := protovalidate.New()
|
|
assert.NoError(t, err)
|
|
|
|
topicSubscriptionTopicPattern := "stackit-platform/t/swz/audit-log/>"
|
|
|
|
// Check that event-type data-access is rejected as it is currently
|
|
// not supported by downstream services
|
|
t.Run("reject data access event", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
// Create the queue and topic subscription in solace
|
|
queueName := "org-reject-data-access-legacy"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-rejected"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
|
event.LogName = strings.Replace(event.LogName, string(pkgAuditCommon.EventTypeAdminActivity), string(pkgAuditCommon.EventTypeDataAccess), 1)
|
|
|
|
// Log the event to solace
|
|
assert.ErrorIs(t, auditApi.Log(
|
|
ctx,
|
|
event,
|
|
auditV1.Visibility_VISIBILITY_PUBLIC,
|
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
|
), pkgAuditCommon.ErrUnsupportedEventTypeDataAccess)
|
|
})
|
|
|
|
// Check logging of organization events
|
|
t.Run("Log public organization event", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
// Create the queue and topic subscription in solace
|
|
queueName := "org-event-public-legacy"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-created"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
|
|
|
// Log the event to solace
|
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
|
assert.NoError(t, auditApi.Log(
|
|
ctx,
|
|
event,
|
|
visibility,
|
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
|
))
|
|
|
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
|
assert.NoError(t, err)
|
|
|
|
validateSentMessage(t, topicName, message, event)
|
|
})
|
|
|
|
t.Run("Log private organization event", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
// Create the queue and topic subscription in solace
|
|
queueName := "org-event-private-legacy"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-created"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
|
|
|
// Log the event to solace
|
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
|
assert.NoError(t, auditApi.Log(
|
|
ctx,
|
|
event,
|
|
visibility,
|
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
|
))
|
|
|
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
|
assert.NoError(t, err)
|
|
|
|
validateSentMessage(t, topicName, message, event)
|
|
})
|
|
|
|
// Check logging of folder events
|
|
t.Run("Log public folder event", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
// Create the queue and topic subscription in solace
|
|
queueName := "folder-event-public-legacy"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/folder-created"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event, objectIdentifier := internalAuditApi.NewFolderAuditEvent(nil)
|
|
|
|
// Log the event to solace
|
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
|
assert.NoError(t, auditApi.Log(
|
|
ctx,
|
|
event,
|
|
visibility,
|
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
|
))
|
|
|
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
|
assert.NoError(t, err)
|
|
|
|
validateSentMessage(t, topicName, message, event)
|
|
})
|
|
|
|
t.Run("Log private folder event", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
// Create the queue and topic subscription in solace
|
|
queueName := "folder-event-private-legacy"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/folder-created"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event, objectIdentifier := internalAuditApi.NewFolderAuditEvent(nil)
|
|
|
|
// Log the event to solace
|
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
|
assert.NoError(t, auditApi.Log(
|
|
ctx,
|
|
event,
|
|
visibility,
|
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
|
))
|
|
|
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
|
assert.NoError(t, err)
|
|
|
|
validateSentMessage(t, topicName, message, event)
|
|
})
|
|
|
|
// Check logging of project events
|
|
t.Run("Log public project event", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
// Create the queue and topic subscription in solace
|
|
queueName := "project-event-public-legacy"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/project-created"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(nil)
|
|
|
|
// Log the event to solace
|
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
|
assert.NoError(t, auditApi.Log(
|
|
ctx,
|
|
event,
|
|
visibility,
|
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
|
))
|
|
|
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
|
assert.NoError(t, err)
|
|
|
|
validateSentMessage(t, topicName, message, event)
|
|
})
|
|
|
|
t.Run("Log private project event", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
// Create the queue and topic subscription in solace
|
|
queueName := "project-event-private-legacy"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/project-created"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(nil)
|
|
|
|
// Log the event to solace
|
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
|
assert.NoError(t, auditApi.Log(
|
|
ctx,
|
|
event,
|
|
visibility,
|
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
|
))
|
|
|
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
|
assert.NoError(t, err)
|
|
|
|
validateSentMessage(t, topicName, message, event)
|
|
})
|
|
|
|
// Check logging of system events with identifier
|
|
t.Run("Log private project system event", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
queueName := "project-system-event-private"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/project-system-changed"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event := internalAuditApi.NewProjectSystemAuditEvent(nil)
|
|
|
|
// Log the event to solace
|
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
|
assert.NoError(t,
|
|
auditApi.Log(
|
|
ctx,
|
|
event,
|
|
visibility,
|
|
pkgAuditCommon.RoutableSystemIdentifier,
|
|
))
|
|
|
|
// Receive the event from solace
|
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
|
assert.NoError(t, err)
|
|
|
|
// Check topic name
|
|
assert.Equal(t, topicName, *message.Properties.To)
|
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:traceparent"])
|
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
|
|
|
// Check deserialized message
|
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
|
|
|
assert.Equal(t, event.ProtoPayload.ResourceName, *auditEvent.ResourceName)
|
|
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(), auditEvent.EventTimeStamp)
|
|
assert.Equal(t, event.ProtoPayload.AuthenticationInfo.PrincipalId, auditEvent.Initiator.Id)
|
|
assert.Equal(t, "SYSTEM_EVENT", auditEvent.EventType)
|
|
assert.Equal(t, "INFO", auditEvent.Severity)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Path, auditEvent.Request.Endpoint)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.CallerIp, auditEvent.SourceIpAddress)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.CallerSuppliedUserAgent, auditEvent.UserAgent)
|
|
})
|
|
|
|
// Check logging of system events
|
|
t.Run("Log private system event", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
queueName := "system-event-private"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/system-changed"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
|
|
|
// Log the event to solace
|
|
visibility := auditV1.Visibility_VISIBILITY_PRIVATE
|
|
assert.NoError(t,
|
|
auditApi.Log(
|
|
ctx,
|
|
event,
|
|
visibility,
|
|
pkgAuditCommon.RoutableSystemIdentifier,
|
|
))
|
|
|
|
// Receive the event from solace
|
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
|
assert.NoError(t, err)
|
|
|
|
// Check topic name
|
|
assert.Equal(t, topicName, *message.Properties.To)
|
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:traceparent"])
|
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
|
|
|
// Check deserialized message
|
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
|
|
|
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(), auditEvent.EventTimeStamp)
|
|
assert.Equal(t, event.ProtoPayload.AuthenticationInfo.PrincipalId, auditEvent.Initiator.Id)
|
|
assert.Equal(t, "SYSTEM_EVENT", auditEvent.EventType)
|
|
assert.Equal(t, "INFO", auditEvent.Severity)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Path, auditEvent.Request.Endpoint)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.CallerIp, auditEvent.SourceIpAddress)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.CallerSuppliedUserAgent, auditEvent.UserAgent)
|
|
})
|
|
|
|
t.Run("Log event with details", func(t *testing.T) {
|
|
defer solaceContainer.StopOnError()
|
|
|
|
// Create the queue and topic subscription in solace
|
|
queueName := "org-event-with-details-legacy"
|
|
assert.NoError(t, solaceContainer.QueueCreate(ctx, queueName))
|
|
assert.NoError(t, solaceContainer.TopicSubscriptionCreate(ctx, queueName, topicSubscriptionTopicPattern))
|
|
|
|
topicName := "topic://stackit-platform/t/swz/audit-log/eu01/v1/resource-manager/organization-created"
|
|
assert.NoError(t, solaceContainer.ValidateTopicName(topicSubscriptionTopicPattern, topicName))
|
|
|
|
// Instantiate audit api
|
|
auditApi, err := NewLegacyAuditApi(
|
|
amqpApi,
|
|
StaticTopicNameConfig{TopicName: topicName},
|
|
validator,
|
|
)
|
|
assert.NoError(t, err)
|
|
|
|
// Instantiate test data
|
|
event, objectIdentifier := internalAuditApi.NewOrganizationAuditEvent(nil)
|
|
escapedQuery := url.QueryEscape("param=value")
|
|
event.ProtoPayload.RequestMetadata.RequestAttributes.Query = &escapedQuery
|
|
|
|
// Log the event to solace
|
|
visibility := auditV1.Visibility_VISIBILITY_PUBLIC
|
|
assert.NoError(t, auditApi.Log(
|
|
ctx,
|
|
event,
|
|
visibility,
|
|
pkgAuditCommon.NewRoutableIdentifier(objectIdentifier),
|
|
))
|
|
|
|
message, err := solaceContainer.NextMessageFromQueue(ctx, queueName, true)
|
|
assert.NoError(t, err)
|
|
|
|
validateSentMessageWithDetails(t, topicName, message, event)
|
|
})
|
|
}
|
|
|
|
func validateSentMessage(
|
|
t *testing.T,
|
|
topicName string,
|
|
message *amqp.Message,
|
|
event *auditV1.AuditLogEntry,
|
|
) {
|
|
|
|
// Check message properties
|
|
assert.Equal(t, topicName, *message.Properties.To)
|
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:traceparent"])
|
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
|
|
|
// Check deserialized message
|
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
|
|
|
var severity string
|
|
switch event.Severity {
|
|
case auditV1.LogSeverity_LOG_SEVERITY_DEFAULT:
|
|
fallthrough
|
|
case auditV1.LogSeverity_LOG_SEVERITY_DEBUG:
|
|
fallthrough
|
|
case auditV1.LogSeverity_LOG_SEVERITY_INFO:
|
|
fallthrough
|
|
case auditV1.LogSeverity_LOG_SEVERITY_NOTICE:
|
|
fallthrough
|
|
case auditV1.LogSeverity_LOG_SEVERITY_WARNING:
|
|
severity = "INFO"
|
|
case auditV1.LogSeverity_LOG_SEVERITY_ERROR:
|
|
fallthrough
|
|
case auditV1.LogSeverity_LOG_SEVERITY_CRITICAL:
|
|
fallthrough
|
|
case auditV1.LogSeverity_LOG_SEVERITY_ALERT:
|
|
fallthrough
|
|
case auditV1.LogSeverity_LOG_SEVERITY_EMERGENCY:
|
|
severity = "ERROR"
|
|
default:
|
|
assert.Fail(t, "unknown log severity")
|
|
}
|
|
|
|
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(), auditEvent.EventTimeStamp)
|
|
assert.Equal(t, event.ProtoPayload.AuthenticationInfo.PrincipalId, auditEvent.Initiator.Id)
|
|
assert.Equal(t, "ADMIN_ACTIVITY", auditEvent.EventType)
|
|
assert.Equal(t, severity, auditEvent.Severity)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Path, auditEvent.Request.Endpoint)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.CallerIp, auditEvent.SourceIpAddress)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.CallerSuppliedUserAgent, auditEvent.UserAgent)
|
|
}
|
|
|
|
func validateSentMessageWithDetails(
|
|
t *testing.T,
|
|
topicName string,
|
|
message *amqp.Message,
|
|
event *auditV1.AuditLogEntry,
|
|
) {
|
|
|
|
// Check topic name
|
|
assert.Equal(t, topicName, *message.Properties.To)
|
|
assert.Equal(t, pkgAuditCommon.ContentTypeCloudEventsJson, message.ApplicationProperties["cloudEvents:datacontenttype"])
|
|
assert.Equal(t, DataTypeLegacyAuditEventV1, message.ApplicationProperties["cloudEvents:type"])
|
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:traceparent"])
|
|
assert.Equal(t, "", message.ApplicationProperties["cloudEvents:tracestate"])
|
|
|
|
// Check deserialized message
|
|
var auditEvent internalAuditApi.LegacyAuditEvent
|
|
assert.NoError(t, json.Unmarshal(message.Data[0], &auditEvent))
|
|
|
|
assert.Equal(t, event.ProtoPayload.OperationName, auditEvent.EventName)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(), auditEvent.EventTimeStamp)
|
|
assert.Equal(t, event.ProtoPayload.AuthenticationInfo.PrincipalId, auditEvent.Initiator.Id)
|
|
assert.Equal(t, "ADMIN_ACTIVITY", auditEvent.EventType)
|
|
assert.Equal(t, "INFO", auditEvent.Severity)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.RequestAttributes.Path, auditEvent.Request.Endpoint)
|
|
var parameters map[string]interface{} = nil
|
|
if event.ProtoPayload.RequestMetadata.RequestAttributes.Path != "" &&
|
|
event.ProtoPayload.RequestMetadata.RequestAttributes.Query != nil &&
|
|
*event.ProtoPayload.RequestMetadata.RequestAttributes.Query != "" {
|
|
parameters = map[string]interface{}{}
|
|
|
|
unescapedQuery, err := url.QueryUnescape(*event.ProtoPayload.RequestMetadata.RequestAttributes.Query)
|
|
assert.NoError(t, err)
|
|
parsedUrl, err := url.Parse(fmt.Sprintf("%s?%s",
|
|
event.ProtoPayload.RequestMetadata.RequestAttributes.Path,
|
|
unescapedQuery))
|
|
|
|
assert.NoError(t, err)
|
|
for k, v := range parsedUrl.Query() {
|
|
parameters[k] = v
|
|
}
|
|
}
|
|
assert.Equal(t, event.ProtoPayload.Request.AsMap(), *auditEvent.Request.Body)
|
|
assert.Equal(t, parameters, *auditEvent.Request.Parameters)
|
|
for key, value := range event.ProtoPayload.RequestMetadata.RequestAttributes.Headers {
|
|
assert.Equal(t, value, (*auditEvent.Request.Headers)[key])
|
|
}
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.CallerIp, auditEvent.SourceIpAddress)
|
|
assert.Equal(t, event.ProtoPayload.RequestMetadata.CallerSuppliedUserAgent, auditEvent.UserAgent)
|
|
assert.Equal(t, event.ProtoPayload.Request.AsMap(), *auditEvent.Details)
|
|
assert.Equal(t, event.ProtoPayload.Response.AsMap(), *auditEvent.Result)
|
|
assert.True(t, auditEvent.Context.OrganizationId != nil || auditEvent.Context.FolderId != nil || auditEvent.Context.ProjectId != nil)
|
|
|
|
for idx, principal := range event.ProtoPayload.AuthenticationInfo.ServiceAccountDelegationInfo {
|
|
switch principalValue := principal.Authority.(type) {
|
|
case *auditV1.ServiceAccountDelegationInfo_IdpPrincipal_:
|
|
assert.Equal(t, principalValue.IdpPrincipal.PrincipalId, auditEvent.ServiceAccountDelegationInfo.Principals[idx].Id)
|
|
assert.Equal(t, principalValue.IdpPrincipal.PrincipalEmail, auditEvent.ServiceAccountDelegationInfo.Principals[idx].Email)
|
|
case *auditV1.ServiceAccountDelegationInfo_SystemPrincipal_:
|
|
assert.Equal(t, "system", auditEvent.ServiceAccountDelegationInfo.Principals[idx].Id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLegacyAuditApi_NewLegacyAuditApi(t *testing.T) {
|
|
|
|
t.Run("messaging api nil", func(t *testing.T) {
|
|
auditApi, err := NewLegacyAuditApi(nil, StaticTopicNameConfig{}, nil)
|
|
assert.Nil(t, auditApi)
|
|
assert.EqualError(t, err, "messaging api nil")
|
|
})
|
|
|
|
t.Run("topic name is blank", func(t *testing.T) {
|
|
// Start solace docker container
|
|
solaceContainer, err := pkgMessagingTest.NewSolaceContainer(context.Background())
|
|
assert.NoError(t, err)
|
|
defer solaceContainer.Stop()
|
|
|
|
// Instantiate the messaging api
|
|
amqpApi, err := pkgMessagingApi.NewAmqpApi(pkgMessagingCommon.AmqpConnectionPoolConfig{
|
|
Parameters: pkgMessagingCommon.AmqpConnectionConfig{BrokerUrl: solaceContainer.AmqpConnectionString},
|
|
PoolSize: 1,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
// Validator
|
|
validator, err := protovalidate.New()
|
|
assert.NoError(t, err)
|
|
|
|
auditApi, err := NewLegacyAuditApi(amqpApi, StaticTopicNameConfig{
|
|
TopicName: "",
|
|
}, validator)
|
|
|
|
assert.Nil(t, auditApi)
|
|
assert.EqualError(t, err, "topic name is required")
|
|
})
|
|
}
|
|
|
|
func TestLegacyAuditApi_ValidateAndSerialize_ValidationFailed(t *testing.T) {
|
|
expectedError := errors.New("expected error")
|
|
|
|
validator := &ProtobufValidatorMock{}
|
|
validator.On("Validate", mock.Anything).Return(expectedError)
|
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
|
|
|
auditApi := LegacyAuditApi{
|
|
tracer: otel.Tracer("test"),
|
|
validator: protobufValidator,
|
|
}
|
|
|
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
|
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
|
assert.ErrorIs(t, err, expectedError)
|
|
}
|
|
|
|
func TestLegacyAuditApi_Log_ValidationFailed(t *testing.T) {
|
|
expectedError := errors.New("expected error")
|
|
|
|
validator := &ProtobufValidatorMock{}
|
|
validator.On("Validate", mock.Anything).Return(expectedError)
|
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
|
|
|
auditApi := LegacyAuditApi{
|
|
tracer: otel.Tracer("test"),
|
|
validator: protobufValidator,
|
|
}
|
|
|
|
event := internalAuditApi.NewSystemAuditEvent(nil)
|
|
err := auditApi.Log(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
|
assert.ErrorIs(t, err, expectedError)
|
|
}
|
|
|
|
func TestLegacyAuditApi_Log_NilEvent(t *testing.T) {
|
|
auditApi := LegacyAuditApi{tracer: otel.Tracer("test")}
|
|
err := auditApi.Log(context.Background(), nil, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.RoutableSystemIdentifier)
|
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrEventNil)
|
|
}
|
|
|
|
func TestLegacyAuditApi_ConvertAndSerializeIntoLegacyFormatInvalidObjectIdentifierType(t *testing.T) {
|
|
customization := func(event *auditV1.AuditLogEntry,
|
|
objectIdentifier *auditV1.ObjectIdentifier) {
|
|
objectIdentifier.Type = "invalid"
|
|
}
|
|
event, objectIdentifier := internalAuditApi.NewProjectAuditEvent(&customization)
|
|
|
|
validator := &ProtobufValidatorMock{}
|
|
validator.On("Validate", mock.Anything).Return(nil)
|
|
var protobufValidator pkgAuditCommon.ProtobufValidator = validator
|
|
|
|
auditApi := LegacyAuditApi{
|
|
tracer: otel.Tracer("test"),
|
|
validator: protobufValidator,
|
|
}
|
|
_, err := auditApi.ValidateAndSerialize(context.Background(), event, auditV1.Visibility_VISIBILITY_PUBLIC, pkgAuditCommon.NewRoutableIdentifier(objectIdentifier))
|
|
assert.ErrorIs(t, err, pkgAuditCommon.ErrUnsupportedRoutableType)
|
|
}
|