Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into app-service/mount
Browse files Browse the repository at this point in the history
  • Loading branch information
joshdover committed Aug 30, 2019
2 parents f6c5bb2 + 7a0a3f5 commit 65e64c3
Show file tree
Hide file tree
Showing 148 changed files with 5,826 additions and 3,346 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ module.exports = {
{
from: ['src/legacy/ui/**/*', 'ui/**/*'],
target: [
'test/plugin_functional/plugins/**/public/np_ready/**/*',
'test/plugin_functional/plugins/**/server/np_ready/**/*',
'src/legacy/core_plugins/**/public/np_ready/**/*',
'src/legacy/core_plugins/**/server/np_ready/**/*',
'x-pack/legacy/plugins/**/public/np_ready/**/*',
Expand Down
31 changes: 31 additions & 0 deletions docs/security/authentication/index.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

- <<basic-authentication>>
- <<token-authentication>>
- <<pki-authentication>>
- <<saml>>
- <<oidc>>

Expand Down Expand Up @@ -44,6 +45,36 @@ The token authentication provider can be used in conjunction with the basic auth
xpack.security.authc.providers: [token, basic]
--------------------------------------------------------------------------------

[[pki-authentication]]
==== Public Key Infrastructure (PKI) Authentication

[IMPORTANT]
============================================================================
PKI authentication will not work if {kib} is hosted behind a TLS termination reverse proxy. In this configuration, {kib} does not have direct access to the client certificates and cannot authenticate the user.
============================================================================

PKI authentication allows users to log into {kib} using X.509 client certificates that must be presented while connecting to {kib}. The certificates must first be accepted for authentication on the {kib} TLS layer, and then they are further validated by an {es} PKI realm. The PKI authentication provider relies on the {es} {ref}/security-api-delegate-pki-authentication.html[Delegate PKI authentication API] to exchange X.509 client certificates to access tokens. All subsequent requests to {es} APIs on behalf of users will be authenticated using these access tokens.

Prior to configuring {kib}, ensure that the PKI realm is enabled in {es} and configured to permit delegation. See {ref}/configuring-pki-realm.html[Configuring a PKI realm] for more information.

To enable the PKI authentication provider in {kib}, you must first <<configuring-tls,configure {kib} to encrypt communications between the browser and {kib} server>>. You must also enable TLS client authentication and include the certificate authority (CA) used to sign client certificates into a list of CAs trusted by {kib} in your `kibana.yml`:

[source,yaml]
--------------------------------------------------------------------------------
server.ssl.certificateAuthorities: /path/to/your/cacert.pem
server.ssl.clientAuthentication: required
xpack.security.authc.providers: [pki]
--------------------------------------------------------------------------------

PKI support in {kib} is designed to be the primary (or sole) authentication method for users of that {kib} instance. However, you can configure both PKI and Basic authentication for the same {kib} instance:

[source,yaml]
--------------------------------------------------------------------------------
xpack.security.authc.providers: [pki, basic]
--------------------------------------------------------------------------------

Note that with `server.ssl.clientAuthentication` set to `required`, users are asked to provide a valid client certificate, even if they want to authenticate with username and password. Depending on the security policies, it may or may not be desired. If not, `server.ssl.clientAuthentication` can be set to `optional`. In this case, {kib} still requests a client certificate, but the client won't be required to present one. The `optional` client authentication mode might also be needed in other cases, for example, when PKI authentication is used in conjunction with Reporting.

[[saml]]
==== SAML Single Sign-On

Expand Down
3,785 changes: 1,955 additions & 1,830 deletions packages/kbn-pm/dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/kbn-pm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@types/write-pkg": "^3.1.0",
"babel-loader": "^8.0.6",
"chalk": "^2.4.2",
"cmd-shim": "^2.0.2",
"cmd-shim": "^2.1.0",
"cpy": "^7.0.1",
"dedent": "^0.7.0",
"del": "^4.0.0",
Expand Down
6 changes: 3 additions & 3 deletions renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@
'release_note:skip',
'renovate',
'v8.0.0',
'v7.4.0',
'v7.5.0',
],
major: {
labels: [
'release_note:skip',
'renovate',
'v8.0.0',
'v7.4.0',
'v7.5.0',
'renovate:major',
],
},
Expand Down Expand Up @@ -210,7 +210,7 @@
'release_note:skip',
'renovate',
'v8.0.0',
'v7.4.0',
'v7.5.0',
':ml',
],
},
Expand Down
70 changes: 70 additions & 0 deletions src/core/utils/poller.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { Poller } from './poller';

