Skip to content

Commit

Permalink
Create API keys with metadata (#100682) (#101074)
Browse files Browse the repository at this point in the history
Co-authored-by: Thom Heymann <190132+thomheymann@users.noreply.github.com>
  • Loading branch information
kibanamachine and thomheymann committed Jun 1, 2021
1 parent 491e90c commit 313a887
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 33 deletions.
Binary file modified docs/user/security/api-keys/images/create-api-key.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions x-pack/plugins/security/common/model/api_key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface ApiKey {
creation: number;
expiration: number;
invalidated: boolean;
metadata: Record<string, any>;
}

export interface ApiKeyToInvalidate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface CreateApiKeyRequest {
name: string;
expiration?: string;
role_descriptors?: ApiKeyRoleDescriptors;
metadata?: Record<string, any>;
}

export interface CreateApiKeyResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ export interface ApiKeyFormValues {
expiration: string;
customExpiration: boolean;
customPrivileges: boolean;
includeMetadata: boolean;
role_descriptors: string;
metadata: string;
}

export interface CreateApiKeyFlyoutProps {
Expand All @@ -59,30 +61,9 @@ const defaultDefaultValues: ApiKeyFormValues = {
expiration: '',
customExpiration: false,
customPrivileges: false,
role_descriptors: JSON.stringify(
{
'role-a': {
cluster: ['all'],
indices: [
{
names: ['index-a*'],
privileges: ['read'],
},
],
},
'role-b': {
cluster: ['all'],
indices: [
{
names: ['index-b*'],
privileges: ['all'],
},
],
},
},
null,
2
),
includeMetadata: false,
role_descriptors: '{}',
metadata: '{}',
};

export const CreateApiKeyFlyout: FunctionComponent<CreateApiKeyFlyoutProps> = ({
Expand Down Expand Up @@ -227,7 +208,6 @@ export const CreateApiKeyFlyout: FunctionComponent<CreateApiKeyFlyoutProps> = ({
<EuiSpacer />
<EuiFormFieldset>
<EuiSwitch
id="apiKeyCustom"
label={i18n.translate(
'xpack.security.accountManagement.createApiKey.customPrivilegesLabel',
{
Expand Down Expand Up @@ -270,7 +250,6 @@ export const CreateApiKeyFlyout: FunctionComponent<CreateApiKeyFlyoutProps> = ({
<EuiSpacer />
<EuiFormFieldset>
<EuiSwitch
name="customExpiration"
label={i18n.translate(
'xpack.security.accountManagement.createApiKey.customExpirationLabel',
{
Expand Down Expand Up @@ -312,6 +291,48 @@ export const CreateApiKeyFlyout: FunctionComponent<CreateApiKeyFlyoutProps> = ({
)}
</EuiFormFieldset>

<EuiSpacer />
<EuiFormFieldset>
<EuiSwitch
label={i18n.translate(
'xpack.security.accountManagement.createApiKey.includeMetadataLabel',
{
defaultMessage: 'Include metadata',
}
)}
checked={!!form.values.includeMetadata}
onChange={(e) => form.setValue('includeMetadata', e.target.checked)}
/>
{form.values.includeMetadata && (
<>
<EuiSpacer size="m" />
<EuiFormRow
helpText={
<DocLink
app="elasticsearch"
doc="security-api-create-api-key.html#security-api-create-api-key-request-body"
>
<FormattedMessage
id="xpack.security.accountManagement.createApiKey.metadataHelpText"
defaultMessage="Learn how to structure metadata."
/>
</DocLink>
}
error={form.errors.metadata}
isInvalid={form.touched.metadata && !!form.errors.metadata}
>
<CodeEditorField
value={form.values.metadata!}
onChange={(value) => form.setValue('metadata', value)}
languageId="xjson"
height={200}
/>
</EuiFormRow>
<EuiSpacer size="s" />
</>
)}
</EuiFormFieldset>

{/* Hidden submit button is required for enter key to trigger form submission */}
<input type="submit" hidden />
</EuiForm>
Expand Down Expand Up @@ -363,6 +384,28 @@ export function validate(values: ApiKeyFormValues) {
}
}

if (values.includeMetadata) {
if (!values.metadata) {
errors.metadata = i18n.translate(
'xpack.security.management.apiKeys.createApiKey.metadataRequired',
{
defaultMessage: 'Enter metadata or disable this option.',
}
);
} else {
try {
JSON.parse(values.metadata);
} catch (e) {
errors.metadata = i18n.translate(
'xpack.security.management.apiKeys.createApiKey.invalidJsonError',
{
defaultMessage: 'Enter valid JSON.',
}
);
}
}
}

return errors;
}

Expand All @@ -374,5 +417,6 @@ export function mapValues(values: ApiKeyFormValues): CreateApiKeyRequest {
values.customPrivileges && values.role_descriptors
? JSON.parse(values.role_descriptors)
: undefined,
metadata: values.includeMetadata && values.metadata ? JSON.parse(values.metadata) : undefined,
};
}
20 changes: 13 additions & 7 deletions x-pack/plugins/security/server/authentication/api_keys/api_keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,21 @@ export interface CreateAPIKeyParams {
name: string;
role_descriptors: Record<string, any>;
expiration?: string;
metadata?: Record<string, any>;
}

interface GrantAPIKeyParams {
api_key: CreateAPIKeyParams;
grant_type: 'password' | 'access_token';
username?: string;
password?: string;
access_token?: string;
}
type GrantAPIKeyParams =
| {
api_key: CreateAPIKeyParams;
grant_type: 'password';
username: string;
password: string;
}
| {
api_key: CreateAPIKeyParams;
grant_type: 'access_token';
access_token: string;
};

/**
* Represents the params for invalidating multiple API keys
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/security/server/routes/api_keys/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ describe('Create API Key route', () => {
role_descriptors: {
role_1: {},
},
metadata: {
foo: 'bar',
},
};

const request = httpServerMock.createKibanaRequest({
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/security/server/routes/api_keys/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export function defineCreateApiKeyRoutes({
defaultValue: {},
}
),
metadata: schema.maybe(schema.object({}, { unknowns: 'allow' })),
}),
},
},
Expand Down
17 changes: 17 additions & 0 deletions x-pack/test/api_integration/apis/security/api_keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ export default function ({ getService }: FtrProviderContext) {
expect(name).to.eql('test_api_key');
});
});

it('should allow an API Key to be created with metadata', async () => {
await supertest
.post('/internal/security/api_key')
.set('kbn-xsrf', 'xxx')
.send({
name: 'test_api_key_with_metadata',
metadata: {
foo: 'bar',
},
})
.expect(200)
.then((response: Record<string, any>) => {
const { name } = response.body;
expect(name).to.eql('test_api_key_with_metadata');
});
});
});
});
}

0 comments on commit 313a887

Please sign in to comment.