[9.0] [Core] Added reason for opting out of authz (#213878) (#214723)

# Backport

This will backport the following commits from `main` to `9.0`:
- [[Core] Added reason for opting out of authz
(#213878)](https://github.com/elastic/kibana/pull/213878)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Elena
Shostak","email":"165678770+elena-shostak@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-03-17T11:42:05Z","message":"[Core]
Added reason for opting out of authz (#213878)\n\n## Summary\n\nAdded
reason for opting out of authz for routes.\n\n\n### Checklist\n\n- [x]
[Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] The PR
description includes the appropriate Release Notes section,\nand the
correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"4008c1f24e68bb3837f12c60e3d472926aa80ac4","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Feature:Security/Authorization","backport:prev-minor","backport:version","Authz:
API migration","v9.1.0","v8.19.0"],"title":"[Core] Added reason for
opting out of
authz","number":213878,"url":"https://github.com/elastic/kibana/pull/213878","mergeCommit":{"message":"[Core]
Added reason for opting out of authz (#213878)\n\n## Summary\n\nAdded
reason for opting out of authz for routes.\n\n\n### Checklist\n\n- [x]
[Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] The PR
description includes the appropriate Release Notes section,\nand the
correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"4008c1f24e68bb3837f12c60e3d472926aa80ac4"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/213878","number":213878,"mergeCommit":{"message":"[Core]
Added reason for opting out of authz (#213878)\n\n## Summary\n\nAdded
reason for opting out of authz for routes.\n\n\n### Checklist\n\n- [x]
[Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] The PR
description includes the appropriate Release Notes section,\nand the
correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)","sha":"4008c1f24e68bb3837f12c60e3d472926aa80ac4"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Elena Shostak <165678770+elena-shostak@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2025-03-17 14:39:14 +01:00 committed by GitHub
parent 8e87c2f673
commit 0ce508ea46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 351 additions and 32 deletions

View file

@ -136,8 +136,15 @@ describe('CoreApp', () => {
{
path: '/status',
validate: false,
options: {
authRequired: false,
security: {
authz: {
enabled: false,
reason: expect.any(String),
},
authc: {
enabled: false,
reason: expect.any(String),
},
},
},
expect.any(Function)
@ -152,8 +159,14 @@ describe('CoreApp', () => {
{
path: '/status',
validate: false,
options: {
authRequired: true,
security: {
authz: {
enabled: false,
reason: expect.any(String),
},
authc: {
enabled: true,
},
},
},
expect.any(Function)
@ -200,6 +213,12 @@ describe('CoreApp', () => {
{
path: '/{path*}',
validate: expect.any(Object),
security: {
authz: {
enabled: false,
reason: expect.any(String),
},
},
},
expect.any(Function)
);
@ -331,8 +350,15 @@ describe('CoreApp', () => {
{
path: '/app/{id}/{any*}',
validate: false,
options: {
authRequired: true,
security: {
authz: {
enabled: false,
reason:
'The route is opted out of the authorization since it is a wrapper around core app view',
},
authc: {
enabled: true,
},
},
},
expect.any(Function)

View file

@ -174,8 +174,15 @@ export class CoreAppsService {
{
path: '/app/{id}/{any*}',
validate: false,
options: {
authRequired: true,
security: {
authz: {
enabled: false,
reason:
'The route is opted out of the authorization since it is a wrapper around core app view',
},
authc: {
enabled: true,
},
},
},
async (context, request, response) => {
@ -188,8 +195,19 @@ export class CoreAppsService {
{
path: '/status',
validate: false,
options: {
authRequired: !anonymousStatusPage,
security: {
authz: {
enabled: false,
reason:
'The route is opted out of the authorization since it is a wrapper around core app view',
},
authc: anonymousStatusPage
? {
enabled: false,
reason:
'The route is opted out of the authentication since it since it is a wrapper around core app anonymous view',
}
: { enabled: true },
},
},
async (context, request, response) => {
@ -338,6 +356,12 @@ export class CoreAppsService {
}),
query: schema.maybe(schema.recordOf(schema.string(), schema.any())),
},
security: {
authz: {
enabled: false,
reason: 'The route is opted out of the authorization since it is a catch-all route',
},
},
},
async (context, req, res) => {
const { query, params } = req;
@ -366,8 +390,18 @@ export class CoreAppsService {
}
);
router.get({ path: '/core', validate: false }, async (context, req, res) =>
res.ok({ body: { version: '0.0.1' } })
router.get(
{
path: '/core',
validate: false,
security: {
authz: {
enabled: false,
reason: 'The route is opted out of the authorization since it returns static response',
},
},
},
async (context, req, res) => res.ok({ body: { version: '0.0.1' } })
);
registerBundleRoutes({

View file

@ -51,7 +51,15 @@ describe('CapabilitiesService', () => {
expect(router.post).toHaveBeenCalledWith(
expect.objectContaining({
path: '/api/core/capabilities',
options: { authRequired: 'optional' },
security: {
authz: {
enabled: false,
reason: expect.any(String),
},
authc: {
enabled: 'optional',
},
},
}),
expect.any(Function)
);

View file

@ -17,8 +17,14 @@ export function registerCapabilitiesRoutes(router: IRouter, resolver: Capabiliti
router.post(
{
path: '/api/core/capabilities',
options: {
authRequired: 'optional',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Capabilities Resolver',
},
authc: {
enabled: 'optional',
},
},
validate: {
query: schema.object({

View file

@ -22,6 +22,12 @@ export const registerMarkAsResolvedRoute = (
options: {
access: 'internal',
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Core Usage Client',
},
},
validate: {
body: schema.object({
domainId: schema.string(),

View file

@ -41,6 +41,12 @@ export const registerBulkCreateRoute = (
access,
deprecated: deprecationInfo,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
query: schema.object({
overwrite: schema.boolean({ defaultValue: false }),

View file

@ -41,6 +41,12 @@ export const registerBulkDeleteRoute = (
access,
deprecated: deprecationInfo,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
body: schema.arrayOf(
schema.object({

View file

@ -41,6 +41,12 @@ export const registerBulkGetRoute = (
access,
deprecated: deprecationInfo,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
body: schema.arrayOf(
schema.object({

View file

@ -43,6 +43,12 @@ export const registerBulkResolveRoute = (
description: `Retrieve multiple Kibana saved objects by ID, using any legacy URL aliases if they exist.
Under certain circumstances, when Kibana is upgraded, saved object migrations may necessitate regenerating some object IDs to enable new features. When an object's ID is regenerated, a legacy URL alias is created for that object, preserving its old ID. In such a scenario, that object can be retrieved with the bulk resolve API using either its new ID or its old ID.`,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
body: schema.arrayOf(
schema.object({

View file

@ -41,6 +41,12 @@ export const registerBulkUpdateRoute = (
access,
deprecated: deprecationInfo,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
body: schema.arrayOf(
schema.object({

View file

@ -41,6 +41,12 @@ export const registerCreateRoute = (
access,
deprecated: deprecationInfo,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -41,6 +41,12 @@ export const registerDeleteRoute = (
access,
deprecated: deprecationInfo,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -151,6 +151,12 @@ export const registerExportRoute = (
description:
'Retrieve sets of saved objects that you want to import into Kibana. You must include `type` or `objects` in the request body. \nExported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. \nNOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported.',
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
body: schema.object({
type: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])),

View file

@ -45,6 +45,12 @@ export const registerFindRoute = (
access,
deprecated: deprecationInfo,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
query: schema.object({
per_page: schema.number({ min: 0, defaultValue: 20 }),

View file

@ -41,6 +41,12 @@ export const registerGetRoute = (
access,
deprecated: deprecationInfo,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -48,6 +48,12 @@ export const registerImportRoute = (
accepts: 'multipart/form-data',
},
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
query: schema.object(
{

View file

@ -39,6 +39,12 @@ export const registerLegacyExportRoute = (
dashboard: schema.oneOf([schema.string(), schema.arrayOf(schema.string())]),
}),
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
options: {
access,
deprecated: legacyDeprecationInfo,

View file

@ -34,6 +34,12 @@ export const registerLegacyImportRoute = (
router.post(
{
path: '/api/kibana/dashboards/import',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
body: schema.object({
objects: schema.arrayOf(schema.recordOf(schema.string(), schema.any())),

View file

@ -39,6 +39,12 @@ export const registerResolveRoute = (
description: `Retrieve a single Kibana saved object by ID, using any legacy URL alias if it exists.
Under certain circumstances, when Kibana is upgraded, saved object migrations may necessitate regenerating some object IDs to enable new features. When an object's ID is regenerated, a legacy URL alias is created for that object, preserving its old ID. In such a scenario, that object can be retrieved with the resolve API using either its new ID or its old ID.`,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -49,6 +49,12 @@ export const registerResolveImportErrorsRoute = (
accepts: 'multipart/form-data',
},
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
query: schema.object(
{

View file

@ -42,6 +42,12 @@ export const registerUpdateRoute = (
access,
deprecated: deprecationInfo,
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Saved Objects Client',
},
},
validate: {
params: schema.object({
type: schema.string(),

View file

@ -53,14 +53,32 @@ export function registerDeleteRoute(router: InternalUiSettingsRouter) {
}
};
router.delete(
{ path: '/api/kibana/settings/{key}', validate },
{
path: '/api/kibana/settings/{key}',
validate,
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.client;
return await deleteFromRequest(uiSettingsClient, context, request, response);
}
);
router.delete(
{ path: '/api/kibana/global_settings/{key}', validate },
{
path: '/api/kibana/global_settings/{key}',
validate,
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.globalClient;
return await deleteFromRequest(uiSettingsClient, context, request, response);

View file

@ -53,14 +53,34 @@ export function registerInternalDeleteRoute(router: InternalUiSettingsRouter) {
}
};
router.delete(
{ path: '/internal/kibana/settings/{key}', validate, options: { access: 'internal' } },
{
path: '/internal/kibana/settings/{key}',
validate,
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.client;
return await deleteFromRequest(uiSettingsClient, context, request, response);
}
);
router.delete(
{ path: '/internal/kibana/global_settings/{key}', validate, options: { access: 'internal' } },
{
path: '/internal/kibana/global_settings/{key}',
validate,
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.globalClient;
return await deleteFromRequest(uiSettingsClient, context, request, response);

View file

@ -38,14 +38,34 @@ export function registerInternalGetRoute(router: InternalUiSettingsRouter) {
}
};
router.get(
{ path: '/internal/kibana/settings', validate: false, options: { access: 'internal' } },
{
path: '/internal/kibana/settings',
validate: false,
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.client;
return await getFromRequest(uiSettingsClient, context, request, response);
}
);
router.get(
{ path: '/internal/kibana/global_settings', validate: false, options: { access: 'internal' } },
{
path: '/internal/kibana/global_settings',
validate: false,
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.globalClient;
return await getFromRequest(uiSettingsClient, context, request, response);

View file

@ -65,14 +65,34 @@ export function registerInternalSetRoute(router: InternalUiSettingsRouter) {
}
};
router.post(
{ path: '/internal/kibana/settings/{key}', validate, options: { access: 'internal' } },
{
path: '/internal/kibana/settings/{key}',
validate,
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.client;
return await setFromRequest(uiSettingsClient, context, request, response);
}
);
router.post(
{ path: '/internal/kibana/global_settings/{key}', validate, options: { access: 'internal' } },
{
path: '/internal/kibana/global_settings/{key}',
validate,
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.globalClient;
return await setFromRequest(uiSettingsClient, context, request, response);

View file

@ -55,7 +55,17 @@ export function registerInternalSetManyRoute(router: InternalUiSettingsRouter) {
};
router.post(
{ path: '/internal/kibana/settings', validate, options: { access: 'internal' } },
{
path: '/internal/kibana/settings',
validate,
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.client;
return await setManyFromRequest(uiSettingsClient, context, request, response);
@ -63,7 +73,17 @@ export function registerInternalSetManyRoute(router: InternalUiSettingsRouter) {
);
router.post(
{ path: '/internal/kibana/global_settings', validate, options: { access: 'internal' } },
{
path: '/internal/kibana/global_settings',
validate,
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.globalClient;
return await setManyFromRequest(uiSettingsClient, context, request, response);

View file

@ -55,6 +55,12 @@ export function registerInternalValidateRoute(router: InternalUiSettingsRouter)
router.post(
{
path: '/internal/kibana/settings/{key}/validate',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
validate: {
params: schema.object({
key: schema.string(),

View file

@ -65,14 +65,32 @@ export function registerSetRoute(router: InternalUiSettingsRouter) {
}
};
router.post(
{ path: '/api/kibana/settings/{key}', validate },
{
path: '/api/kibana/settings/{key}',
validate,
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.client;
return await setFromRequest(uiSettingsClient, context, request, response);
}
);
router.post(
{ path: '/api/kibana/global_settings/{key}', validate },
{
path: '/api/kibana/global_settings/{key}',
validate,
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.globalClient;
return await setFromRequest(uiSettingsClient, context, request, response);

View file

@ -53,13 +53,34 @@ export function registerSetManyRoute(router: InternalUiSettingsRouter) {
throw error;
}
};
router.post({ path: '/api/kibana/settings', validate }, async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.client;
return await setManyFromRequest(uiSettingsClient, context, request, response);
});
router.post(
{
path: '/api/kibana/settings',
validate,
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.client;
return await setManyFromRequest(uiSettingsClient, context, request, response);
}
);
router.post(
{ path: '/api/kibana/global_settings', validate },
{
path: '/api/kibana/global_settings',
validate,
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the UI Settings Client',
},
},
},
async (context, request, response) => {
const uiSettingsClient = (await context.core).uiSettings.globalClient;
return await setManyFromRequest(uiSettingsClient, context, request, response);