const delay = (duration: number) => new Promise(r => setTimeout(r, duration));

describe('Poller', () => {
let handler: jest.Mock<any, any>;
let poller: Poller<string>;

beforeEach(() => {
handler = jest.fn().mockImplementation((iteration: number) => `polling-${iteration}`);
poller = new Poller<string>(100, 'polling', handler);
});

afterEach(() => {
poller.unsubscribe();
});

it('returns an observable of subject', async () => {
await delay(300);
expect(poller.subject$.getValue()).toBe('polling-2');
});

it('executes a function on an interval', async () => {
await delay(300);
expect(handler).toBeCalledTimes(3);
});

it('no longer polls after unsubscribing', async () => {
await delay(300);
poller.unsubscribe();
await delay(300);
expect(handler).toBeCalledTimes(3);
});

it('does not add next value if returns undefined', async () => {
const values: any[] = [];
const polling = new Poller<string>(100, 'polling', iteration => {
if (iteration % 2 === 0) {
return `polling-${iteration}`;
}
});

polling.subject$.subscribe(value => {
values.push(value);
});
await delay(300);
polling.unsubscribe();

expect(values).toEqual(['polling', 'polling-0', 'polling-2']);
});
});
55 changes: 55 additions & 0 deletions src/core/utils/poller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { BehaviorSubject, timer } from 'rxjs';

/**
* Create an Observable BehaviorSubject to invoke a function on an interval
* which returns the next value for the observable.
* @public
*/
export class Poller<T> {
/**
* The observable to observe for changes to the poller value.
*/
public readonly subject$ = new BehaviorSubject<T>(this.initialValue);
private poller$ = timer(0, this.frequency);
private subscription = this.poller$.subscribe(async iteration => {
const next = await this.handler(iteration);

if (next !== undefined) {
this.subject$.next(next);
}

return iteration;
});

constructor(
private frequency: number,
private initialValue: T,
private handler: (iteration: number) => Promise<T | undefined> | T | undefined
) {}

/**
* Permanently end the polling operation.
*/
unsubscribe() {
return this.subscription.unsubscribe();
}
}
2 changes: 1 addition & 1 deletion src/dev/renovate/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { RENOVATE_PACKAGE_GROUPS } from './package_groups';
import { PACKAGE_GLOBS } from './package_globs';
import { wordRegExp, maybeFlatMap, maybeMap, getTypePackageName } from './utils';

const DEFAULT_LABELS = ['release_note:skip', 'renovate', 'v8.0.0', 'v7.4.0'];
const DEFAULT_LABELS = ['release_note:skip', 'renovate', 'v8.0.0', 'v7.5.0'];

export const RENOVATE_CONFIG = {
extends: ['config:base'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe('context app', function () {
it('should use the `fetch` method of the SearchSource', function () {
const searchSourceStub = new SearchSourceStub();

return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
return fetchAnchor('INDEX_PATTERN_ID', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
.then(() => {
expect(searchSourceStub.fetch.calledOnce).to.be(true);
});
Expand All @@ -77,7 +77,7 @@ describe('context app', function () {
it('should configure the SearchSource to not inherit from the implicit root', function () {
const searchSourceStub = new SearchSourceStub();

return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
return fetchAnchor('INDEX_PATTERN_ID', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
.then(() => {
const setParentSpy = searchSourceStub.setParent;
expect(setParentSpy.calledOnce).to.be(true);
Expand All @@ -88,7 +88,7 @@ describe('context app', function () {
it('should set the SearchSource index pattern', function () {
const searchSourceStub = new SearchSourceStub();

return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
return fetchAnchor('INDEX_PATTERN_ID', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
.then(() => {
const setFieldSpy = searchSourceStub.setField;
expect(setFieldSpy.firstCall.args[1].id).to.eql('INDEX_PATTERN_ID');
Expand All @@ -98,7 +98,7 @@ describe('context app', function () {
it('should set the SearchSource version flag to true', function () {
const searchSourceStub = new SearchSourceStub();

return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
return fetchAnchor('INDEX_PATTERN_ID', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
.then(() => {
const setVersionSpy = searchSourceStub.setField.withArgs('version');
expect(setVersionSpy.calledOnce).to.be(true);
Expand All @@ -109,7 +109,7 @@ describe('context app', function () {
it('should set the SearchSource size to 1', function () {
const searchSourceStub = new SearchSourceStub();

return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
return fetchAnchor('INDEX_PATTERN_ID', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
.then(() => {
const setSizeSpy = searchSourceStub.setField.withArgs('size');
expect(setSizeSpy.calledOnce).to.be(true);
Expand All @@ -120,7 +120,7 @@ describe('context app', function () {
it('should set the SearchSource query to an ids query', function () {
const searchSourceStub = new SearchSourceStub();

return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
return fetchAnchor('INDEX_PATTERN_ID', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
.then(() => {
const setQuerySpy = searchSourceStub.setField.withArgs('query');
expect(setQuerySpy.calledOnce).to.be(true);
Expand All @@ -142,7 +142,7 @@ describe('context app', function () {
it('should set the SearchSource sort order', function () {
const searchSourceStub = new SearchSourceStub();

return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
return fetchAnchor('INDEX_PATTERN_ID', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
.then(() => {
const setSortSpy = searchSourceStub.setField.withArgs('sort');
expect(setSortSpy.calledOnce).to.be(true);
Expand All @@ -157,7 +157,7 @@ describe('context app', function () {
const searchSourceStub = new SearchSourceStub();
searchSourceStub._stubHits = [];

return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
return fetchAnchor('INDEX_PATTERN_ID', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
.then(
() => {
expect().fail('expected the promise to be rejected');
Expand All @@ -175,7 +175,7 @@ describe('context app', function () {
{ property2: 'value2' },
];

return fetchAnchor('INDEX_PATTERN_ID', 'doc', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
return fetchAnchor('INDEX_PATTERN_ID', 'id', [{ '@timestamp': 'desc' }, { '_doc': 'desc' }])
.then((anchorDocument) => {
expect(anchorDocument).to.have.property('property1', 'value1');
expect(anchorDocument).to.have.property('$$_isAnchor', true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export function fetchAnchorProvider(indexPatterns, Private) {

return async function fetchAnchor(
indexPatternId,
anchorType,
anchorId,
sort
) {
Expand Down
2 changes: 0 additions & 2 deletions src/legacy/core_plugins/kibana/public/context/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ module.directive('contextApp', function ContextApp() {
controllerAs: 'contextApp',
restrict: 'E',
scope: {
anchorType: '=',
anchorId: '=',
columns: '=',
indexPattern: '=',
Expand Down Expand Up @@ -110,7 +109,6 @@ function ContextAppController($scope, config, Private) {
const { queryParameters } = this.state;
if (
(newQueryParameters.indexPatternId !== queryParameters.indexPatternId)
|| (newQueryParameters.anchorType !== queryParameters.anchorType)
|| (newQueryParameters.anchorId !== queryParameters.anchorId)
|| (!_.isEqual(newQueryParameters.sort, queryParameters.sort))
) {
Expand Down
1 change: 0 additions & 1 deletion src/legacy/core_plugins/kibana/public/context/index.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<context-app
anchor-type="contextAppRoute.anchorType"
anchor-id="contextAppRoute.anchorId"
columns="contextAppRoute.state.columns"
discover-url="contextAppRoute.discoverUrl"
Expand Down
Loading

0 comments on commit 65e64c3

Please sign in to comment.