Skip to content

Commit

Permalink
Merge branch 'master' into handle-delete
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Oct 11, 2021
2 parents d23f78e + e8d16cd commit e8f8b10
Show file tree
Hide file tree
Showing 122 changed files with 2,294 additions and 784 deletions.
2 changes: 1 addition & 1 deletion docs/settings/security-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ There is a very limited set of cases when you'd want to change these settings. F
| Determines if HTTP authentication schemes used by the enabled authentication providers should be automatically supported during HTTP authentication. By default, this setting is set to `true`.

| `xpack.security.authc.http.schemes[]`
| List of HTTP authentication schemes that {kib} HTTP authentication should support. By default, this setting is set to `['apikey']` to support HTTP authentication with <<api-keys, `ApiKey`>> scheme.
| List of HTTP authentication schemes that {kib} HTTP authentication should support. By default, this setting is set to `['apikey', 'bearer']` to support HTTP authentication with the <<api-keys, `ApiKey`>> and <<http-authentication, `Bearer`>> schemes.

|===

Expand Down
6 changes: 3 additions & 3 deletions docs/user/security/authentication/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -437,14 +437,14 @@ This type of authentication is usually useful for machine-to-machine interaction

By default {kib} supports <<api-keys, `ApiKey`>> authentication scheme _and_ any scheme supported by the currently enabled authentication provider. For example, `Basic` authentication scheme is automatically supported when basic authentication provider is enabled, or `Bearer` scheme when any of the token based authentication providers is enabled (Token, SAML, OpenID Connect, PKI or Kerberos). But it's also possible to add support for any other authentication scheme in the `kibana.yml` configuration file, as follows:

NOTE: Don't forget to explicitly specify default `apikey` scheme when you just want to add a new one to the list.
NOTE: Don't forget to explicitly specify the default `apikey` and `bearer` schemes when you just want to add a new one to the list.

[source,yaml]
--------------------------------------------------------------------------------
xpack.security.authc.http.schemes: [apikey, basic, something-custom]
xpack.security.authc.http.schemes: [apikey, bearer, basic, something-custom]
--------------------------------------------------------------------------------

With this configuration, you can send requests to {kib} with the `Authorization` header using `ApiKey`, `Basic` or `Something-Custom` HTTP schemes (case insensitive). Under the hood, {kib} relays this header to {es}, then {es} authenticates the request using the credentials in the header.
With this configuration, you can send requests to {kib} with the `Authorization` header using `ApiKey`, `Bearer`, `Basic` or `Something-Custom` HTTP schemes (case insensitive). Under the hood, {kib} relays this header to {es}, then {es} authenticates the request using the credentials in the header.

[float]
[[embedded-content-authentication]]
Expand Down
15 changes: 8 additions & 7 deletions vars/tasks.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,14 @@ def functionalXpack(Map params = [:]) {
}
}

whenChanged([
'x-pack/plugins/apm/',
]) {
if (githubPr.isPr()) {
task(kibanaPipeline.functionalTestProcess('xpack-APMCypress', './test/scripts/jenkins_apm_cypress.sh'))
}
}
//temporarily disable apm e2e test since it's breaking.
// whenChanged([
// 'x-pack/plugins/apm/',
// ]) {
// if (githubPr.isPr()) {
// task(kibanaPipeline.functionalTestProcess('xpack-APMCypress', './test/scripts/jenkins_apm_cypress.sh'))
// }
// }

