mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com>
This commit is contained in:
parent
63b9762e82
commit
e250fc5a9b
10 changed files with 174 additions and 8 deletions
|
@ -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.
|
||||
|
||||
|===
|
||||
|
||||
|
|
|
@ -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]]
|
||||
|
|
|
@ -210,7 +210,7 @@ describe('Authenticator', () => {
|
|||
expect(
|
||||
jest.requireMock('./providers/http').HTTPAuthenticationProvider
|
||||
).toHaveBeenCalledWith(expect.anything(), {
|
||||
supportedSchemes: new Set(['apikey', 'basic']),
|
||||
supportedSchemes: new Set(['apikey', 'bearer', 'basic']),
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -238,7 +238,9 @@ describe('Authenticator', () => {
|
|||
|
||||
expect(
|
||||
jest.requireMock('./providers/http').HTTPAuthenticationProvider
|
||||
).toHaveBeenCalledWith(expect.anything(), { supportedSchemes: new Set(['apikey']) });
|
||||
).toHaveBeenCalledWith(expect.anything(), {
|
||||
supportedSchemes: new Set(['apikey', 'bearer']),
|
||||
});
|
||||
});
|
||||
|
||||
it('disabled if explicitly disabled', () => {
|
||||
|
|
|
@ -27,6 +27,7 @@ describe('config schema', () => {
|
|||
"enabled": true,
|
||||
"schemes": Array [
|
||||
"apikey",
|
||||
"bearer",
|
||||
],
|
||||
},
|
||||
"providers": Object {
|
||||
|
@ -78,6 +79,7 @@ describe('config schema', () => {
|
|||
"enabled": true,
|
||||
"schemes": Array [
|
||||
"apikey",
|
||||
"bearer",
|
||||
],
|
||||
},
|
||||
"providers": Object {
|
||||
|
@ -129,6 +131,7 @@ describe('config schema', () => {
|
|||
"enabled": true,
|
||||
"schemes": Array [
|
||||
"apikey",
|
||||
"bearer",
|
||||
],
|
||||
},
|
||||
"providers": Object {
|
||||
|
@ -305,6 +308,7 @@ describe('config schema', () => {
|
|||
"enabled": true,
|
||||
"schemes": Array [
|
||||
"apikey",
|
||||
"bearer",
|
||||
],
|
||||
},
|
||||
"oidc": Object {
|
||||
|
@ -336,6 +340,7 @@ describe('config schema', () => {
|
|||
"enabled": true,
|
||||
"schemes": Array [
|
||||
"apikey",
|
||||
"bearer",
|
||||
],
|
||||
},
|
||||
"oidc": Object {
|
||||
|
@ -367,6 +372,7 @@ describe('config schema', () => {
|
|||
"enabled": true,
|
||||
"schemes": Array [
|
||||
"apikey",
|
||||
"bearer",
|
||||
],
|
||||
},
|
||||
"providers": Array [
|
||||
|
@ -385,6 +391,7 @@ describe('config schema', () => {
|
|||
"enabled": true,
|
||||
"schemes": Array [
|
||||
"apikey",
|
||||
"bearer",
|
||||
],
|
||||
},
|
||||
"providers": Array [
|
||||
|
@ -406,6 +413,7 @@ describe('config schema', () => {
|
|||
"enabled": true,
|
||||
"schemes": Array [
|
||||
"apikey",
|
||||
"bearer",
|
||||
],
|
||||
},
|
||||
"providers": Array [
|
||||
|
@ -1479,6 +1487,7 @@ describe('createConfig()', () => {
|
|||
"enabled": true,
|
||||
"schemes": Array [
|
||||
"apikey",
|
||||
"bearer",
|
||||
],
|
||||
},
|
||||
"providers": Object {
|
||||
|
|
|
@ -265,7 +265,7 @@ export const ConfigSchema = schema.object({
|
|||
http: schema.object({
|
||||
enabled: schema.boolean({ defaultValue: true }),
|
||||
autoSchemesEnabled: schema.boolean({ defaultValue: true }),
|
||||
schemes: schema.arrayOf(schema.string(), { defaultValue: ['apikey'] }),
|
||||
schemes: schema.arrayOf(schema.string(), { defaultValue: ['apikey', 'bearer'] }),
|
||||
}),
|
||||
}),
|
||||
audit: schema.object(
|
||||
|
|
|
@ -46,7 +46,7 @@ describe('Security UsageCollector', () => {
|
|||
authProviderCount: 1,
|
||||
enabledAuthProviders: ['basic'],
|
||||
loginSelectorEnabled: false,
|
||||
httpAuthSchemes: ['apikey'],
|
||||
httpAuthSchemes: ['apikey', 'bearer'],
|
||||
sessionIdleTimeoutInMinutes: 0,
|
||||
sessionLifespanInMinutes: 0,
|
||||
sessionCleanupInMinutes: 60,
|
||||
|
|
|
@ -50,6 +50,7 @@ require('@kbn/test').runTestsCli([
|
|||
require.resolve('../test/security_api_integration/session_lifespan.config.ts'),
|
||||
require.resolve('../test/security_api_integration/login_selector.config.ts'),
|
||||
require.resolve('../test/security_api_integration/audit.config.ts'),
|
||||
require.resolve('../test/security_api_integration/http_bearer.config.ts'),
|
||||
require.resolve('../test/security_api_integration/kerberos.config.ts'),
|
||||
require.resolve('../test/security_api_integration/kerberos_anonymous_access.config.ts'),
|
||||
require.resolve('../test/security_api_integration/pki.config.ts'),
|
||||
|
|
36
x-pack/test/security_api_integration/http_bearer.config.ts
Normal file
36
x-pack/test/security_api_integration/http_bearer.config.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrConfigProviderContext } from '@kbn/test';
|
||||
import { services } from './services';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const xPackAPITestsConfig = await readConfigFile(require.resolve('../api_integration/config.ts'));
|
||||
|
||||
return {
|
||||
testFiles: [require.resolve('./tests/http_bearer')],
|
||||
servers: xPackAPITestsConfig.get('servers'),
|
||||
security: { disableTestUser: true },
|
||||
services,
|
||||
junit: {
|
||||
reportName: 'X-Pack Security API Integration Tests (HTTP Bearer)',
|
||||
},
|
||||
|
||||
esTestCluster: {
|
||||
...xPackAPITestsConfig.get('esTestCluster'),
|
||||
serverArgs: [
|
||||
...xPackAPITestsConfig.get('esTestCluster.serverArgs'),
|
||||
'xpack.security.authc.token.enabled=true',
|
||||
'xpack.security.authc.token.timeout=15s',
|
||||
],
|
||||
},
|
||||
|
||||
kbnTestServer: {
|
||||
...xPackAPITestsConfig.get('kbnTestServer'),
|
||||
},
|
||||
};
|
||||
}
|
103
x-pack/test/security_api_integration/tests/http_bearer/header.ts
Normal file
103
x-pack/test/security_api_integration/tests/http_bearer/header.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { adminTestUser } from '@kbn/test';
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const supertest = getService('supertestWithoutAuth');
|
||||
const es = getService('es');
|
||||
|
||||
async function createToken() {
|
||||
const {
|
||||
body: { access_token: accessToken, authentication },
|
||||
} = await es.security.getToken({
|
||||
body: {
|
||||
grant_type: 'password',
|
||||
...adminTestUser,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
accessToken,
|
||||
expectedUser: {
|
||||
...authentication,
|
||||
authentication_provider: { name: '__http__', type: 'http' },
|
||||
authentication_type: 'token',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('header', () => {
|
||||
it('accepts valid access token via authorization Bearer header', async () => {
|
||||
const { accessToken, expectedUser } = await createToken();
|
||||
|
||||
const response = await supertest
|
||||
.get('/internal/security/me')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('authorization', `Bearer ${accessToken}`)
|
||||
.expect(200, expectedUser);
|
||||
|
||||
// Make sure we don't automatically create a session
|
||||
expect(response.headers['set-cookie']).to.be(undefined);
|
||||
});
|
||||
|
||||
it('accepts multiple requests for a single valid access token', async () => {
|
||||
const { accessToken, expectedUser } = await createToken();
|
||||
|
||||
// try it once
|
||||
await supertest
|
||||
.get('/internal/security/me')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('authorization', `Bearer ${accessToken}`)
|
||||
.expect(200, expectedUser);
|
||||
|
||||
// try it again to verity it isn't invalidated after a single request
|
||||
await supertest
|
||||
.get('/internal/security/me')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('authorization', `Bearer ${accessToken}`)
|
||||
.expect(200, expectedUser);
|
||||
});
|
||||
|
||||
it('rejects invalid access token via authorization Bearer header', async () => {
|
||||
await supertest
|
||||
.get('/internal/security/me')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('authorization', 'Bearer notreal')
|
||||
.expect(401);
|
||||
});
|
||||
|
||||
it('rejects invalidated access token via authorization Bearer header', async () => {
|
||||
const { accessToken } = await createToken();
|
||||
await es.security.invalidateToken({ body: { token: accessToken } });
|
||||
|
||||
await supertest
|
||||
.get('/internal/security/me')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('authorization', `Bearer ${accessToken}`)
|
||||
.expect(401);
|
||||
});
|
||||
|
||||
it('rejects expired access token via authorization Bearer header', async function () {
|
||||
this.timeout(40000);
|
||||
|
||||
const { accessToken } = await createToken();
|
||||
|
||||
// Access token expiration is set to 15s for API integration tests.
|
||||
// Let's wait for 20s to make sure token expires.
|
||||
await new Promise((resolve) => setTimeout(resolve, 20000));
|
||||
|
||||
await supertest
|
||||
.get('/internal/security/me')
|
||||
.set('kbn-xsrf', 'true')
|
||||
.set('authorization', `Bearer ${accessToken}`)
|
||||
.expect(401);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { FtrProviderContext } from '../../ftr_provider_context';
|
||||
|
||||
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||
describe('security APIs - HTTP Bearer', function () {
|
||||
this.tags('ciGroup6');
|
||||
loadTestFile(require.resolve('./header'));
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue