mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Add session ID to user login audit event (#124299)
This commit is contained in:
parent
b92e180e85
commit
ddc300069d
35 changed files with 304 additions and 244 deletions
|
@ -462,7 +462,7 @@ When "thom" logs in, a "user_login" {kib} audit event is written:
|
|||
|
||||
[source,json]
|
||||
-------------
|
||||
{"event":{"action":"user_login","category":["authentication"],"outcome":"success"},"user":{"name":"thom","roles":["superuser"]},"@timestamp":"2022-01-25T09:40:39.267-05:00","message":"User [thom] has logged in using basic provider [name=basic]","trace":{"id":"818cbf3..."}}
|
||||
{"event":{"action":"user_login","category":["authentication"],"outcome":"success"},"kibana":{"session_id":"ab93zdA..."},"user":{"name":"thom","roles":["superuser"]},"@timestamp":"2022-01-25T09:40:39.267-05:00","message":"User [thom] has logged in using basic provider [name=basic]","trace":{"id":"818cbf3..."}}
|
||||
-------------
|
||||
|
||||
The `trace.id` value `"818cbf3..."` in the {kib} audit event can be correlated with the `opaque_id` value in these six {es} audit events:
|
||||
|
|
|
@ -19,7 +19,7 @@ import { getActionsConfigurationUtilities } from './actions_config';
|
|||
import { licenseStateMock } from './lib/license_state.mock';
|
||||
import { licensingMock } from '../../licensing/server/mocks';
|
||||
import { httpServerMock, loggingSystemMock } from '../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../security/server/audit/mocks';
|
||||
import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock';
|
||||
|
||||
import {
|
||||
|
@ -72,7 +72,7 @@ const authorization = actionsAuthorizationMock.create();
|
|||
const executionEnqueuer = jest.fn();
|
||||
const ephemeralExecutionEnqueuer = jest.fn();
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
const auditLogger = auditServiceMock.create().asScoped(request);
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract();
|
||||
const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test');
|
||||
const logger = loggingSystemMock.create().get() as jest.Mocked<Logger>;
|
||||
|
|
|
@ -14,8 +14,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
import { RecoveredActionGroup } from '../../../common';
|
||||
import { RegistryRuleType } from '../../rule_type_registry';
|
||||
|
@ -27,7 +26,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -16,8 +16,7 @@ import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
|||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization, ActionsClient } from '../../../../actions/server';
|
||||
import { TaskStatus } from '../../../../task_manager/server';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
import { RecoveredActionGroup } from '../../../common';
|
||||
import { getDefaultRuleMonitoring } from '../../task_runner/task_runner';
|
||||
|
@ -34,7 +33,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v8.0.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -14,8 +14,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup } from './lib';
|
||||
|
||||
const taskManager = taskManagerMock.createStart();
|
||||
|
@ -24,7 +23,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -15,8 +15,7 @@ import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
|||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { InvalidatePendingApiKey } from '../../types';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
import { eventLoggerMock } from '../../../../event_log/server/event_logger.mock';
|
||||
import { TaskStatus } from '../../../../task_manager/server';
|
||||
|
@ -31,7 +30,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
const eventLogger = eventLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
|
|
|
@ -15,8 +15,7 @@ import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
|||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { TaskStatus } from '../../../../task_manager/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { InvalidatePendingApiKey } from '../../types';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
|
||||
|
@ -26,7 +25,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -16,8 +16,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
import { RecoveredActionGroup } from '../../../common';
|
||||
import { RegistryRuleType } from '../../rule_type_registry';
|
||||
|
@ -28,7 +27,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -14,8 +14,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
import { RecoveredActionGroup } from '../../../common';
|
||||
|
||||
|
@ -25,7 +24,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -14,8 +14,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
|
||||
const taskManager = taskManagerMock.createStart();
|
||||
|
@ -24,7 +23,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -14,8 +14,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
|
||||
const taskManager = taskManagerMock.createStart();
|
||||
|
@ -24,7 +23,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -14,8 +14,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
import { RecoveredActionGroup } from '../../../common';
|
||||
|
||||
|
@ -25,7 +24,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -14,8 +14,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
|
||||
const taskManager = taskManagerMock.createStart();
|
||||
|
@ -24,7 +23,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -14,8 +14,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
|
||||
const taskManager = taskManagerMock.createStart();
|
||||
|
@ -24,7 +23,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -20,8 +20,7 @@ import { AlertingAuthorization } from '../../authorization/alerting_authorizatio
|
|||
import { resolvable } from '../../test_utils';
|
||||
import { ActionsAuthorization, ActionsClient } from '../../../../actions/server';
|
||||
import { TaskStatus } from '../../../../task_manager/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
|
||||
jest.mock('../../../../../../src/core/server/saved_objects/service/lib/utils', () => ({
|
||||
|
@ -36,7 +35,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -14,8 +14,7 @@ import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/s
|
|||
import { actionsAuthorizationMock } from '../../../../actions/server/mocks';
|
||||
import { AlertingAuthorization } from '../../authorization/alerting_authorization';
|
||||
import { ActionsAuthorization } from '../../../../actions/server';
|
||||
import { httpServerMock } from '../../../../../../src/core/server/mocks';
|
||||
import { auditServiceMock } from '../../../../security/server/audit/index.mock';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { InvalidatePendingApiKey } from '../../types';
|
||||
import { getBeforeSetup, setGlobalDate } from './lib';
|
||||
|
||||
|
@ -25,7 +24,7 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create();
|
|||
const encryptedSavedObjects = encryptedSavedObjectsMock.createClient();
|
||||
const authorization = alertingAuthorizationMock.create();
|
||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const kibanaVersion = 'v7.10.0';
|
||||
const rulesClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AuditLogger } from '../../../../plugins/security/server';
|
||||
import { auditLoggerMock } from '../../../../plugins/security/server/audit/mocks';
|
||||
import { Operations } from '.';
|
||||
import { AuthorizationAuditLogger } from './audit_logger';
|
||||
import { ReadOperations } from './types';
|
||||
|
@ -30,11 +30,7 @@ describe('audit_logger', () => {
|
|||
});
|
||||
|
||||
describe('log function', () => {
|
||||
const mockLogger: jest.Mocked<AuditLogger> = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
const mockLogger = auditLoggerMock.create();
|
||||
let logger: AuthorizationAuditLogger;
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -14,6 +14,7 @@ import { AuthorizationAuditLogger } from './audit_logger';
|
|||
import { KibanaRequest } from 'kibana/server';
|
||||
import { KibanaFeature } from '../../../../plugins/features/common';
|
||||
import { AuditLogger, SecurityPluginStart } from '../../../security/server';
|
||||
import { auditLoggerMock } from '../../../security/server/audit/mocks';
|
||||
import { PluginStartContract as FeaturesPluginStart } from '../../../features/server';
|
||||
|
||||
describe('authorization', () => {
|
||||
|
@ -22,10 +23,7 @@ describe('authorization', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
request = httpServerMock.createKibanaRequest();
|
||||
mockLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
};
|
||||
mockLogger = auditLoggerMock.create();
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
|
|
|
@ -11,7 +11,7 @@ import { AlertsClientFactory, AlertsClientFactoryProps } from './alerts_client_f
|
|||
import { ElasticsearchClient, KibanaRequest } from 'src/core/server';
|
||||
import { loggingSystemMock } from 'src/core/server/mocks';
|
||||
import { securityMock } from '../../../security/server/mocks';
|
||||
import { AuditLogger } from '../../../security/server';
|
||||
import { auditLoggerMock } from '../../../security/server/audit/mocks';
|
||||
import { alertingAuthorizationMock } from '../../../alerting/server/authorization/alerting_authorization.mock';
|
||||
import { ruleDataServiceMock } from '../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||
|
||||
|
@ -44,10 +44,7 @@ const fakeRequest = {
|
|||
},
|
||||
} as unknown as Request;
|
||||
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
} as jest.Mocked<AuditLogger>;
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
describe('AlertsClientFactory', () => {
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -17,16 +17,13 @@ import { loggingSystemMock } from '../../../../../../src/core/server/mocks';
|
|||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks';
|
||||
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
||||
import { AuditLogger } from '../../../../security/server';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
||||
import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||
|
||||
const alertingAuthMock = alertingAuthorizationMock.create();
|
||||
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
} as jest.Mocked<AuditLogger>;
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const alertsClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
logger: loggingSystemMock.create().get(),
|
||||
|
|
|
@ -16,16 +16,13 @@ import { loggingSystemMock } from '../../../../../../src/core/server/mocks';
|
|||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks';
|
||||
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
||||
import { AuditLogger } from '../../../../security/server';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
||||
import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||
|
||||
const alertingAuthMock = alertingAuthorizationMock.create();
|
||||
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
} as jest.Mocked<AuditLogger>;
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const alertsClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
logger: loggingSystemMock.create().get(),
|
||||
|
|
|
@ -17,16 +17,13 @@ import { loggingSystemMock } from '../../../../../../src/core/server/mocks';
|
|||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks';
|
||||
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
||||
import { AuditLogger } from '../../../../security/server';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
||||
import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||
|
||||
const alertingAuthMock = alertingAuthorizationMock.create();
|
||||
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
} as jest.Mocked<AuditLogger>;
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const alertsClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
logger: loggingSystemMock.create().get(),
|
||||
|
|
|
@ -16,16 +16,13 @@ import { loggingSystemMock } from '../../../../../../src/core/server/mocks';
|
|||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks';
|
||||
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
||||
import { AuditLogger } from '../../../../security/server';
|
||||
import { auditLoggerMock } from '../../../../security/server/audit/mocks';
|
||||
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
||||
import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||
|
||||
const alertingAuthMock = alertingAuthorizationMock.create();
|
||||
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
} as jest.Mocked<AuditLogger>;
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const alertsClientParams: jest.Mocked<ConstructorOptions> = {
|
||||
logger: loggingSystemMock.create().get(),
|
||||
|
|
|
@ -239,6 +239,7 @@ describe('#userLoginEvent', () => {
|
|||
authenticationResult: AuthenticationResult.succeeded(mockAuthenticatedUser()),
|
||||
authenticationProvider: 'basic1',
|
||||
authenticationType: 'basic',
|
||||
sessionId: '123',
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
|
@ -255,6 +256,7 @@ describe('#userLoginEvent', () => {
|
|||
"authentication_realm": "native1",
|
||||
"authentication_type": "basic",
|
||||
"lookup_realm": "native1",
|
||||
"session_id": "123",
|
||||
"space_id": undefined,
|
||||
},
|
||||
"message": "User [user] has logged in using basic provider [name=basic1]",
|
||||
|
@ -293,6 +295,7 @@ describe('#userLoginEvent', () => {
|
|||
"authentication_realm": undefined,
|
||||
"authentication_type": "basic",
|
||||
"lookup_realm": undefined,
|
||||
"session_id": undefined,
|
||||
"space_id": undefined,
|
||||
},
|
||||
"message": "Failed attempt to login using basic provider [name=basic1]",
|
||||
|
|
|
@ -97,12 +97,14 @@ export interface UserLoginParams {
|
|||
authenticationResult: AuthenticationResult;
|
||||
authenticationProvider?: string;
|
||||
authenticationType?: string;
|
||||
sessionId?: string;
|
||||
}
|
||||
|
||||
export function userLoginEvent({
|
||||
authenticationResult,
|
||||
authenticationProvider,
|
||||
authenticationType,
|
||||
sessionId,
|
||||
}: UserLoginParams): AuditEvent {
|
||||
return {
|
||||
message: authenticationResult.user
|
||||
|
@ -119,6 +121,7 @@ export function userLoginEvent({
|
|||
},
|
||||
kibana: {
|
||||
space_id: undefined, // Ensure this does not get populated by audit service
|
||||
session_id: sessionId,
|
||||
authentication_provider: authenticationProvider,
|
||||
authentication_type: authenticationType,
|
||||
authentication_realm: authenticationResult.user?.authentication_realm.name,
|
||||
|
|
|
@ -5,20 +5,23 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { AuditService } from './audit_service';
|
||||
import type { AuditLogger, AuditService } from './audit_service';
|
||||
|
||||
export const auditLoggerMock = {
|
||||
create() {
|
||||
return {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
} as jest.Mocked<AuditLogger>;
|
||||
},
|
||||
};
|
||||
|
||||
export const auditServiceMock = {
|
||||
create() {
|
||||
return {
|
||||
getLogger: jest.fn(),
|
||||
asScoped: jest.fn().mockReturnValue({
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
}),
|
||||
withoutRequest: {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
},
|
||||
asScoped: jest.fn().mockReturnValue(auditLoggerMock.create()),
|
||||
withoutRequest: auditLoggerMock.create(),
|
||||
} as jest.Mocked<ReturnType<AuditService['setup']>>;
|
||||
},
|
||||
};
|
|
@ -39,7 +39,7 @@ import type { AuthenticatedUser, SecurityLicense } from '../../common';
|
|||
import { licenseMock } from '../../common/licensing/index.mock';
|
||||
import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock';
|
||||
import type { AuditServiceSetup } from '../audit';
|
||||
import { auditServiceMock } from '../audit/index.mock';
|
||||
import { auditServiceMock } from '../audit/mocks';
|
||||
import type { ConfigType } from '../config';
|
||||
import { ConfigSchema, createConfig } from '../config';
|
||||
import type { SecurityFeatureUsageServiceStart } from '../feature_usage';
|
||||
|
|
|
@ -27,7 +27,8 @@ import {
|
|||
import type { SecurityLicenseFeatures } from '../../common/licensing';
|
||||
import { licenseMock } from '../../common/licensing/index.mock';
|
||||
import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock';
|
||||
import { auditServiceMock } from '../audit/index.mock';
|
||||
import type { AuditLogger } from '../audit';
|
||||
import { auditLoggerMock, auditServiceMock } from '../audit/mocks';
|
||||
import { ConfigSchema, createConfig } from '../config';
|
||||
import { securityFeatureUsageServiceMock } from '../feature_usage/index.mock';
|
||||
import { securityMock } from '../mocks';
|
||||
|
@ -39,6 +40,7 @@ import { Authenticator } from './authenticator';
|
|||
import { DeauthenticationResult } from './deauthentication_result';
|
||||
import type { BasicAuthenticationProvider, SAMLAuthenticationProvider } from './providers';
|
||||
|
||||
let auditLogger: AuditLogger;
|
||||
function getMockOptions({
|
||||
providers,
|
||||
http = {},
|
||||
|
@ -48,8 +50,11 @@ function getMockOptions({
|
|||
http?: Partial<AuthenticatorOptions['config']['authc']['http']>;
|
||||
selector?: AuthenticatorOptions['config']['authc']['selector'];
|
||||
} = {}) {
|
||||
const auditService = auditServiceMock.create();
|
||||
auditLogger = auditLoggerMock.create();
|
||||
auditService.asScoped.mockReturnValue(auditLogger);
|
||||
return {
|
||||
audit: auditServiceMock.create(),
|
||||
audit: auditService,
|
||||
getCurrentUser: jest.fn(),
|
||||
clusterClient: elasticsearchServiceMock.createClusterClient(),
|
||||
basePath: httpServiceMock.createSetupContract().basePath,
|
||||
|
@ -66,6 +71,26 @@ function getMockOptions({
|
|||
};
|
||||
}
|
||||
|
||||
interface ExpectedAuditEvent {
|
||||
action: string;
|
||||
outcome?: string;
|
||||
kibana?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
function expectAuditEvents(...events: ExpectedAuditEvent[]) {
|
||||
expect(auditLogger.log).toHaveBeenCalledTimes(events.length);
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
const { action, outcome, kibana } = events[i];
|
||||
expect(auditLogger.log).toHaveBeenNthCalledWith(
|
||||
i + 1,
|
||||
expect.objectContaining({
|
||||
event: { action, category: ['authentication'], ...(outcome && { outcome }) },
|
||||
...(kibana && { kibana }),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
describe('Authenticator', () => {
|
||||
let mockBasicAuthenticationProvider: jest.Mocked<PublicMethodsOf<BasicAuthenticationProvider>>;
|
||||
beforeEach(() => {
|
||||
|
@ -262,16 +287,10 @@ describe('Authenticator', () => {
|
|||
let authenticator: Authenticator;
|
||||
let mockOptions: ReturnType<typeof getMockOptions>;
|
||||
let mockSessVal: SessionValue;
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
auditLogger.log.mockClear();
|
||||
mockOptions = getMockOptions({ providers: { basic: { basic1: { order: 0 } } } });
|
||||
mockOptions.session.get.mockResolvedValue(null);
|
||||
mockOptions.audit.asScoped.mockReturnValue(auditLogger);
|
||||
mockSessVal = sessionMock.createValue({ state: { authorization: 'Basic xxx' } });
|
||||
|
||||
authenticator = new Authenticator(mockOptions);
|
||||
|
@ -281,6 +300,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.login(undefined as any, undefined as any)).rejects.toThrowError(
|
||||
'Request should be a valid "KibanaRequest" instance, was [undefined].'
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('fails if login attempt is not provided or invalid.', async () => {
|
||||
|
@ -304,6 +324,7 @@ describe('Authenticator', () => {
|
|||
).rejects.toThrowError(
|
||||
'Login attempt should be an object with non-empty "provider.type" or "provider.name" property.'
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('fails if an authentication provider fails.', async () => {
|
||||
|
@ -317,6 +338,7 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.failed(failureReason));
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'failure' });
|
||||
});
|
||||
|
||||
it('returns user that authentication provider returns.', async () => {
|
||||
|
@ -332,38 +354,49 @@ describe('Authenticator', () => {
|
|||
).resolves.toEqual(
|
||||
AuthenticationResult.succeeded(user, { authHeaders: { authorization: 'Basic .....' } })
|
||||
);
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('adds audit event when successful.', async () => {
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
const user = mockAuthenticatedUser();
|
||||
mockBasicAuthenticationProvider.login.mockResolvedValue(
|
||||
AuthenticationResult.succeeded(user, { authHeaders: { authorization: 'Basic .....' } })
|
||||
);
|
||||
await authenticator.login(request, { provider: { type: 'basic' }, value: {} });
|
||||
describe('user_login audit events', () => {
|
||||
// Every other test case includes audit event assertions, but the user_login event is a bit special.
|
||||
// We have these separate, detailed test cases to ensure that the session ID is included for user_login success events.
|
||||
// This allows us to keep audit event assertions in the other test cases simpler.
|
||||
|
||||
expect(auditLogger.log).toHaveBeenCalledTimes(1);
|
||||
expect(auditLogger.log).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
event: { action: 'user_login', category: ['authentication'], outcome: 'success' },
|
||||
})
|
||||
);
|
||||
});
|
||||
it('adds audit event with session ID when successful.', async () => {
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
const user = mockAuthenticatedUser();
|
||||
mockBasicAuthenticationProvider.login.mockResolvedValue(
|
||||
AuthenticationResult.succeeded(user, {
|
||||
authHeaders: { authorization: 'Basic .....' },
|
||||
state: 'foo', // to ensure a new session is created
|
||||
})
|
||||
);
|
||||
mockOptions.session.create.mockResolvedValue({ ...mockSessVal, sid: '123' });
|
||||
await authenticator.login(request, { provider: { type: 'basic' }, value: {} });
|
||||
|
||||
it('adds audit event when not successful.', async () => {
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
const failureReason = new Error('Not Authorized');
|
||||
mockBasicAuthenticationProvider.login.mockResolvedValue(
|
||||
AuthenticationResult.failed(failureReason)
|
||||
);
|
||||
await authenticator.login(request, { provider: { type: 'basic' }, value: {} });
|
||||
expect(mockOptions.session.create).toHaveBeenCalledTimes(1);
|
||||
expectAuditEvents({
|
||||
action: 'user_login',
|
||||
outcome: 'success',
|
||||
kibana: expect.objectContaining({ authentication_type: 'basic', session_id: '123' }),
|
||||
});
|
||||
});
|
||||
|
||||
expect(auditLogger.log).toHaveBeenCalledTimes(1);
|
||||
expect(auditLogger.log).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
event: { action: 'user_login', category: ['authentication'], outcome: 'failure' },
|
||||
})
|
||||
);
|
||||
it('adds audit event without session ID when not successful.', async () => {
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
const failureReason = new Error('Not Authorized');
|
||||
mockBasicAuthenticationProvider.login.mockResolvedValue(
|
||||
AuthenticationResult.failed(failureReason)
|
||||
);
|
||||
await authenticator.login(request, { provider: { type: 'basic' }, value: {} });
|
||||
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expectAuditEvents({
|
||||
action: 'user_login',
|
||||
outcome: 'failure',
|
||||
kibana: expect.objectContaining({ authentication_type: 'basic', session_id: undefined }),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('does not add audit event when not handled.', async () => {
|
||||
|
@ -396,6 +429,7 @@ describe('Authenticator', () => {
|
|||
provider: mockSessVal.provider,
|
||||
state: { authorization },
|
||||
});
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('returns `notHandled` if login attempt is targeted to not configured provider.', async () => {
|
||||
|
@ -476,6 +510,7 @@ describe('Authenticator', () => {
|
|||
|
||||
expect(mockBasicAuthenticationProvider.login).not.toHaveBeenCalled();
|
||||
expect(mockSAMLAuthenticationProvider1.login).not.toHaveBeenCalled();
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('tries to login only with the provider that has specified type', async () => {
|
||||
|
@ -493,6 +528,7 @@ describe('Authenticator', () => {
|
|||
expect(mockSAMLAuthenticationProvider1.login.mock.invocationCallOrder[0]).toBeLessThan(
|
||||
mockSAMLAuthenticationProvider2.login.mock.invocationCallOrder[0]
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns as soon as provider handles request', async () => {
|
||||
|
@ -528,6 +564,10 @@ describe('Authenticator', () => {
|
|||
expect(mockBasicAuthenticationProvider.login).not.toHaveBeenCalled();
|
||||
expect(mockSAMLAuthenticationProvider2.login).not.toHaveBeenCalled();
|
||||
expect(mockSAMLAuthenticationProvider1.login).toHaveBeenCalledTimes(3);
|
||||
expectAuditEvents(
|
||||
{ action: 'user_login', outcome: 'failure' },
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
|
||||
it('provides session only if provider name matches', async () => {
|
||||
|
@ -563,6 +603,7 @@ describe('Authenticator', () => {
|
|||
expect(mockSAMLAuthenticationProvider2.login.mock.invocationCallOrder[0]).toBeLessThan(
|
||||
mockSAMLAuthenticationProvider1.login.mock.invocationCallOrder[0]
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -595,6 +636,10 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expectAuditEvents(
|
||||
{ action: 'user_logout', outcome: 'unknown' },
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
|
||||
it('clears session if provider asked to do so in `succeeded` result.', async () => {
|
||||
|
@ -615,6 +660,10 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expectAuditEvents(
|
||||
{ action: 'user_logout', outcome: 'unknown' },
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
|
||||
it('clears session if provider asked to do so in `redirected` result.', async () => {
|
||||
|
@ -634,6 +683,7 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
|
||||
describe('with Access Agreement', () => {
|
||||
|
@ -670,6 +720,7 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.succeeded(mockUser));
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if request cannot be handled', async () => {
|
||||
|
@ -681,6 +732,7 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.notHandled());
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if authentication fails', async () => {
|
||||
|
@ -695,6 +747,7 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.failed(failureReason));
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'failure' });
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if redirect is required to complete login', async () => {
|
||||
|
@ -708,6 +761,7 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.redirectTo('/some-url', { state: 'some-state' }));
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if user has already acknowledged it', async () => {
|
||||
|
@ -724,6 +778,7 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.succeeded(mockUser, { state: 'some-state' }));
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement its own requests', async () => {
|
||||
|
@ -737,6 +792,7 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.succeeded(mockUser, { state: 'some-state' }));
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if it is not configured', async () => {
|
||||
|
@ -752,6 +808,7 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.succeeded(mockUser, { state: 'some-state' }));
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if license doesnt allow it.', async () => {
|
||||
|
@ -768,6 +825,7 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.succeeded(mockUser, { state: 'some-state' }));
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('redirects to Access Agreement when needed.', async () => {
|
||||
|
@ -793,6 +851,7 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('redirects to Access Agreement preserving redirect URL specified in login attempt.', async () => {
|
||||
|
@ -822,6 +881,7 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('redirects to Access Agreement preserving redirect URL specified in the authentication result.', async () => {
|
||||
|
@ -848,6 +908,7 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('redirects AJAX requests to Access Agreement when needed.', async () => {
|
||||
|
@ -873,6 +934,7 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -909,6 +971,10 @@ describe('Authenticator', () => {
|
|||
await expect(
|
||||
authenticator.login(request, { provider: { type: 'basic' }, value: {} })
|
||||
).resolves.toEqual(AuthenticationResult.succeeded(mockUser, { state: 'some-state' }));
|
||||
expectAuditEvents(
|
||||
{ action: 'user_logout', outcome: 'unknown' },
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
|
||||
it('does not redirect to Overwritten Session if username and provider did not change', async () => {
|
||||
|
@ -930,6 +996,7 @@ describe('Authenticator', () => {
|
|||
authResponseHeaders: { 'WWW-Authenticate': 'Negotiate' },
|
||||
})
|
||||
);
|
||||
expectAuditEvents({ action: 'user_login', outcome: 'success' });
|
||||
});
|
||||
|
||||
it('does not redirect to Overwritten Session if session was unauthenticated before login', async () => {
|
||||
|
@ -952,6 +1019,10 @@ describe('Authenticator', () => {
|
|||
authResponseHeaders: { 'WWW-Authenticate': 'Negotiate' },
|
||||
})
|
||||
);
|
||||
expectAuditEvents(
|
||||
// We do not record a user_logout event for "intermediate" sessions that are deleted, only user_login for the new session
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
|
||||
it('redirects to Overwritten Session when username changes', async () => {
|
||||
|
@ -977,6 +1048,10 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents(
|
||||
{ action: 'user_logout', outcome: 'unknown' },
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
|
||||
it('redirects to Overwritten Session when provider changes', async () => {
|
||||
|
@ -1005,6 +1080,10 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents(
|
||||
{ action: 'user_logout', outcome: 'unknown' },
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
|
||||
it('redirects to Overwritten Session preserving redirect URL specified in login attempt.', async () => {
|
||||
|
@ -1034,6 +1113,10 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents(
|
||||
{ action: 'user_logout', outcome: 'unknown' },
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
|
||||
it('redirects to Overwritten Session preserving redirect URL specified in the authentication result.', async () => {
|
||||
|
@ -1060,6 +1143,10 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents(
|
||||
{ action: 'user_logout', outcome: 'unknown' },
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
|
||||
it('redirects AJAX requests to Overwritten Session when needed.', async () => {
|
||||
|
@ -1085,6 +1172,10 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents(
|
||||
{ action: 'user_logout', outcome: 'unknown' },
|
||||
{ action: 'user_login', outcome: 'success' }
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1093,16 +1184,10 @@ describe('Authenticator', () => {
|
|||
let authenticator: Authenticator;
|
||||
let mockOptions: ReturnType<typeof getMockOptions>;
|
||||
let mockSessVal: SessionValue;
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
auditLogger.log.mockClear();
|
||||
mockOptions = getMockOptions({ providers: { basic: { basic1: { order: 0 } } } });
|
||||
mockOptions.session.get.mockResolvedValue(null);
|
||||
mockOptions.audit.asScoped.mockReturnValue(auditLogger);
|
||||
mockSessVal = sessionMock.createValue({ state: { authorization: 'Basic xxx' } });
|
||||
|
||||
authenticator = new Authenticator(mockOptions);
|
||||
|
@ -1112,6 +1197,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(undefined as any)).rejects.toThrowError(
|
||||
'Request should be a valid "KibanaRequest" instance, was [undefined].'
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('fails if an authentication provider fails.', async () => {
|
||||
|
@ -1125,6 +1211,7 @@ describe('Authenticator', () => {
|
|||
const authenticationResult = await authenticator.authenticate(request);
|
||||
expect(authenticationResult.failed()).toBe(true);
|
||||
expect(authenticationResult.error).toBe(failureReason);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns user that authentication provider returns.', async () => {
|
||||
|
@ -1140,6 +1227,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.succeeded(user, { authHeaders: { authorization: 'Basic .....' } })
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('creates session whenever authentication provider returns state for system API requests', async () => {
|
||||
|
@ -1163,6 +1251,7 @@ describe('Authenticator', () => {
|
|||
provider: mockSessVal.provider,
|
||||
state: { authorization },
|
||||
});
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('creates session whenever authentication provider returns state for non-system API requests', async () => {
|
||||
|
@ -1186,6 +1275,7 @@ describe('Authenticator', () => {
|
|||
provider: mockSessVal.provider,
|
||||
state: { authorization },
|
||||
});
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not extend session for system API calls.', async () => {
|
||||
|
@ -1207,6 +1297,7 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('extends session for non-system API calls.', async () => {
|
||||
|
@ -1229,6 +1320,7 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not touch session for system API calls if authentication fails with non-401 reason.', async () => {
|
||||
|
@ -1250,6 +1342,7 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not touch session for non-system API calls if authentication fails with non-401 reason.', async () => {
|
||||
|
@ -1271,6 +1364,7 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('replaces existing session with the one returned by authentication provider for system API requests', async () => {
|
||||
|
@ -1297,6 +1391,7 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('replaces existing session with the one returned by authentication provider for non-system API requests', async () => {
|
||||
|
@ -1323,6 +1418,7 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('clears session if provider failed to authenticate system API request with 401 with active session.', async () => {
|
||||
|
@ -1342,11 +1438,12 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.failed(failureReason)
|
||||
);
|
||||
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
|
||||
it('clears session if provider failed to authenticate non-system API request with 401 with active session.', async () => {
|
||||
|
@ -1366,11 +1463,12 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.failed(failureReason)
|
||||
);
|
||||
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
|
||||
it('clears session if provider requested it via setting state to `null`.', async () => {
|
||||
|
@ -1385,31 +1483,12 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.redirectTo('some-url', { state: null })
|
||||
);
|
||||
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('adds audit event when invalidating session.', async () => {
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
|
||||
mockBasicAuthenticationProvider.authenticate.mockResolvedValue(
|
||||
AuthenticationResult.redirectTo('some-url', { state: null })
|
||||
);
|
||||
mockOptions.session.get.mockResolvedValue(mockSessVal);
|
||||
|
||||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.redirectTo('some-url', { state: null })
|
||||
);
|
||||
|
||||
expect(auditLogger.log).toHaveBeenCalledTimes(1);
|
||||
expect(auditLogger.log).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
event: { action: 'user_logout', category: ['authentication'], outcome: 'unknown' },
|
||||
})
|
||||
);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
|
||||
it('does not clear session if provider can not handle system API request authentication with active session.', async () => {
|
||||
|
@ -1423,10 +1502,11 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.notHandled()
|
||||
);
|
||||
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not clear session if provider can not handle non-system API request authentication with active session.', async () => {
|
||||
|
@ -1440,10 +1520,11 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.notHandled()
|
||||
);
|
||||
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('with Login Selector', () => {
|
||||
|
@ -1464,6 +1545,7 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.notHandled()
|
||||
);
|
||||
expect(mockBasicAuthenticationProvider.authenticate).toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect AJAX requests to Login Selector', async () => {
|
||||
|
@ -1473,6 +1555,7 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.notHandled()
|
||||
);
|
||||
expect(mockBasicAuthenticationProvider.authenticate).toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Login Selector if request has `Authorization` header', async () => {
|
||||
|
@ -1484,6 +1567,7 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.notHandled()
|
||||
);
|
||||
expect(mockBasicAuthenticationProvider.authenticate).toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Login Selector if it is not enabled', async () => {
|
||||
|
@ -1495,6 +1579,7 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.notHandled()
|
||||
);
|
||||
expect(mockBasicAuthenticationProvider.authenticate).toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('redirects to the Login Selector when needed.', async () => {
|
||||
|
@ -1513,6 +1598,7 @@ describe('Authenticator', () => {
|
|||
)
|
||||
);
|
||||
expect(mockBasicAuthenticationProvider.authenticate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('redirects to the Login Selector with auth provider hint when needed.', async () => {
|
||||
|
@ -1536,6 +1622,7 @@ describe('Authenticator', () => {
|
|||
);
|
||||
|
||||
expect(mockBasicAuthenticationProvider.authenticate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1565,6 +1652,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.succeeded(mockUser)
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect AJAX requests to Access Agreement', async () => {
|
||||
|
@ -1574,6 +1662,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.succeeded(mockUser)
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if request cannot be handled', async () => {
|
||||
|
@ -1587,6 +1676,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.notHandled()
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if authentication fails', async () => {
|
||||
|
@ -1601,6 +1691,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.failed(failureReason)
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if redirect is required to complete authentication', async () => {
|
||||
|
@ -1614,6 +1705,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.redirectTo('/some-url')
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if user has already acknowledged it', async () => {
|
||||
|
@ -1626,6 +1718,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.succeeded(mockUser)
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement its own requests', async () => {
|
||||
|
@ -1635,6 +1728,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.succeeded(mockUser)
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if it is not configured', async () => {
|
||||
|
@ -1646,6 +1740,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.succeeded(mockUser)
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Access Agreement if license doesnt allow it.', async () => {
|
||||
|
@ -1658,6 +1753,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.succeeded(mockUser)
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('redirects to Access Agreement when needed.', async () => {
|
||||
|
@ -1677,6 +1773,7 @@ describe('Authenticator', () => {
|
|||
{ user: mockUser, authResponseHeaders: { 'WWW-Authenticate': 'Negotiate' } }
|
||||
)
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1712,6 +1809,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.authenticate(request)).resolves.toEqual(
|
||||
AuthenticationResult.succeeded(mockUser)
|
||||
);
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
|
||||
it('does not redirect AJAX requests to Overwritten Session', async () => {
|
||||
|
@ -1731,6 +1829,7 @@ describe('Authenticator', () => {
|
|||
authResponseHeaders: { 'WWW-Authenticate': 'Negotiate' },
|
||||
})
|
||||
);
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
|
||||
it('does not redirect to Overwritten Session if username and provider did not change', async () => {
|
||||
|
@ -1750,6 +1849,7 @@ describe('Authenticator', () => {
|
|||
authResponseHeaders: { 'WWW-Authenticate': 'Negotiate' },
|
||||
})
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('redirects to Overwritten Session when username changes', async () => {
|
||||
|
@ -1773,6 +1873,7 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
|
||||
it('redirects to Overwritten Session when provider changes', async () => {
|
||||
|
@ -1799,6 +1900,7 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
|
||||
it('redirects to Overwritten Session preserving redirect URL specified in the authentication result.', async () => {
|
||||
|
@ -1823,6 +1925,7 @@ describe('Authenticator', () => {
|
|||
}
|
||||
)
|
||||
);
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1831,16 +1934,10 @@ describe('Authenticator', () => {
|
|||
let authenticator: Authenticator;
|
||||
let mockOptions: ReturnType<typeof getMockOptions>;
|
||||
let mockSessVal: SessionValue;
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
auditLogger.log.mockClear();
|
||||
mockOptions = getMockOptions({ providers: { basic: { basic1: { order: 0 } } } });
|
||||
mockOptions.session.get.mockResolvedValue(null);
|
||||
mockOptions.audit.asScoped.mockReturnValue(auditLogger);
|
||||
mockSessVal = sessionMock.createValue({ state: { authorization: 'Basic xxx' } });
|
||||
|
||||
authenticator = new Authenticator(mockOptions);
|
||||
|
@ -1863,8 +1960,8 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
|
||||
expect(mockBasicAuthenticationProvider.authenticate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not redirect to Login Selector even if it is enabled if session is not available.', async () => {
|
||||
|
@ -1885,8 +1982,8 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
|
||||
expect(mockBasicAuthenticationProvider.authenticate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not clear session if provider cannot handle authentication', async () => {
|
||||
|
@ -1905,12 +2002,12 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
|
||||
expect(mockBasicAuthenticationProvider.authenticate).toHaveBeenCalledTimes(1);
|
||||
expect(mockBasicAuthenticationProvider.authenticate).toBeCalledWith(
|
||||
request,
|
||||
mockSessVal.state
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not clear session if authentication fails with non-401 reason.', async () => {
|
||||
|
@ -1930,6 +2027,7 @@ describe('Authenticator', () => {
|
|||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('extends session if no update is needed.', async () => {
|
||||
|
@ -1945,11 +2043,12 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.succeeded(user)
|
||||
);
|
||||
|
||||
expect(mockOptions.session.extend).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.extend).toHaveBeenCalledWith(request, mockSessVal);
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.extend).toHaveBeenCalledWith(request, mockSessVal);
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('replaces existing session with the one returned by authentication provider', async () => {
|
||||
|
@ -1966,14 +2065,15 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.succeeded(user, { state: newState })
|
||||
);
|
||||
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.update).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.update).toHaveBeenCalledWith(request, {
|
||||
...mockSessVal,
|
||||
state: newState,
|
||||
});
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('clears session if provider failed to authenticate request with 401.', async () => {
|
||||
|
@ -1991,18 +2091,12 @@ describe('Authenticator', () => {
|
|||
AuthenticationResult.failed(failureReason)
|
||||
);
|
||||
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expect(mockOptions.session.create).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.extend).not.toHaveBeenCalled();
|
||||
|
||||
expect(auditLogger.log).toHaveBeenCalledTimes(1);
|
||||
expect(auditLogger.log).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
event: { action: 'user_logout', category: ['authentication'], outcome: 'unknown' },
|
||||
})
|
||||
);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalledWith(request, { match: 'current' });
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -2010,15 +2104,9 @@ describe('Authenticator', () => {
|
|||
let authenticator: Authenticator;
|
||||
let mockOptions: ReturnType<typeof getMockOptions>;
|
||||
let mockSessVal: SessionValue;
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
auditLogger.log.mockClear();
|
||||
mockOptions = getMockOptions({ providers: { basic: { basic1: { order: 0 } } } });
|
||||
mockOptions.audit.asScoped.mockReturnValue(auditLogger);
|
||||
mockSessVal = sessionMock.createValue({ state: { authorization: 'Basic xxx' } });
|
||||
|
||||
authenticator = new Authenticator(mockOptions);
|
||||
|
@ -2028,6 +2116,7 @@ describe('Authenticator', () => {
|
|||
await expect(authenticator.logout(undefined as any)).rejects.toThrowError(
|
||||
'Request should be a valid "KibanaRequest" instance, was [undefined].'
|
||||
);
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('redirects to login form if session does not exist.', async () => {
|
||||
|
@ -2040,6 +2129,7 @@ describe('Authenticator', () => {
|
|||
);
|
||||
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('clears session and returns whatever authentication provider returns.', async () => {
|
||||
|
@ -2055,25 +2145,7 @@ describe('Authenticator', () => {
|
|||
|
||||
expect(mockBasicAuthenticationProvider.logout).toHaveBeenCalledTimes(1);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('adds audit event.', async () => {
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
mockBasicAuthenticationProvider.logout.mockResolvedValue(
|
||||
DeauthenticationResult.redirectTo('some-url')
|
||||
);
|
||||
mockOptions.session.get.mockResolvedValue(mockSessVal);
|
||||
|
||||
await expect(authenticator.logout(request)).resolves.toEqual(
|
||||
DeauthenticationResult.redirectTo('some-url')
|
||||
);
|
||||
|
||||
expect(auditLogger.log).toHaveBeenCalledTimes(1);
|
||||
expect(auditLogger.log).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
event: { action: 'user_logout', category: ['authentication'], outcome: 'unknown' },
|
||||
})
|
||||
);
|
||||
expectAuditEvents({ action: 'user_logout', outcome: 'unknown' });
|
||||
});
|
||||
|
||||
it('if session does not exist but provider name is valid, returns whatever authentication provider returns.', async () => {
|
||||
|
@ -2093,6 +2165,7 @@ describe('Authenticator', () => {
|
|||
expect(mockBasicAuthenticationProvider.logout).toHaveBeenCalledTimes(1);
|
||||
expect(mockBasicAuthenticationProvider.logout).toHaveBeenCalledWith(request, null);
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('if session does not exist and provider name is not available, returns whatever authentication provider returns.', async () => {
|
||||
|
@ -2110,6 +2183,7 @@ describe('Authenticator', () => {
|
|||
expect(mockBasicAuthenticationProvider.logout).toHaveBeenCalledTimes(1);
|
||||
expect(mockBasicAuthenticationProvider.logout).toHaveBeenCalledWith(request);
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('if session does not exist and providers is empty, redirects to default logout path.', async () => {
|
||||
|
@ -2128,6 +2202,7 @@ describe('Authenticator', () => {
|
|||
|
||||
expect(mockBasicAuthenticationProvider.logout).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('redirects to login form if session does not exist and provider name is invalid', async () => {
|
||||
|
@ -2140,6 +2215,7 @@ describe('Authenticator', () => {
|
|||
|
||||
expect(mockBasicAuthenticationProvider.logout).not.toHaveBeenCalled();
|
||||
expect(mockOptions.session.invalidate).toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -2147,16 +2223,11 @@ describe('Authenticator', () => {
|
|||
let authenticator: Authenticator;
|
||||
let mockOptions: ReturnType<typeof getMockOptions>;
|
||||
let mockSessionValue: SessionValue;
|
||||
const auditLogger = {
|
||||
log: jest.fn(),
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockOptions = getMockOptions({ providers: { basic: { basic1: { order: 0 } } } });
|
||||
mockSessionValue = sessionMock.createValue({ state: { authorization: 'Basic xxx' } });
|
||||
mockOptions.session.get.mockResolvedValue(mockSessionValue);
|
||||
mockOptions.audit.asScoped.mockReturnValue(auditLogger);
|
||||
mockOptions.getCurrentUser.mockReturnValue(mockAuthenticatedUser());
|
||||
mockOptions.license.getFeatures.mockReturnValue({
|
||||
allowAccessAgreement: true,
|
||||
|
@ -2176,6 +2247,7 @@ describe('Authenticator', () => {
|
|||
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.featureUsageService.recordPreAccessAgreementUsage).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('fails if cannot retrieve user session', async () => {
|
||||
|
@ -2189,6 +2261,7 @@ describe('Authenticator', () => {
|
|||
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(mockOptions.featureUsageService.recordPreAccessAgreementUsage).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('fails if license does not allow access agreement acknowledgement', async () => {
|
||||
|
@ -2203,6 +2276,7 @@ describe('Authenticator', () => {
|
|||
);
|
||||
|
||||
expect(mockOptions.session.update).not.toHaveBeenCalled();
|
||||
expect(auditLogger.log).not.toHaveBeenCalled();
|
||||
expect(mockOptions.featureUsageService.recordPreAccessAgreementUsage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -2215,17 +2289,10 @@ describe('Authenticator', () => {
|
|||
...mockSessionValue,
|
||||
accessAgreementAcknowledged: true,
|
||||
});
|
||||
|
||||
expect(auditLogger.log).toHaveBeenCalledTimes(1);
|
||||
expect(auditLogger.log).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
event: { action: 'access_agreement_acknowledged', category: ['authentication'] },
|
||||
})
|
||||
);
|
||||
|
||||
expect(mockOptions.featureUsageService.recordPreAccessAgreementUsage).toHaveBeenCalledTimes(
|
||||
1
|
||||
);
|
||||
expectAuditEvents({ action: 'access_agreement_acknowledged' });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -90,6 +90,16 @@ export interface AuthenticatorOptions {
|
|||
getServerBaseURL: () => string;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
interface InvalidateSessionValueParams {
|
||||
/** Request instance. */
|
||||
request: KibanaRequest;
|
||||
/** Value of the existing session, if any. */
|
||||
sessionValue: SessionValue | null;
|
||||
/** If enabled, skips writing a `user_logout` audit event for this session. */
|
||||
skipAuditEvent?: boolean;
|
||||
}
|
||||
|
||||
// Mapping between provider key defined in the config and authentication
|
||||
// provider class that can handle specific authentication mechanism.
|
||||
const providerMap = new Map<
|
||||
|
@ -325,6 +335,9 @@ export class Authenticator {
|
|||
const auditLogger = this.options.audit.asScoped(request);
|
||||
auditLogger.log(
|
||||
userLoginEvent({
|
||||
// We must explicitly specify the sessionId for login events because we just created the session, so
|
||||
// it won't automatically get included in the audit event from the request context.
|
||||
sessionId: sessionUpdateResult?.value?.sid,
|
||||
authenticationResult,
|
||||
authenticationProvider: providerName,
|
||||
authenticationType: provider.type,
|
||||
|
@ -446,7 +459,7 @@ export class Authenticator {
|
|||
sessionValue?.provider.name ??
|
||||
request.url.searchParams.get(LOGOUT_PROVIDER_QUERY_STRING_PARAMETER);
|
||||
if (suggestedProviderName) {
|
||||
await this.invalidateSessionValue(request, sessionValue);
|
||||
await this.invalidateSessionValue({ request, sessionValue });
|
||||
|
||||
// Provider name may be passed in a query param and sourced from the browser's local storage;
|
||||
// hence, we can't assume that this provider exists, so we have to check it.
|
||||
|
@ -595,7 +608,7 @@ export class Authenticator {
|
|||
this.logger.warn(
|
||||
`Attempted to retrieve session for the "${existingSessionValue.provider.type}/${existingSessionValue.provider.name}" provider, but it is not configured.`
|
||||
);
|
||||
await this.invalidateSessionValue(request, existingSessionValue);
|
||||
await this.invalidateSessionValue({ request, sessionValue: existingSessionValue });
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -629,7 +642,7 @@ export class Authenticator {
|
|||
// attempt didn't fail.
|
||||
if (authenticationResult.shouldClearState()) {
|
||||
this.logger.debug('Authentication provider requested to invalidate existing session.');
|
||||
await this.invalidateSessionValue(request, existingSessionValue);
|
||||
await this.invalidateSessionValue({ request, sessionValue: existingSessionValue });
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -643,7 +656,7 @@ export class Authenticator {
|
|||
if (authenticationResult.failed()) {
|
||||
if (ownsSession && getErrorStatusCode(authenticationResult.error) === 401) {
|
||||
this.logger.debug('Authentication attempt failed, existing session will be invalidated.');
|
||||
await this.invalidateSessionValue(request, existingSessionValue);
|
||||
await this.invalidateSessionValue({ request, sessionValue: existingSessionValue });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -681,17 +694,21 @@ export class Authenticator {
|
|||
this.logger.debug(
|
||||
'Authentication provider has changed, existing session will be invalidated.'
|
||||
);
|
||||
await this.invalidateSessionValue(request, existingSessionValue);
|
||||
await this.invalidateSessionValue({ request, sessionValue: existingSessionValue });
|
||||
existingSessionValue = null;
|
||||
} else if (sessionHasBeenAuthenticated) {
|
||||
this.logger.debug(
|
||||
'Session is authenticated, existing unauthenticated session will be invalidated.'
|
||||
);
|
||||
await this.invalidateSessionValue(request, existingSessionValue);
|
||||
await this.invalidateSessionValue({
|
||||
request,
|
||||
sessionValue: existingSessionValue,
|
||||
skipAuditEvent: true, // Skip writing an audit event when we are replacing an intermediate session with a fullly authenticated session
|
||||
});
|
||||
existingSessionValue = null;
|
||||
} else if (usernameHasChanged) {
|
||||
this.logger.debug('Username has changed, existing session will be invalidated.');
|
||||
await this.invalidateSessionValue(request, existingSessionValue);
|
||||
await this.invalidateSessionValue({ request, sessionValue: existingSessionValue });
|
||||
existingSessionValue = null;
|
||||
}
|
||||
|
||||
|
@ -726,11 +743,13 @@ export class Authenticator {
|
|||
|
||||
/**
|
||||
* Invalidates session value associated with the specified request.
|
||||
* @param request Request instance.
|
||||
* @param sessionValue Value of the existing session if any.
|
||||
*/
|
||||
private async invalidateSessionValue(request: KibanaRequest, sessionValue: SessionValue | null) {
|
||||
if (sessionValue) {
|
||||
private async invalidateSessionValue({
|
||||
request,
|
||||
sessionValue,
|
||||
skipAuditEvent,
|
||||
}: InvalidateSessionValueParams) {
|
||||
if (sessionValue && !skipAuditEvent) {
|
||||
const auditLogger = this.options.audit.asScoped(request);
|
||||
auditLogger.log(
|
||||
userLogoutEvent({
|
||||
|
|
|
@ -10,7 +10,7 @@ import type { TransportResult } from '@elastic/elasticsearch';
|
|||
import { licenseMock } from '../common/licensing/index.mock';
|
||||
import type { MockAuthenticatedUserProps } from '../common/model/authenticated_user.mock';
|
||||
import { mockAuthenticatedUser } from '../common/model/authenticated_user.mock';
|
||||
import { auditServiceMock } from './audit/index.mock';
|
||||
import { auditServiceMock } from './audit/mocks';
|
||||
import { authenticationServiceMock } from './authentication/authentication_service.mock';
|
||||
import { authorizationMock } from './authorization/index.mock';
|
||||
|
||||
|
|
|
@ -15,10 +15,10 @@ import type {
|
|||
SavedObjectsResolveResponse,
|
||||
SavedObjectsUpdateObjectsSpacesResponseObject,
|
||||
} from 'src/core/server';
|
||||
import { httpServerMock, savedObjectsClientMock } from 'src/core/server/mocks';
|
||||
import { savedObjectsClientMock } from 'src/core/server/mocks';
|
||||
|
||||
import type { AuditEvent } from '../audit';
|
||||
import { auditServiceMock } from '../audit/index.mock';
|
||||
import { auditLoggerMock } from '../audit/mocks';
|
||||
import { Actions } from '../authorization';
|
||||
import type { SavedObjectActions } from '../authorization/actions/saved_object';
|
||||
import { SecureSavedObjectsClientWrapper } from './secure_saved_objects_client_wrapper';
|
||||
|
@ -65,7 +65,7 @@ const createSecureSavedObjectsClientWrapperOptions = () => {
|
|||
checkSavedObjectsPrivilegesAsCurrentUser: jest.fn(),
|
||||
errors,
|
||||
getSpacesService,
|
||||
auditLogger: auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest()),
|
||||
auditLogger: auditLoggerMock.create(),
|
||||
forbiddenError,
|
||||
generalError,
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@ import type { ElasticsearchClient } from 'src/core/server';
|
|||
import { elasticsearchServiceMock, loggingSystemMock } from 'src/core/server/mocks';
|
||||
|
||||
import type { AuditLogger } from '../audit';
|
||||
import { auditServiceMock } from '../audit/index.mock';
|
||||
import { auditLoggerMock } from '../audit/mocks';
|
||||
import { ConfigSchema, createConfig } from '../config';
|
||||
import { securityMock } from '../mocks';
|
||||
import { getSessionIndexTemplate, SessionIndex } from './session_index';
|
||||
|
@ -32,7 +32,7 @@ describe('Session index', () => {
|
|||
const indexTemplateName = '.kibana_some_tenant_security_session_index_template_1';
|
||||
beforeEach(() => {
|
||||
mockElasticsearchClient = elasticsearchServiceMock.createElasticsearchClient();
|
||||
auditLogger = auditServiceMock.create().withoutRequest;
|
||||
auditLogger = auditLoggerMock.create();
|
||||
sessionIndex = new SessionIndex({
|
||||
logger: loggingSystemMock.createLogger(),
|
||||
kibanaIndexName: '.kibana_some_tenant',
|
||||
|
@ -364,7 +364,7 @@ describe('Session index', () => {
|
|||
{ isTLSEnabled: false }
|
||||
),
|
||||
elasticsearchClient: mockElasticsearchClient,
|
||||
auditLogger: auditServiceMock.create().withoutRequest,
|
||||
auditLogger,
|
||||
});
|
||||
|
||||
await sessionIndex.cleanUp();
|
||||
|
@ -456,7 +456,7 @@ describe('Session index', () => {
|
|||
{ isTLSEnabled: false }
|
||||
),
|
||||
elasticsearchClient: mockElasticsearchClient,
|
||||
auditLogger: auditServiceMock.create().withoutRequest,
|
||||
auditLogger,
|
||||
});
|
||||
|
||||
await sessionIndex.cleanUp();
|
||||
|
@ -542,7 +542,7 @@ describe('Session index', () => {
|
|||
{ isTLSEnabled: false }
|
||||
),
|
||||
elasticsearchClient: mockElasticsearchClient,
|
||||
auditLogger: auditServiceMock.create().withoutRequest,
|
||||
auditLogger,
|
||||
});
|
||||
|
||||
await sessionIndex.cleanUp();
|
||||
|
@ -653,7 +653,7 @@ describe('Session index', () => {
|
|||
{ isTLSEnabled: false }
|
||||
),
|
||||
elasticsearchClient: mockElasticsearchClient,
|
||||
auditLogger: auditServiceMock.create().withoutRequest,
|
||||
auditLogger,
|
||||
});
|
||||
|
||||
await sessionIndex.cleanUp();
|
||||
|
|
|
@ -16,7 +16,7 @@ import type {
|
|||
} from '../../../task_manager/server';
|
||||
import { taskManagerMock } from '../../../task_manager/server/mocks';
|
||||
import type { AuditLogger } from '../audit';
|
||||
import { auditServiceMock } from '../audit/index.mock';
|
||||
import { auditLoggerMock } from '../audit/mocks';
|
||||
import { ConfigSchema, createConfig } from '../config';
|
||||
import type { OnlineStatusRetryScheduler } from '../elasticsearch';
|
||||
import { Session } from './session';
|
||||
|
@ -37,7 +37,7 @@ describe('SessionManagementService', () => {
|
|||
let auditLogger: AuditLogger;
|
||||
beforeEach(() => {
|
||||
service = new SessionManagementService(loggingSystemMock.createLogger());
|
||||
auditLogger = auditServiceMock.create().withoutRequest;
|
||||
auditLogger = auditLoggerMock.create();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
@ -20,7 +20,7 @@ import type { GetAllSpacesPurpose, LegacyUrlAliasTarget, Space } from '../../../
|
|||
import { spacesClientMock } from '../../../spaces/server/mocks';
|
||||
import type { AuditEvent, AuditLogger } from '../audit';
|
||||
import { SavedObjectAction, SpaceAuditAction } from '../audit';
|
||||
import { auditServiceMock } from '../audit/index.mock';
|
||||
import { auditLoggerMock } from '../audit/mocks';
|
||||
import type {
|
||||
AuthorizationServiceSetup,
|
||||
AuthorizationServiceSetupInternal,
|
||||
|
@ -98,7 +98,7 @@ const setup = ({ securityEnabled = false }: Opts = {}) => {
|
|||
});
|
||||
authorization.mode.useRbacForRequest.mockReturnValue(securityEnabled);
|
||||
|
||||
const auditLogger = auditServiceMock.create().asScoped(httpServerMock.createKibanaRequest());
|
||||
const auditLogger = auditLoggerMock.create();
|
||||
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { coreMock, httpServerMock } from 'src/core/server/mocks';
|
||||
|
||||
import { spacesMock } from '../../../spaces/server/mocks';
|
||||
import { auditServiceMock } from '../audit/index.mock';
|
||||
import { auditServiceMock } from '../audit/mocks';
|
||||
import { authorizationMock } from '../authorization/index.mock';
|
||||
import { setupSpacesClient } from './setup_spaces_client';
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue