Optimize performance of ES privilege response validation (#90074)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
219a86dbe5
commit
00a20268b1
|
@ -1,21 +1,21 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when an action is malformed in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [child \\"foo-application\\" fails because [child \\"foo-resource\\" fails because [child \\"action3\\" fails because [\\"action3\\" must be a boolean]]]]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when an action is malformed in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: [action3]: expected value of type [boolean] but got [string]"`;
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when an action is missing in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [child \\"foo-application\\" fails because [child \\"foo-resource\\" fails because [child \\"action2\\" fails because [\\"action2\\" is required]]]]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when an action is missing in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: [action2]: expected value of type [boolean] but got [undefined]"`;
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when an expected resource property is missing from the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [child \\"foo-application\\" fails because [child \\"bar-resource\\" fails because [\\"bar-resource\\" is required]]]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when an expected resource property is missing from the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: Payload did not match expected resources"`;
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when an extra action is present in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [child \\"foo-application\\" fails because [child \\"foo-resource\\" fails because [\\"action4\\" is not allowed]]]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when an extra action is present in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: [action4]: definition for this key is missing"`;
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when an extra application is present in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [\\"otherApplication\\" is not allowed]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when an extra application is present in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.otherApplication]: definition for this key is missing"`;
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when an unexpected resource property is present in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [child \\"foo-application\\" fails because [child \\"bar-resource\\" fails because [\\"bar-resource\\" is required]]]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when an unexpected resource property is present in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: Payload did not match expected resources"`;
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when the "application" property is missing from the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [\\"application\\" is required]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when the "application" property is missing from the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: Payload did not match expected resources"`;
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when the requested application is missing from the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [child \\"foo-application\\" fails because [\\"foo-application\\" is required]]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when the requested application is missing from the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: Payload did not match expected resources"`;
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when the resource propertry is malformed in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [child \\"foo-application\\" fails because [child \\"foo-resource\\" fails because [\\"foo-resource\\" must be an object]]]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when the resource propertry is malformed in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: could not parse object value from json input"`;
|
||||
|
||||
exports[`validateEsPrivilegeResponse fails validation when there are no resource properties in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child \\"application\\" fails because [child \\"foo-application\\" fails because [child \\"foo-resource\\" fails because [\\"foo-resource\\" is required]]]"`;
|
||||
exports[`validateEsPrivilegeResponse fails validation when there are no resource properties in the response 1`] = `"Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.foo-application]: Payload did not match expected resources"`;
|
||||
|
|
|
@ -316,7 +316,7 @@ describe('#atSpace', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_1" fails because ["saved_object:bar-type/get" is not allowed]]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [saved_object:bar-type/get]: definition for this key is missing]`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -338,7 +338,7 @@ describe('#atSpace', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_1" fails because [child "saved_object:foo-type/get" fails because ["saved_object:foo-type/get" is required]]]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [saved_object:foo-type/get]: expected value of type [boolean] but got [undefined]]`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1092,7 +1092,7 @@ describe('#atSpaces', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_1" fails because [child "mock-action:version" fails because ["mock-action:version" is required]]]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [mock-action:version]: expected value of type [boolean] but got [undefined]]`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1379,7 +1379,7 @@ describe('#atSpaces', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_2" fails because ["space:space_2" is required]]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected resources]`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1407,7 +1407,7 @@ describe('#atSpaces', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_2" fails because ["space:space_2" is required]]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected resources]`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1440,7 +1440,7 @@ describe('#atSpaces', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because ["space:space_3" is not allowed]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected resources]`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1463,7 +1463,7 @@ describe('#atSpaces', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "space:space_2" fails because ["space:space_2" is required]]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected resources]`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -2266,7 +2266,7 @@ describe('#globally', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "*" fails because [child "mock-action:version" fails because ["mock-action:version" is required]]]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [mock-action:version]: expected value of type [boolean] but got [undefined]]`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2384,7 +2384,7 @@ describe('#globally', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "*" fails because ["saved_object:bar-type/get" is not allowed]]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [saved_object:bar-type/get]: definition for this key is missing]`
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -2405,7 +2405,7 @@ describe('#globally', () => {
|
|||
},
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. ValidationError: child "application" fails because [child "kibana-our_application" fails because [child "*" fails because [child "saved_object:foo-type/get" fails because ["saved_object:foo-type/get" is required]]]]]`
|
||||
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: [saved_object:foo-type/get]: expected value of type [boolean] but got [undefined]]`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import Joi from 'joi';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { HasPrivilegesResponse } from './types';
|
||||
|
||||
export function validateEsPrivilegeResponse(
|
||||
|
@ -14,48 +14,57 @@ export function validateEsPrivilegeResponse(
|
|||
actions: string[],
|
||||
resources: string[]
|
||||
) {
|
||||
const schema = buildValidationSchema(application, actions, resources);
|
||||
const { error, value } = schema.validate(response);
|
||||
|
||||
if (error) {
|
||||
throw new Error(
|
||||
`Invalid response received from Elasticsearch has_privilege endpoint. ${error}`
|
||||
);
|
||||
const validationSchema = buildValidationSchema(application, actions, resources);
|
||||
try {
|
||||
validationSchema.validate(response);
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid response received from Elasticsearch has_privilege endpoint. ${e}`);
|
||||
}
|
||||
|
||||
return value;
|
||||
return response;
|
||||
}
|
||||
|
||||
function buildActionsValidationSchema(actions: string[]) {
|
||||
return Joi.object({
|
||||
return schema.object({
|
||||
...actions.reduce<Record<string, any>>((acc, action) => {
|
||||
return {
|
||||
...acc,
|
||||
[action]: Joi.bool().required(),
|
||||
[action]: schema.boolean(),
|
||||
};
|
||||
}, {}),
|
||||
}).required();
|
||||
});
|
||||
}
|
||||
|
||||
function buildValidationSchema(application: string, actions: string[], resources: string[]) {
|
||||
const actionValidationSchema = buildActionsValidationSchema(actions);
|
||||
|
||||
const resourceValidationSchema = Joi.object({
|
||||
...resources.reduce((acc, resource) => {
|
||||
return {
|
||||
...acc,
|
||||
[resource]: actionValidationSchema,
|
||||
};
|
||||
}, {}),
|
||||
}).required();
|
||||
const resourceValidationSchema = schema.object(
|
||||
{},
|
||||
{
|
||||
unknowns: 'allow',
|
||||
validate: (value) => {
|
||||
const actualResources = Object.keys(value).sort();
|
||||
if (
|
||||
resources.length !== actualResources.length ||
|
||||
!resources.sort().every((x, i) => x === actualResources[i])
|
||||
) {
|
||||
throw new Error('Payload did not match expected resources');
|
||||
}
|
||||
|
||||
return Joi.object({
|
||||
username: Joi.string().required(),
|
||||
has_all_requested: Joi.bool(),
|
||||
cluster: Joi.object(),
|
||||
application: Joi.object({
|
||||
Object.values(value).forEach((actionResult) => {
|
||||
actionValidationSchema.validate(actionResult);
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return schema.object({
|
||||
username: schema.string(),
|
||||
has_all_requested: schema.boolean(),
|
||||
cluster: schema.object({}, { unknowns: 'allow' }),
|
||||
application: schema.object({
|
||||
[application]: resourceValidationSchema,
|
||||
}).required(),
|
||||
index: Joi.object(),
|
||||
}).required();
|
||||
}),
|
||||
index: schema.object({}, { unknowns: 'allow' }),
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue