[Alerting Plugin] Migrate authc.getCurrentUser usage to core.security (#187020)

Part of https://github.com/elastic/kibana/issues/186574

## Summary

This PR migrates the Alerting Plugin's server-side code that consumes
`authc.getCurrentUser` to use coreContext.security.

Background: This PR serves as an example of a plugin migrating away from
depending on the Security plugin, which is a high priority effort for
the last release before 9.0.

### Checklist

Delete any items that are not applicable to this PR.

- [X] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
This commit is contained in:
Tim Sullivan 2024-07-01 17:05:32 -07:00 committed by GitHub
parent c209f3442d
commit 01cce981bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 50 additions and 63 deletions

View file

@ -14,9 +14,9 @@ import {
savedObjectsServiceMock,
loggingSystemMock,
uiSettingsServiceMock,
securityServiceMock,
} from '@kbn/core/server/mocks';
import { AuthenticatedUser } from '@kbn/security-plugin/common';
import { securityMock } from '@kbn/security-plugin/server/mocks';
import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server';
import { MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE } from '../common';
@ -24,12 +24,13 @@ jest.mock('./maintenance_window_client');
const savedObjectsClient = savedObjectsClientMock.create();
const savedObjectsService = savedObjectsServiceMock.createInternalStartContract();
const securityPluginStart = securityMock.createStart();
const securityService = securityServiceMock.createStart();
const uiSettings = uiSettingsServiceMock.createStartContract();
const maintenanceWindowClientFactoryParams: jest.Mocked<MaintenanceWindowClientFactoryOpts> = {
logger: loggingSystemMock.create().get(),
savedObjectsService,
securityService,
uiSettings,
};
@ -39,10 +40,7 @@ beforeEach(() => {
test('creates a maintenance window client with proper constructor arguments when security is enabled', async () => {
const factory = new MaintenanceWindowClientFactory();
factory.initialize({
securityPluginStart,
...maintenanceWindowClientFactoryParams,
});
factory.initialize(maintenanceWindowClientFactoryParams);
const request = mockRouter.createKibanaRequest();
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
@ -86,10 +84,7 @@ test('creates a maintenance window client with proper constructor arguments', as
test('creates an unauthorized maintenance window client', async () => {
const factory = new MaintenanceWindowClientFactory();
factory.initialize({
securityPluginStart,
...maintenanceWindowClientFactoryParams,
});
factory.initialize(maintenanceWindowClientFactoryParams);
const request = mockRouter.createKibanaRequest();
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
@ -125,10 +120,7 @@ test('getUserName() returns null when security is disabled', async () => {
test('getUserName() returns a name when security is enabled', async () => {
const factory = new MaintenanceWindowClientFactory();
factory.initialize({
securityPluginStart,
...maintenanceWindowClientFactoryParams,
});
factory.initialize(maintenanceWindowClientFactoryParams);
const request = mockRouter.createKibanaRequest();
factory.createWithAuthorization(request);
@ -136,7 +128,7 @@ test('getUserName() returns a name when security is enabled', async () => {
const constructorCall = jest.requireMock('./maintenance_window_client').MaintenanceWindowClient
.mock.calls[0][0];
securityPluginStart.authc.getCurrentUser.mockReturnValueOnce({
securityService.authc.getCurrentUser.mockReturnValueOnce({
username: 'testname',
} as unknown as AuthenticatedUser);
const userNameResult = await constructorCall.getUserName();

View file

@ -10,16 +10,16 @@ import {
Logger,
SavedObjectsServiceStart,
SECURITY_EXTENSION_ID,
SecurityServiceStart,
UiSettingsServiceStart,
} from '@kbn/core/server';
import { SecurityPluginStart } from '@kbn/security-plugin/server';
import { MaintenanceWindowClient } from './maintenance_window_client';
import { MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE } from '../common';
export interface MaintenanceWindowClientFactoryOpts {
logger: Logger;
savedObjectsService: SavedObjectsServiceStart;
securityPluginStart?: SecurityPluginStart;
securityService: SecurityServiceStart;
uiSettings: UiSettingsServiceStart;
}
@ -27,7 +27,7 @@ export class MaintenanceWindowClientFactory {
private isInitialized = false;
private logger!: Logger;
private savedObjectsService!: SavedObjectsServiceStart;
private securityPluginStart?: SecurityPluginStart;
private securityService!: SecurityServiceStart;
private uiSettings!: UiSettingsServiceStart;
public initialize(options: MaintenanceWindowClientFactoryOpts) {
@ -37,12 +37,12 @@ export class MaintenanceWindowClientFactory {
this.isInitialized = true;
this.logger = options.logger;
this.savedObjectsService = options.savedObjectsService;
this.securityPluginStart = options.securityPluginStart;
this.securityService = options.securityService;
this.uiSettings = options.uiSettings;
}
private createMaintenanceWindowClient(request: KibanaRequest, withAuth: boolean) {
const { securityPluginStart } = this;
const { securityService } = this;
const savedObjectsClient = this.savedObjectsService.getScopedClient(request, {
includedHiddenTypes: [MAINTENANCE_WINDOW_SAVED_OBJECT_TYPE],
...(withAuth ? {} : { excludedExtensions: [SECURITY_EXTENSION_ID] }),
@ -55,11 +55,8 @@ export class MaintenanceWindowClientFactory {
savedObjectsClient,
uiSettings: uiSettingClient,
async getUserName() {
if (!securityPluginStart || !request) {
return null;
}
const user = securityPluginStart.authc.getCurrentUser(request);
return user ? user.username : null;
const user = securityService.authc.getCurrentUser(request);
return user?.username ?? null;
},
});
}

View file

@ -541,19 +541,20 @@ export class AlertingPlugin {
backfillClient: this.backfillClient!,
connectorAdapterRegistry: this.connectorAdapterRegistry,
uiSettings: core.uiSettings,
securityService: core.security,
});
rulesSettingsClientFactory.initialize({
logger: this.logger,
savedObjectsService: core.savedObjects,
securityPluginStart: plugins.security,
securityService: core.security,
isServerless: !!plugins.serverless,
});
maintenanceWindowClientFactory.initialize({
logger: this.logger,
savedObjectsService: core.savedObjects,
securityPluginStart: plugins.security,
securityService: core.security,
uiSettings: core.uiSettings,
});

View file

@ -14,6 +14,7 @@ import {
loggingSystemMock,
savedObjectsRepositoryMock,
uiSettingsServiceMock,
securityServiceMock,
} from '@kbn/core/server/mocks';
import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks';
import { AuthenticatedUser } from '@kbn/security-plugin/common';
@ -43,6 +44,7 @@ const savedObjectsService = savedObjectsServiceMock.createInternalStartContract(
const securityPluginSetup = securityMock.createSetup();
const securityPluginStart = securityMock.createStart();
const securityService = securityServiceMock.createStart();
const alertingAuthorization = alertingAuthorizationMock.create();
const alertingAuthorizationClientFactory = alertingAuthorizationClientFactoryMock.createFactory();
@ -67,6 +69,7 @@ const rulesClientFactoryParams: jest.Mocked<RulesClientFactoryOpts> = {
backfillClient,
connectorAdapterRegistry: new ConnectorAdapterRegistry(),
uiSettings: uiSettingsServiceMock.createStartContract(),
securityService: securityServiceMock.createStart(),
getAlertIndicesAlias: jest.fn(),
alertsService: null,
};
@ -87,7 +90,11 @@ beforeEach(() => {
test('creates a rules client with proper constructor arguments when security is enabled', async () => {
const factory = new RulesClientFactory();
factory.initialize({ securityPluginSetup, securityPluginStart, ...rulesClientFactoryParams });
factory.initialize({
securityPluginSetup,
securityPluginStart,
...rulesClientFactoryParams,
});
const request = mockRouter.createKibanaRequest();
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
@ -207,13 +214,12 @@ test('getUserName() returns a name when security is enabled', async () => {
const factory = new RulesClientFactory();
factory.initialize({
...rulesClientFactoryParams,
securityPluginSetup,
securityPluginStart,
securityService,
});
factory.create(mockRouter.createKibanaRequest(), savedObjectsService);
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
securityPluginStart.authc.getCurrentUser.mockReturnValueOnce({
securityService.authc.getCurrentUser.mockReturnValueOnce({
username: 'bob',
} as unknown as AuthenticatedUser);
const userNameResult = await constructorCall.getUserName();
@ -255,6 +261,7 @@ test('createAPIKey() returns an API key when security is enabled', async () => {
const factory = new RulesClientFactory();
factory.initialize({
...rulesClientFactoryParams,
securityService,
securityPluginSetup,
securityPluginStart,
});
@ -285,6 +292,7 @@ test('createAPIKey() throws when security plugin createAPIKey throws an error',
const factory = new RulesClientFactory();
factory.initialize({
...rulesClientFactoryParams,
securityService,
securityPluginSetup,
securityPluginStart,
});

View file

@ -58,6 +58,7 @@ export interface RulesClientFactoryOpts {
backfillClient: BackfillClient;
connectorAdapterRegistry: ConnectorAdapterRegistry;
uiSettings: CoreStart['uiSettings'];
securityService: CoreStart['security'];
}
export class RulesClientFactory {
@ -83,6 +84,7 @@ export class RulesClientFactory {
private backfillClient!: BackfillClient;
private connectorAdapterRegistry!: ConnectorAdapterRegistry;
private uiSettings!: CoreStart['uiSettings'];
private securityService!: CoreStart['security'];
public initialize(options: RulesClientFactoryOpts) {
if (this.isInitialized) {
@ -110,10 +112,11 @@ export class RulesClientFactory {
this.backfillClient = options.backfillClient;
this.connectorAdapterRegistry = options.connectorAdapterRegistry;
this.uiSettings = options.uiSettings;
this.securityService = options.securityService;
}
public create(request: KibanaRequest, savedObjects: SavedObjectsServiceStart): RulesClient {
const { securityPluginSetup, securityPluginStart, actions, eventLog } = this;
const { securityPluginSetup, securityService, securityPluginStart, actions, eventLog } = this;
const spaceId = this.getSpaceId(request);
if (!this.authorization) {
@ -149,11 +152,8 @@ export class RulesClientFactory {
uiSettings: this.uiSettings,
async getUserName() {
if (!securityPluginStart) {
return null;
}
const user = await securityPluginStart.authc.getCurrentUser(request);
return user ? user.username : null;
const user = securityService.authc.getCurrentUser(request);
return user?.username ?? null;
},
async createAPIKey(name: string) {
if (!securityPluginStart) {
@ -185,7 +185,7 @@ export class RulesClientFactory {
if (!securityPluginStart) {
return false;
}
const user = securityPluginStart.authc.getCurrentUser(request);
const user = securityService.authc.getCurrentUser(request);
return user && user.authentication_type ? user.authentication_type === 'api_key' : false;
},
getAuthenticationAPIKey(name: string) {

View file

@ -14,9 +14,9 @@ import {
savedObjectsClientMock,
savedObjectsServiceMock,
loggingSystemMock,
securityServiceMock,
} from '@kbn/core/server/mocks';
import { AuthenticatedUser } from '@kbn/security-plugin/common';
import { securityMock } from '@kbn/security-plugin/server/mocks';
import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server';
import { RULES_SETTINGS_SAVED_OBJECT_TYPE } from '../common';
@ -25,11 +25,12 @@ jest.mock('./rules_settings_client');
const savedObjectsClient = savedObjectsClientMock.create();
const savedObjectsService = savedObjectsServiceMock.createInternalStartContract();
const securityPluginStart = securityMock.createStart();
const securityService = securityServiceMock.createStart();
const rulesSettingsClientFactoryParams: jest.Mocked<RulesSettingsClientFactoryOpts> = {
logger: loggingSystemMock.create().get(),
savedObjectsService,
securityService,
isServerless: false,
};
@ -39,10 +40,7 @@ beforeEach(() => {
test('creates a rules settings client with proper constructor arguments when security is enabled', async () => {
const factory = new RulesSettingsClientFactory();
factory.initialize({
securityPluginStart,
...rulesSettingsClientFactoryParams,
});
factory.initialize(rulesSettingsClientFactoryParams);
const request = mockRouter.createKibanaRequest();
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
@ -88,10 +86,7 @@ test('creates a rules settings client with proper constructor arguments', async
test('creates an unauthorized rules settings client', async () => {
const factory = new RulesSettingsClientFactory();
factory.initialize({
securityPluginStart,
...rulesSettingsClientFactoryParams,
});
factory.initialize(rulesSettingsClientFactoryParams);
const request = mockRouter.createKibanaRequest();
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
@ -128,10 +123,7 @@ test('getUserName() returns null when security is disabled', async () => {
test('getUserName() returns a name when security is enabled', async () => {
const factory = new RulesSettingsClientFactory();
factory.initialize({
securityPluginStart,
...rulesSettingsClientFactoryParams,
});
factory.initialize(rulesSettingsClientFactoryParams);
const request = mockRouter.createKibanaRequest();
factory.createWithAuthorization(request);
@ -139,7 +131,7 @@ test('getUserName() returns a name when security is enabled', async () => {
const constructorCall =
jest.requireMock('./rules_settings_client').RulesSettingsClient.mock.calls[0][0];
securityPluginStart.authc.getCurrentUser.mockReturnValueOnce({
securityService.authc.getCurrentUser.mockReturnValueOnce({
username: 'testname',
} as unknown as AuthenticatedUser);
const userNameResult = await constructorCall.getUserName();

View file

@ -10,8 +10,8 @@ import {
Logger,
SavedObjectsServiceStart,
SECURITY_EXTENSION_ID,
SecurityServiceStart,
} from '@kbn/core/server';
import { SecurityPluginStart } from '@kbn/security-plugin/server';
import { RulesSettingsClient } from './rules_settings_client';
import { RULES_SETTINGS_SAVED_OBJECT_TYPE } from '../common';
@ -19,14 +19,14 @@ export interface RulesSettingsClientFactoryOpts {
logger: Logger;
savedObjectsService: SavedObjectsServiceStart;
isServerless: boolean;
securityPluginStart?: SecurityPluginStart;
securityService: SecurityServiceStart;
}
export class RulesSettingsClientFactory {
private isInitialized = false;
private logger!: Logger;
private savedObjectsService!: SavedObjectsServiceStart;
private securityPluginStart?: SecurityPluginStart;
private securityService!: SecurityServiceStart;
private isServerless = false;
public initialize(options: RulesSettingsClientFactoryOpts) {
@ -36,12 +36,12 @@ export class RulesSettingsClientFactory {
this.isInitialized = true;
this.logger = options.logger;
this.savedObjectsService = options.savedObjectsService;
this.securityPluginStart = options.securityPluginStart;
this.securityService = options.securityService;
this.isServerless = options.isServerless;
}
private createRulesSettingsClient(request: KibanaRequest, withAuth: boolean) {
const { securityPluginStart } = this;
const { securityService } = this;
const savedObjectsClient = this.savedObjectsService.getScopedClient(request, {
includedHiddenTypes: [RULES_SETTINGS_SAVED_OBJECT_TYPE],
...(withAuth ? {} : { excludedExtensions: [SECURITY_EXTENSION_ID] }),
@ -51,11 +51,8 @@ export class RulesSettingsClientFactory {
logger: this.logger,
savedObjectsClient,
async getUserName() {
if (!securityPluginStart || !request) {
return null;
}
const user = securityPluginStart.authc.getCurrentUser(request);
return user ? user.username : null;
const user = securityService.authc.getCurrentUser(request);
return user?.username ?? null;
},
isServerless: this.isServerless,
});