Skip to content

Commit

Permalink
Further optimize check privileges response validation (#90631)
Browse files Browse the repository at this point in the history
  • Loading branch information
legrego authored Feb 16, 2021
1 parent f2e4cce commit d5aea93
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 25 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ describe('#atSpace', () => {
},
});
expect(result).toMatchInlineSnapshot(
`[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]`
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]`
);
});

Expand All @@ -338,7 +338,7 @@ describe('#atSpace', () => {
},
});
expect(result).toMatchInlineSnapshot(
`[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]]`
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]`
);
});
});
Expand Down Expand Up @@ -1092,7 +1092,7 @@ describe('#atSpaces', () => {
},
});
expect(result).toMatchInlineSnapshot(
`[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]]`
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]`
);
});

Expand Down Expand Up @@ -2266,7 +2266,7 @@ describe('#globally', () => {
},
});
expect(result).toMatchInlineSnapshot(
`[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]]`
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]`
);
});

Expand Down Expand Up @@ -2384,7 +2384,7 @@ describe('#globally', () => {
},
});
expect(result).toMatchInlineSnapshot(
`[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]`
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]`
);
});

Expand All @@ -2405,7 +2405,7 @@ describe('#globally', () => {
},
});
expect(result).toMatchInlineSnapshot(
`[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]]`
`[Error: Invalid response received from Elasticsearch has_privilege endpoint. Error: [application.kibana-our_application]: Payload did not match expected actions]`
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
import { schema } from '@kbn/config-schema';
import { HasPrivilegesResponse } from './types';

/**
* Validates an Elasticsearch "Has privileges" response against the expected application, actions, and resources.
*
* Note: the `actions` and `resources` parameters must be unique string arrays; any duplicates will cause validation to fail.
*/
export function validateEsPrivilegeResponse(
response: HasPrivilegesResponse,
application: string,
Expand All @@ -24,35 +29,43 @@ export function validateEsPrivilegeResponse(
return response;
}

function buildActionsValidationSchema(actions: string[]) {
return schema.object({
...actions.reduce<Record<string, any>>((acc, action) => {
return {
...acc,
[action]: schema.boolean(),
};
}, {}),
});
}

function buildValidationSchema(application: string, actions: string[], resources: string[]) {
const actionValidationSchema = buildActionsValidationSchema(actions);
const actionValidationSchema = schema.boolean();
const actionsValidationSchema = schema.object(
{},
{
unknowns: 'allow',
validate: (value) => {
const actualActions = Object.keys(value).sort();
if (
actions.length !== actualActions.length ||
![...actions].sort().every((x, i) => x === actualActions[i])
) {
throw new Error('Payload did not match expected actions');
}

Object.values(value).forEach((actionResult) => {
actionValidationSchema.validate(actionResult);
});
},
}
);

const resourceValidationSchema = schema.object(
const resourcesValidationSchema = 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])
![...resources].sort().every((x, i) => x === actualResources[i])
) {
throw new Error('Payload did not match expected resources');
}

Object.values(value).forEach((actionResult) => {
actionValidationSchema.validate(actionResult);
actionsValidationSchema.validate(actionResult);
});
},
}
Expand All @@ -63,7 +76,7 @@ function buildValidationSchema(application: string, actions: string[], resources
has_all_requested: schema.boolean(),
cluster: schema.object({}, { unknowns: 'allow' }),
application: schema.object({
[application]: resourceValidationSchema,
[application]: resourcesValidationSchema,
}),
index: schema.object({}, { unknowns: 'allow' }),
});
Expand Down

0 comments on commit d5aea93

Please sign in to comment.