whenChanged([
'x-pack/plugins/uptime/',
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/alerting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ The following table describes the properties of the `options` object.
|useSavedObjectReferences.extractReferences|(Optional) When developing a rule type, you can choose to implement hooks for extracting saved object references from rule parameters. This hook will be invoked when a rule is created or updated. Implementing this hook is optional, but if an extract hook is implemented, an inject hook must also be implemented.|Function
|useSavedObjectReferences.injectReferences|(Optional) When developing a rule type, you can choose to implement hooks for injecting saved object references into rule parameters. This hook will be invoked when a rule is retrieved (get or find). Implementing this hook is optional, but if an inject hook is implemented, an extract hook must also be implemented.|Function
|isExportable|Whether the rule type is exportable from the Saved Objects Management UI.|boolean|
|defaultScheduleInterval|The default interval that will show up in the UI when creating a rule of this rule type.|boolean|
|minimumScheduleInterval|The minimum interval that will be allowed for all rules of this rule type.|boolean|

### Executor

Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/alerting/common/alert_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export interface AlertType<
producer: string;
minimumLicenseRequired: LicenseType;
isExportable: boolean;
defaultScheduleInterval?: string;
minimumScheduleInterval?: string;
}

export interface ActionGroup<ActionGroupIds extends string> {
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/alerting/server/routes/rule_types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ describe('ruleTypesRoute', () => {
},
producer: 'test',
enabledInLicense: true,
minimumScheduleInterval: '1m',
defaultScheduleInterval: '10m',
} as RegistryAlertTypeWithAuth,
];
const expectedResult: Array<AsApiContract<RegistryAlertTypeWithAuth>> = [
Expand All @@ -70,7 +72,9 @@ describe('ruleTypesRoute', () => {
},
],
default_action_group_id: 'default',
default_schedule_interval: '10m',
minimum_license_required: 'basic',
minimum_schedule_interval: '1m',
is_exportable: true,
recovery_action_group: RecoveredActionGroup,
authorized_consumers: {},
Expand Down Expand Up @@ -102,10 +106,12 @@ describe('ruleTypesRoute', () => {
},
"authorized_consumers": Object {},
"default_action_group_id": "default",
"default_schedule_interval": "10m",
"enabled_in_license": true,
"id": "1",
"is_exportable": true,
"minimum_license_required": "basic",
"minimum_schedule_interval": "1m",
"name": "name",
"producer": "test",
"recovery_action_group": Object {
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/alerting/server/routes/rule_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const rewriteBodyRes: RewriteResponseCase<RegistryAlertTypeWithAuth[]> = (result
isExportable,
actionVariables,
authorizedConsumers,
minimumScheduleInterval,
defaultScheduleInterval,
...rest
}) => ({
...rest,
Expand All @@ -33,6 +35,8 @@ const rewriteBodyRes: RewriteResponseCase<RegistryAlertTypeWithAuth[]> = (result
is_exportable: isExportable,
action_variables: actionVariables,
authorized_consumers: authorizedConsumers,
minimum_schedule_interval: minimumScheduleInterval,
default_schedule_interval: defaultScheduleInterval,
})
);
};
Expand Down
57 changes: 56 additions & 1 deletion x-pack/plugins/alerting/server/rule_type_registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ describe('register()', () => {

test('throws if AlertType ruleTaskTimeout is not a valid duration', () => {
const alertType: AlertType<never, never, never, never, never, 'default'> = {
id: 123 as unknown as string,
id: '123',
name: 'Test',
actionGroups: [
{
Expand All @@ -138,6 +138,59 @@ describe('register()', () => {
);
});

test('throws if defaultScheduleInterval isnt valid', () => {
const alertType: AlertType<never, never, never, never, never, 'default'> = {
id: '123',
name: 'Test',
actionGroups: [
{
id: 'default',
name: 'Default',
},
],

defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
defaultScheduleInterval: 'foobar',
};
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);

expect(() => registry.register(alertType)).toThrowError(
new Error(
`Rule type \"123\" has invalid default interval: string is not a valid duration: foobar.`
)
);
});

test('throws if minimumScheduleInterval isnt valid', () => {
const alertType: AlertType<never, never, never, never, never, 'default'> = {
id: '123',
name: 'Test',
actionGroups: [
{
id: 'default',
name: 'Default',
},
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
minimumScheduleInterval: 'foobar',
};
const registry = new RuleTypeRegistry(ruleTypeRegistryParams);

expect(() => registry.register(alertType)).toThrowError(
new Error(
`Rule type \"123\" has invalid minimum interval: string is not a valid duration: foobar.`
)
);
});

test('throws if RuleType action groups contains reserved group id', () => {
const alertType: AlertType<never, never, never, never, never, 'default' | 'NotReserved'> = {
id: 'test',
Expand Down Expand Up @@ -465,10 +518,12 @@ describe('list()', () => {
"state": Array [],
},
"defaultActionGroupId": "testActionGroup",
"defaultScheduleInterval": undefined,
"enabledInLicense": false,
"id": "test",
"isExportable": true,
"minimumLicenseRequired": "basic",
"minimumScheduleInterval": undefined,
"name": "Test",
"producer": "alerts",
"recoveryActionGroup": Object {
Expand Down
44 changes: 44 additions & 0 deletions x-pack/plugins/alerting/server/rule_type_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export interface RegistryRuleType
| 'producer'
| 'minimumLicenseRequired'
| 'isExportable'
| 'minimumScheduleInterval'
| 'defaultScheduleInterval'
> {
id: string;
enabledInLicense: boolean;
Expand Down Expand Up @@ -188,6 +190,44 @@ export class RuleTypeRegistry {
}
alertType.actionVariables = normalizedActionVariables(alertType.actionVariables);

// validate defaultScheduleInterval here
if (alertType.defaultScheduleInterval) {
const invalidDefaultTimeout = validateDurationSchema(alertType.defaultScheduleInterval);
if (invalidDefaultTimeout) {
throw new Error(
i18n.translate(
'xpack.alerting.ruleTypeRegistry.register.invalidDefaultTimeoutAlertTypeError',
{
defaultMessage: 'Rule type "{id}" has invalid default interval: {errorMessage}.',
values: {
id: alertType.id,
errorMessage: invalidDefaultTimeout,
},
}
)
);
}
}

// validate minimumScheduleInterval here
if (alertType.minimumScheduleInterval) {
const invalidMinimumTimeout = validateDurationSchema(alertType.minimumScheduleInterval);
if (invalidMinimumTimeout) {
throw new Error(
i18n.translate(
'xpack.alerting.ruleTypeRegistry.register.invalidMinimumTimeoutAlertTypeError',
{
defaultMessage: 'Rule type "{id}" has invalid minimum interval: {errorMessage}.',
values: {
id: alertType.id,
errorMessage: invalidMinimumTimeout,
},
}
)
);
}
}

const normalizedAlertType = augmentActionGroupsWithReserved<
Params,
ExtractedParams,
Expand Down Expand Up @@ -287,6 +327,8 @@ export class RuleTypeRegistry {
producer,
minimumLicenseRequired,
isExportable,
minimumScheduleInterval,
defaultScheduleInterval,
},
]: [string, UntypedNormalizedAlertType]) => ({
id,
Expand All @@ -298,6 +340,8 @@ export class RuleTypeRegistry {
producer,
minimumLicenseRequired,
isExportable,
minimumScheduleInterval,
defaultScheduleInterval,
enabledInLicense: !!this.licenseState.getLicenseCheckForAlertType(
id,
name,
Expand Down
22 changes: 22 additions & 0 deletions x-pack/plugins/alerting/server/rules_client/rules_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,17 @@ export class RulesClient {

await this.validateActions(ruleType, data.actions);

// Validate intervals, if configured
if (ruleType.minimumScheduleInterval) {
const intervalInMs = parseDuration(data.schedule.interval);
const minimumScheduleIntervalInMs = parseDuration(ruleType.minimumScheduleInterval);
if (intervalInMs < minimumScheduleIntervalInMs) {
throw Boom.badRequest(
`Error updating rule: the interval is less than the minimum interval of ${ruleType.minimumScheduleInterval}`
);
}
}

// Extract saved object references for this rule
const {
references,
Expand Down Expand Up @@ -847,6 +858,17 @@ export class RulesClient {
);
await this.validateActions(ruleType, data.actions);

// Validate intervals, if configured
if (ruleType.minimumScheduleInterval) {
const intervalInMs = parseDuration(data.schedule.interval);
const minimumScheduleIntervalInMs = parseDuration(ruleType.minimumScheduleInterval);
if (intervalInMs < minimumScheduleIntervalInMs) {
throw Boom.badRequest(
`Error updating rule: the interval is less than the minimum interval of ${ruleType.minimumScheduleInterval}`
);
}
}

// Extract saved object references for this rule
const {
references,
Expand Down
26 changes: 26 additions & 0 deletions x-pack/plugins/alerting/server/rules_client/tests/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2268,4 +2268,30 @@ describe('create()', () => {
expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled();
expect(taskManager.schedule).not.toHaveBeenCalled();
});

test('throws error when updating with an interval less than the minimum configured one', async () => {
ruleTypeRegistry.get.mockImplementation(() => ({
id: '123',
name: 'Test',
actionGroups: [{ id: 'default', name: 'Default' }],
recoveryActionGroup: RecoveredActionGroup,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {},
producer: 'alerts',
minimumScheduleInterval: '5m',
useSavedObjectReferences: {
extractReferences: jest.fn(),
injectReferences: jest.fn(),
},
}));

const data = getMockData({ schedule: { interval: '1m' } });
await expect(rulesClient.create({ data })).rejects.toThrowErrorMatchingInlineSnapshot(
`"Error updating rule: the interval is less than the minimum interval of 5m"`
);
expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled();
expect(taskManager.schedule).not.toHaveBeenCalled();
});
});
46 changes: 46 additions & 0 deletions x-pack/plugins/alerting/server/rules_client/tests/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ describe('update()', () => {
recoveryActionGroup: RecoveredActionGroup,
async executor() {},
producer: 'alerts',
minimumScheduleInterval: '5s',
});
});

Expand Down Expand Up @@ -1966,4 +1967,49 @@ describe('update()', () => {
);
});
});

test('throws error when updating with an interval less than the minimum configured one', async () => {
await expect(
rulesClient.update({
id: '1',
data: {
schedule: { interval: '1s' },
name: 'abc',
tags: ['foo'],
params: {
bar: true,
},
throttle: null,
notifyWhen: 'onActiveAlert',
actions: [
{
group: 'default',
id: '1',
params: {
foo: true,
},
},
{
group: 'default',
id: '1',
params: {
foo: true,
},
},
{
group: 'default',
id: '2',
params: {
foo: true,
},
},
],
},
})
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Error updating rule: the interval is less than the minimum interval of 5s"`
);
expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled();
expect(taskManager.schedule).not.toHaveBeenCalled();
});
});
Loading

0 comments on commit e8f8b10

Please sign in to comment.