mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[SECURITY] Stop kibana crashes when no authentication providers are enabled (#118784)
* check if a provider is there * the last puzzle * fix lint * review oleg * Update x-pack/plugins/security/public/nav_control/nav_control_component.tsx Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com> * Update x-pack/test/security_api_integration/http_no_auth_providers.config.ts Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com> * Update x-pack/plugins/security/server/authentication/authenticator.test.ts Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com> * Update x-pack/test/security_api_integration/tests/http_no_auth_providers/authentication.ts Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com> * Update x-pack/test/security_api_integration/http_no_auth_providers.config.ts Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com> * review II Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com>
This commit is contained in:
parent
1ac885e428
commit
55fa55ddc9
8 changed files with 131 additions and 6 deletions
|
@ -128,6 +128,19 @@ describe('AuthenticationService', () => {
|
||||||
expect.any(Function)
|
expect.any(Function)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('properly registers auth handler with no providers', () => {
|
||||||
|
mockSetupAuthenticationParams.config.authc = {
|
||||||
|
...mockSetupAuthenticationParams.config.authc,
|
||||||
|
sortedProviders: [],
|
||||||
|
};
|
||||||
|
service.setup(mockSetupAuthenticationParams);
|
||||||
|
|
||||||
|
expect(mockSetupAuthenticationParams.http.registerAuth).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockSetupAuthenticationParams.http.registerAuth).toHaveBeenCalledWith(
|
||||||
|
expect.any(Function)
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#start()', () => {
|
describe('#start()', () => {
|
||||||
|
|
|
@ -98,7 +98,8 @@ export class AuthenticationService {
|
||||||
// 2. Login selector is disabled, but the provider with the lowest `order` uses login form
|
// 2. Login selector is disabled, but the provider with the lowest `order` uses login form
|
||||||
const isLoginPageAvailable =
|
const isLoginPageAvailable =
|
||||||
config.authc.selector.enabled ||
|
config.authc.selector.enabled ||
|
||||||
shouldProviderUseLoginForm(config.authc.sortedProviders[0].type);
|
(config.authc.sortedProviders.length > 0 &&
|
||||||
|
shouldProviderUseLoginForm(config.authc.sortedProviders[0].type));
|
||||||
|
|
||||||
http.registerAuth(async (request, response, t) => {
|
http.registerAuth(async (request, response, t) => {
|
||||||
if (!license.isLicenseAvailable()) {
|
if (!license.isLicenseAvailable()) {
|
||||||
|
|
|
@ -1872,6 +1872,24 @@ describe('Authenticator', () => {
|
||||||
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('if session does not exist and providers is empty, redirects to default logout path.', async () => {
|
||||||
|
const request = httpServerMock.createKibanaRequest();
|
||||||
|
|
||||||
|
mockOptions = getMockOptions({
|
||||||
|
providers: { basic: { basic1: { order: 0, enabled: false } } },
|
||||||
|
});
|
||||||
|
authenticator = new Authenticator(mockOptions);
|
||||||
|
|
||||||
|
await expect(authenticator.logout(request)).resolves.toEqual(
|
||||||
|
DeauthenticationResult.redirectTo(
|
||||||
|
'/mock-server-basepath/security/logged_out?msg=LOGGED_OUT'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mockBasicAuthenticationProvider.logout).not.toHaveBeenCalled();
|
||||||
|
expect(mockOptions.session.invalidate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it('redirects to login form if session does not exist and provider name is invalid', async () => {
|
it('redirects to login form if session does not exist and provider name is invalid', async () => {
|
||||||
const request = httpServerMock.createKibanaRequest({ query: { provider: 'foo' } });
|
const request = httpServerMock.createKibanaRequest({ query: { provider: 'foo' } });
|
||||||
mockOptions.session.get.mockResolvedValue(null);
|
mockOptions.session.get.mockResolvedValue(null);
|
||||||
|
|
|
@ -806,10 +806,7 @@ export class Authenticator {
|
||||||
* @param providerType Type of the provider that handles logout. If not specified, then the first
|
* @param providerType Type of the provider that handles logout. If not specified, then the first
|
||||||
* provider in the chain (default) is assumed.
|
* provider in the chain (default) is assumed.
|
||||||
*/
|
*/
|
||||||
private getLoggedOutURL(
|
private getLoggedOutURL(request: KibanaRequest, providerType?: string) {
|
||||||
request: KibanaRequest,
|
|
||||||
providerType: string = this.options.config.authc.sortedProviders[0].type
|
|
||||||
) {
|
|
||||||
// The app that handles logout needs to know the reason of the logout and the URL we may need to
|
// The app that handles logout needs to know the reason of the logout and the URL we may need to
|
||||||
// redirect user to once they log in again (e.g. when session expires).
|
// redirect user to once they log in again (e.g. when session expires).
|
||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
|
@ -825,7 +822,12 @@ export class Authenticator {
|
||||||
|
|
||||||
// Query string may contain the path where logout has been called or
|
// Query string may contain the path where logout has been called or
|
||||||
// logout reason that login page may need to know.
|
// logout reason that login page may need to know.
|
||||||
return this.options.config.authc.selector.enabled || shouldProviderUseLoginForm(providerType)
|
return this.options.config.authc.selector.enabled ||
|
||||||
|
(providerType
|
||||||
|
? shouldProviderUseLoginForm(providerType)
|
||||||
|
: this.options.config.authc.sortedProviders.length > 0
|
||||||
|
? shouldProviderUseLoginForm(this.options.config.authc.sortedProviders[0].type)
|
||||||
|
: false)
|
||||||
? `${this.options.basePath.serverBasePath}/login?${searchParams.toString()}`
|
? `${this.options.basePath.serverBasePath}/login?${searchParams.toString()}`
|
||||||
: `${this.options.basePath.serverBasePath}/security/logged_out?${searchParams.toString()}`;
|
: `${this.options.basePath.serverBasePath}/security/logged_out?${searchParams.toString()}`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ const onlyNotInCoverageTests = [
|
||||||
require.resolve('../test/security_api_integration/login_selector.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/audit.config.ts'),
|
||||||
require.resolve('../test/security_api_integration/http_bearer.config.ts'),
|
require.resolve('../test/security_api_integration/http_bearer.config.ts'),
|
||||||
|
require.resolve('../test/security_api_integration/http_no_auth_providers.config.ts'),
|
||||||
require.resolve('../test/security_api_integration/kerberos.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/kerberos_anonymous_access.config.ts'),
|
||||||
require.resolve('../test/security_api_integration/pki.config.ts'),
|
require.resolve('../test/security_api_integration/pki.config.ts'),
|
||||||
|
|
|
@ -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_no_auth_providers')],
|
||||||
|
servers: xPackAPITestsConfig.get('servers'),
|
||||||
|
security: { disableTestUser: true },
|
||||||
|
services,
|
||||||
|
junit: {
|
||||||
|
reportName: 'X-Pack Security API Integration Tests (HTTP without providers)',
|
||||||
|
},
|
||||||
|
|
||||||
|
esTestCluster: xPackAPITestsConfig.get('esTestCluster'),
|
||||||
|
|
||||||
|
kbnTestServer: {
|
||||||
|
...xPackAPITestsConfig.get('kbnTestServer'),
|
||||||
|
serverArgs: [
|
||||||
|
...xPackAPITestsConfig.get('kbnTestServer.serverArgs'),
|
||||||
|
`--xpack.security.authc.http.schemes=${JSON.stringify(['apikey', 'basic'])}`,
|
||||||
|
`--xpack.security.authc.providers=${JSON.stringify({
|
||||||
|
basic: { basic1: { order: 0, enabled: false } },
|
||||||
|
})}`,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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');
|
||||||
|
|
||||||
|
describe('authorization', () => {
|
||||||
|
it('fail request without authorization request header', async () => {
|
||||||
|
await supertest.get('/internal/security/me').set('kbn-xsrf', 'true').expect(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accept request with authorization request header', async () => {
|
||||||
|
const credentials = Buffer.from(
|
||||||
|
`${adminTestUser.username}:${adminTestUser.password}`
|
||||||
|
).toString('base64');
|
||||||
|
|
||||||
|
const { body: user, headers } = await supertest
|
||||||
|
.get('/internal/security/me')
|
||||||
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set('Authorization', `Basic ${credentials}`)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(user.username).to.eql(adminTestUser.username);
|
||||||
|
expect(user.authentication_provider).to.eql({ type: 'http', name: '__http__' });
|
||||||
|
expect(user.authentication_type).to.eql('realm');
|
||||||
|
|
||||||
|
// Make sure we don't automatically create a session
|
||||||
|
expect(headers['set-cookie']).to.be(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -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 no authentication providers are enabled', function () {
|
||||||
|
this.tags('ciGroup6');
|
||||||
|
loadTestFile(require.resolve('./authentication'));
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue