Skip to content

Commit

Permalink
Further optimize check privileges response validation (elastic#90631) (
Browse files Browse the repository at this point in the history
…elastic#91530)

Co-authored-by: Larry Gregory <larry.gregory@elastic.co>
  • Loading branch information
kibanamachine and legrego authored Feb 16, 2021
1 parent 2a6442c commit d41df11
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 d41df11

Please sign in to comment.