diff --git a/x-pack/plugins/security/server/audit/audit_service.test.ts b/x-pack/plugins/security/server/audit/audit_service.test.ts index dfe41d6886917..60dbe341dc4bf 100644 --- a/x-pack/plugins/security/server/audit/audit_service.test.ts +++ b/x-pack/plugins/security/server/audit/audit_service.test.ts @@ -30,6 +30,7 @@ const getSpaceId = jest.fn().mockReturnValue('default'); beforeEach(() => { logger.info.mockClear(); + logging.configure.mockClear(); http.registerOnPostAuth.mockClear(); }); @@ -53,10 +54,18 @@ describe('#setup', () => { `); }); - it('configures logging correctly', async () => { + it('configures logging correctly when using ecs logger', async () => { new AuditService(logger).setup({ license, - config, + config: { + enabled: true, + appender: { + kind: 'console', + layout: { + kind: 'pattern', + }, + }, + }, logging, http, getCurrentUser, @@ -65,6 +74,20 @@ describe('#setup', () => { expect(logging.configure).toHaveBeenCalledWith(expect.any(Observable)); }); + it('does not configure logging when using legacy logger', async () => { + new AuditService(logger).setup({ + license, + config: { + enabled: true, + }, + logging, + http, + getCurrentUser, + getSpaceId, + }); + expect(logging.configure).not.toHaveBeenCalled(); + }); + it('registers post auth hook', () => { new AuditService(logger).setup({ license, @@ -158,7 +181,7 @@ describe('#createLoggingConfig', () => { "appenders": Array [ "auditTrailAppender", ], - "context": "audit.beta", + "context": "audit", "level": "info", }, ], diff --git a/x-pack/plugins/security/server/audit/audit_service.ts b/x-pack/plugins/security/server/audit/audit_service.ts index e8bcc8bbfc09a..b84ad37332b85 100644 --- a/x-pack/plugins/security/server/audit/audit_service.ts +++ b/x-pack/plugins/security/server/audit/audit_service.ts @@ -66,11 +66,8 @@ export class AuditService { * @deprecated */ private allowAuditLogging = false; - private readonly betaLogger: Logger; - constructor(private readonly logger: Logger) { - this.betaLogger = this.logger.get('beta'); - } + constructor(private readonly logger: Logger) {} setup({ license, @@ -86,13 +83,16 @@ export class AuditService { }); } - // Configure logging during setup and when license changes - logging.configure( - license.features$.pipe( - distinctUntilKeyChanged('allowAuditLogging'), - createLoggingConfig(config) - ) - ); + // Do not change logging for legacy logger + if (config.appender) { + // Configure logging during setup and when license changes + logging.configure( + license.features$.pipe( + distinctUntilKeyChanged('allowAuditLogging'), + createLoggingConfig(config) + ) + ); + } /** * Creates an {@link AuditLogger} scoped to the current request. @@ -146,7 +146,7 @@ export class AuditService { }, }; if (filterEvent(meta, config.ignore_filters)) { - this.betaLogger.info(event.message!, meta); + this.logger.info(event.message!, meta); } }; return { log }; @@ -203,7 +203,7 @@ export const createLoggingConfig = (config: ConfigType['audit']) => }, loggers: [ { - context: 'audit.beta', + context: 'audit', level: config.enabled && config.appender && features.allowAuditLogging ? 'info' : 'off', appenders: ['auditTrailAppender'], }, diff --git a/x-pack/plugins/security/server/authentication/authenticator.test.ts b/x-pack/plugins/security/server/authentication/authenticator.test.ts index b1ac78d37d017..e5bb00cdc056f 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.test.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.test.ts @@ -221,6 +221,7 @@ describe('Authenticator', () => { }; beforeEach(() => { + auditLogger.log.mockClear(); mockOptions = getMockOptions({ providers: { basic: { basic1: { order: 0 } } } }); mockOptions.session.get.mockResolvedValue(null); mockOptions.audit.asScoped.mockReturnValue(auditLogger); @@ -294,6 +295,7 @@ describe('Authenticator', () => { ); await authenticator.login(request, { provider: { type: 'basic' }, value: {} }); + expect(auditLogger.log).toHaveBeenCalledTimes(1); expect(auditLogger.log).toHaveBeenCalledWith( expect.objectContaining({ event: { action: 'user_login', category: 'authentication', outcome: 'success' }, @@ -309,6 +311,7 @@ describe('Authenticator', () => { ); await authenticator.login(request, { provider: { type: 'basic' }, value: {} }); + expect(auditLogger.log).toHaveBeenCalledTimes(1); expect(auditLogger.log).toHaveBeenCalledWith( expect.objectContaining({ event: { action: 'user_login', category: 'authentication', outcome: 'failure' }, diff --git a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts index 9adc86f2cabb1..8136553e4a623 100644 --- a/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts +++ b/x-pack/plugins/security/server/saved_objects/secure_saved_objects_client_wrapper.test.ts @@ -419,12 +419,15 @@ describe('#addToNamespaces', () => { const apiCallReturnValue = Symbol(); clientOpts.baseClient.addToNamespaces.mockReturnValue(apiCallReturnValue as any); await client.addToNamespaces(type, id, namespaces); + + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_add_to_spaces', EventOutcome.UNKNOWN, { type, id }); }); test(`adds audit event when not successful`, async () => { clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); await expect(() => client.addToNamespaces(type, id, namespaces)).rejects.toThrow(); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_add_to_spaces', EventOutcome.FAILURE, { type, id }); }); }); @@ -487,6 +490,7 @@ describe('#bulkCreate', () => { const objects = [obj1, obj2]; const options = { namespace }; await expectSuccess(client.bulkCreate, { objects, options }); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(2); expectAuditEvent('saved_object_create', EventOutcome.UNKNOWN, { type: obj1.type, id: obj1.id }); expectAuditEvent('saved_object_create', EventOutcome.UNKNOWN, { type: obj2.type, id: obj2.id }); }); @@ -494,6 +498,7 @@ describe('#bulkCreate', () => { test(`adds audit event when not successful`, async () => { clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); await expect(() => client.bulkCreate([obj1, obj2], { namespace })).rejects.toThrow(); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(2); expectAuditEvent('saved_object_create', EventOutcome.FAILURE, { type: obj1.type, id: obj1.id }); expectAuditEvent('saved_object_create', EventOutcome.FAILURE, { type: obj2.type, id: obj2.id }); }); @@ -543,6 +548,7 @@ describe('#bulkGet', () => { const objects = [obj1, obj2]; const options = { namespace }; await expectSuccess(client.bulkGet, { objects, options }); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(2); expectAuditEvent('saved_object_get', EventOutcome.SUCCESS, obj1); expectAuditEvent('saved_object_get', EventOutcome.SUCCESS, obj2); }); @@ -550,6 +556,7 @@ describe('#bulkGet', () => { test(`adds audit event when not successful`, async () => { clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); await expect(() => client.bulkGet([obj1, obj2], { namespace })).rejects.toThrow(); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(2); expectAuditEvent('saved_object_get', EventOutcome.FAILURE, obj1); expectAuditEvent('saved_object_get', EventOutcome.FAILURE, obj2); }); @@ -610,6 +617,7 @@ describe('#bulkUpdate', () => { const objects = [obj1, obj2]; const options = { namespace }; await expectSuccess(client.bulkUpdate, { objects, options }); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(2); expectAuditEvent('saved_object_update', EventOutcome.UNKNOWN, { type: obj1.type, id: obj1.id }); expectAuditEvent('saved_object_update', EventOutcome.UNKNOWN, { type: obj2.type, id: obj2.id }); }); @@ -617,6 +625,7 @@ describe('#bulkUpdate', () => { test(`adds audit event when not successful`, async () => { clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); await expect(() => client.bulkUpdate([obj1, obj2], { namespace })).rejects.toThrow(); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(2); expectAuditEvent('saved_object_update', EventOutcome.FAILURE, { type: obj1.type, id: obj1.id }); expectAuditEvent('saved_object_update', EventOutcome.FAILURE, { type: obj2.type, id: obj2.id }); }); @@ -706,12 +715,14 @@ describe('#create', () => { clientOpts.baseClient.create.mockResolvedValue(apiCallReturnValue as any); const options = { namespace }; await expectSuccess(client.create, { type, attributes, options }); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_create', EventOutcome.UNKNOWN, { type }); }); test(`adds audit event when not successful`, async () => { clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); await expect(() => client.create(type, attributes, { namespace })).rejects.toThrow(); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_create', EventOutcome.FAILURE, { type }); }); }); @@ -749,12 +760,14 @@ describe('#delete', () => { clientOpts.baseClient.delete.mockReturnValue(apiCallReturnValue as any); const options = { namespace }; await expectSuccess(client.delete, { type, id, options }); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_delete', EventOutcome.UNKNOWN, { type, id }); }); test(`adds audit event when not successful`, async () => { clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); await expect(() => client.delete(type, id)).rejects.toThrow(); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_delete', EventOutcome.FAILURE, { type, id }); }); }); @@ -883,6 +896,7 @@ describe('#find', () => { clientOpts.baseClient.find.mockReturnValue(apiCallReturnValue as any); const options = Object.freeze({ type: type1, namespaces: ['some-ns'] }); await expectSuccess(client.find, { options }); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(2); expectAuditEvent('saved_object_find', EventOutcome.SUCCESS, obj1); expectAuditEvent('saved_object_find', EventOutcome.SUCCESS, obj2); }); @@ -892,6 +906,7 @@ describe('#find', () => { getMockCheckPrivilegesFailure ); await client.find({ type: type1 }); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_find', EventOutcome.FAILURE); }); }); @@ -934,12 +949,14 @@ describe('#get', () => { clientOpts.baseClient.get.mockReturnValue(apiCallReturnValue as any); const options = { namespace }; await expectSuccess(client.get, { type, id, options }); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_get', EventOutcome.SUCCESS, { type, id }); }); test(`adds audit event when not successful`, async () => { clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); await expect(() => client.get(type, id, { namespace })).rejects.toThrow(); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_get', EventOutcome.FAILURE, { type, id }); }); }); @@ -1018,12 +1035,14 @@ describe('#deleteFromNamespaces', () => { const apiCallReturnValue = Symbol(); clientOpts.baseClient.deleteFromNamespaces.mockReturnValue(apiCallReturnValue as any); await client.deleteFromNamespaces(type, id, namespaces); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_delete_from_spaces', EventOutcome.UNKNOWN, { type, id }); }); test(`adds audit event when not successful`, async () => { clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); await expect(() => client.deleteFromNamespaces(type, id, namespaces)).rejects.toThrow(); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_delete_from_spaces', EventOutcome.FAILURE, { type, id }); }); }); @@ -1067,12 +1086,14 @@ describe('#update', () => { clientOpts.baseClient.update.mockReturnValue(apiCallReturnValue as any); const options = { namespace }; await expectSuccess(client.update, { type, id, attributes, options }); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_update', EventOutcome.UNKNOWN, { type, id }); }); test(`adds audit event when not successful`, async () => { clientOpts.checkSavedObjectsPrivilegesAsCurrentUser.mockRejectedValue(new Error()); await expect(() => client.update(type, id, attributes, { namespace })).rejects.toThrow(); + expect(clientOpts.auditLogger.log).toHaveBeenCalledTimes(1); expectAuditEvent('saved_object_update', EventOutcome.FAILURE, { type, id }); }); });