[Fleet] Validate policy id when creating an enrollment token (#123298)

This commit is contained in:
Nicolas Chaulet 2022-01-19 11:10:36 -05:00 committed by GitHub
parent d84a5df7bd
commit d40c0abe5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 18 deletions

View file

@ -5,13 +5,23 @@
* 2.0.
*/
import React, { useState } from 'react';
import React, { useState, useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiConfirmModal, EuiForm, EuiFormRow, EuiFieldText, EuiSelect } from '@elastic/eui';
import type { AgentPolicy, EnrollmentAPIKey } from '../types';
import { useInput, useStartServices, sendCreateEnrollmentAPIKey } from '../hooks';
function validatePolicyId(value: string) {
if (value === '') {
return [
i18n.translate('xpack.fleet.newEnrollmentKeyForm.policyIdRequireErrorMessage', {
defaultMessage: 'Policy is required',
}),
];
}
}
function useCreateApiKeyForm(
policyIdDefaultValue: string | undefined,
onSuccess: (key: EnrollmentAPIKey) => void,
@ -19,10 +29,13 @@ function useCreateApiKeyForm(
) {
const [isLoading, setIsLoading] = useState(false);
const apiKeyNameInput = useInput('');
const policyIdInput = useInput(policyIdDefaultValue);
const policyIdInput = useInput(policyIdDefaultValue, validatePolicyId);
const onSubmit = async (event: React.FormEvent) => {
event.preventDefault();
if (!policyIdInput.validate() || !apiKeyNameInput.validate()) {
return;
}
setIsLoading(true);
try {
const res = await sendCreateEnrollmentAPIKey({
@ -65,7 +78,11 @@ export const NewEnrollmentTokenModal: React.FunctionComponent<Props> = ({
const { notifications } = useStartServices();
const policyIdDefaultValue = agentPolicies.find((agentPolicy) => agentPolicy.is_default)?.id;
const form = useCreateApiKeyForm(
policyIdDefaultValue,
policyIdDefaultValue
? policyIdDefaultValue
: agentPolicies.length > 0
? agentPolicies[0].id
: undefined,
(key: EnrollmentAPIKey) => {
onClose(key);
notifications.toasts.addSuccess(
@ -81,6 +98,15 @@ export const NewEnrollmentTokenModal: React.FunctionComponent<Props> = ({
}
);
const selectPolicyOptions = useMemo(() => {
return agentPolicies
.filter((agentPolicy) => !agentPolicy.is_managed)
.map((agentPolicy) => ({
value: agentPolicy.id,
text: agentPolicy.name,
}));
}, [agentPolicies]);
const body = (
<EuiForm>
<form onSubmit={form.onSubmit}>
@ -106,18 +132,9 @@ export const NewEnrollmentTokenModal: React.FunctionComponent<Props> = ({
label={i18n.translate('xpack.fleet.newEnrollmentKey.policyLabel', {
defaultMessage: 'Policy',
})}
{...form.policyIdInput.formRowProps}
>
<EuiSelect
required={true}
defaultValue={policyIdDefaultValue}
{...form.policyIdInput.props}
options={agentPolicies
.filter((agentPolicy) => !agentPolicy.is_managed)
.map((agentPolicy) => ({
value: agentPolicy.id,
text: agentPolicy.name,
}))}
/>
<EuiSelect required={true} {...form.policyIdInput.props} options={selectPolicyOptions} />
</EuiFormRow>
</form>
</EuiForm>

View file

@ -32,6 +32,7 @@ export class PackageNotFoundError extends IngestManagerError {}
export class PackageKeyInvalidError extends IngestManagerError {}
export class PackageOutdatedError extends IngestManagerError {}
export class AgentPolicyError extends IngestManagerError {}
export class AgentPolicyNotFoundError extends IngestManagerError {}
export class AgentNotFoundError extends IngestManagerError {}
export class AgentPolicyNameExistsError extends AgentPolicyError {}
export class PackageUnsupportedMediaTypeError extends IngestManagerError {}

View file

@ -21,7 +21,8 @@ import type {
PostEnrollmentAPIKeyResponse,
} from '../../../common';
import * as APIKeyService from '../../services/api_keys';
import { defaultIngestErrorHandler } from '../../errors';
import { agentPolicyService } from '../../services/agent_policy';
import { defaultIngestErrorHandler, AgentPolicyNotFoundError } from '../../errors';
export const getEnrollmentApiKeysHandler: RequestHandler<
undefined,
@ -57,6 +58,15 @@ export const postEnrollmentApiKeyHandler: RequestHandler<
const soClient = context.core.savedObjects.client;
const esClient = context.core.elasticsearch.client.asInternalUser;
try {
// validate policy id
await agentPolicyService.get(soClient, request.body.policy_id).catch((err) => {
if (soClient.errors.isNotFoundError(err)) {
throw new AgentPolicyNotFoundError(`Agent policy "${request.body.policy_id}" not found`);
}
throw err;
});
const apiKey = await APIKeyService.generateEnrollmentAPIKey(soClient, esClient, {
name: request.body.name,
expiration: request.body.expiration,

View file

@ -92,14 +92,16 @@ export default function (providerContext: FtrProviderContext) {
.expect(400);
});
it('should return a 400 if the fleet admin user is modifed outside of Fleet', async () => {
await supertest
it('should return a 400 if the policy_id is not a valid policy', async () => {
const { body: apiResponse } = await supertest
.post(`/api/fleet/enrollment_api_keys`)
.set('kbn-xsrf', 'xxx')
.send({
raoul: 'raoul',
policy_id: 'idonotexists',
})
.expect(400);
expect(apiResponse.message).to.be('Agent policy "idonotexists" not found');
});
it('should allow to create an enrollment api key with only an agent policy', async () => {