Don't query for the current user on anonymous pages (#99511) (#99551)

Co-authored-by: Larry Gregory <larry.gregory@elastic.co>
This commit is contained in:
Kibana Machine 2021-05-06 20:55:33 -04:00 committed by GitHub
parent 1e7b83dbd1
commit 3a23dc1a17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 68 additions and 34 deletions

View file

@ -13,10 +13,7 @@ import { CloudPlugin } from './plugin';
describe('Cloud Plugin', () => {
describe('#start', () => {
function setupPlugin({
roles = [],
simulateUserError = false,
}: { roles?: string[]; simulateUserError?: boolean } = {}) {
function setupPlugin() {
const plugin = new CloudPlugin(
coreMock.createPluginInitializerContext({
id: 'cloudId',
@ -28,20 +25,10 @@ describe('Cloud Plugin', () => {
);
const coreSetup = coreMock.createSetup();
const homeSetup = homePluginMock.createSetupContract();
const securitySetup = securityMock.createSetup();
if (simulateUserError) {
securitySetup.authc.getCurrentUser.mockRejectedValue(new Error('Something happened'));
} else {
securitySetup.authc.getCurrentUser.mockResolvedValue(
securityMock.createMockAuthenticatedUser({
roles,
})
);
}
plugin.setup(coreSetup, { home: homeSetup, security: securitySetup });
plugin.setup(coreSetup, { home: homeSetup });
return { coreSetup, securitySetup, plugin };
return { coreSetup, plugin };
}
it('registers help support URL', async () => {
@ -59,11 +46,37 @@ describe('Cloud Plugin', () => {
`);
});
it('does not register custom nav links on anonymous pages', async () => {
const { plugin } = setupPlugin();
const coreStart = coreMock.createStart();
coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true);
const securityStart = securityMock.createStart();
securityStart.authc.getCurrentUser.mockResolvedValue(
securityMock.createMockAuthenticatedUser({
roles: ['superuser'],
})
);
plugin.start(coreStart, { security: securityStart });
await nextTick();
expect(coreStart.chrome.setCustomNavLink).not.toHaveBeenCalled();
expect(securityStart.authc.getCurrentUser).not.toHaveBeenCalled();
});
it('registers a custom nav link for superusers', async () => {
const { plugin } = setupPlugin({ roles: ['superuser'] });
const { plugin } = setupPlugin();
const coreStart = coreMock.createStart();
const securityStart = securityMock.createStart();
securityStart.authc.getCurrentUser.mockResolvedValue(
securityMock.createMockAuthenticatedUser({
roles: ['superuser'],
})
);
plugin.start(coreStart, { security: securityStart });
await nextTick();
@ -81,10 +94,11 @@ describe('Cloud Plugin', () => {
});
it('registers a custom nav link when there is an error retrieving the current user', async () => {
const { plugin } = setupPlugin({ simulateUserError: true });
const { plugin } = setupPlugin();
const coreStart = coreMock.createStart();
const securityStart = securityMock.createStart();
securityStart.authc.getCurrentUser.mockRejectedValue(new Error('something happened'));
plugin.start(coreStart, { security: securityStart });
await nextTick();
@ -102,10 +116,15 @@ describe('Cloud Plugin', () => {
});
it('does not register a custom nav link for non-superusers', async () => {
const { plugin } = setupPlugin({ roles: ['not-a-superuser'] });
const { plugin } = setupPlugin();
const coreStart = coreMock.createStart();
const securityStart = securityMock.createStart();
securityStart.authc.getCurrentUser.mockResolvedValue(
securityMock.createMockAuthenticatedUser({
roles: ['not-a-superuser'],
})
);
plugin.start(coreStart, { security: securityStart });
await nextTick();
@ -114,10 +133,15 @@ describe('Cloud Plugin', () => {
});
it('registers user profile links for superusers', async () => {
const { plugin } = setupPlugin({ roles: ['superuser'] });
const { plugin } = setupPlugin();
const coreStart = coreMock.createStart();
const securityStart = securityMock.createStart();
securityStart.authc.getCurrentUser.mockResolvedValue(
securityMock.createMockAuthenticatedUser({
roles: ['superuser'],
})
);
plugin.start(coreStart, { security: securityStart });
await nextTick();
@ -145,10 +169,11 @@ describe('Cloud Plugin', () => {
});
it('registers profile links when there is an error retrieving the current user', async () => {
const { plugin } = setupPlugin({ simulateUserError: true });
const { plugin } = setupPlugin();
const coreStart = coreMock.createStart();
const securityStart = securityMock.createStart();
securityStart.authc.getCurrentUser.mockRejectedValue(new Error('something happened'));
plugin.start(coreStart, { security: securityStart });
await nextTick();
@ -176,10 +201,15 @@ describe('Cloud Plugin', () => {
});
it('does not register profile links for non-superusers', async () => {
const { plugin } = setupPlugin({ roles: ['not-a-superuser'] });
const { plugin } = setupPlugin();
const coreStart = coreMock.createStart();
const securityStart = securityMock.createStart();
securityStart.authc.getCurrentUser.mockResolvedValue(
securityMock.createMockAuthenticatedUser({
roles: ['not-a-superuser'],
})
);
plugin.start(coreStart, { security: securityStart });
await nextTick();

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public';
import { CoreSetup, CoreStart, Plugin, PluginInitializerContext, HttpStart } from 'src/core/public';
import { i18n } from '@kbn/i18n';
import { AuthenticatedUser, SecurityPluginSetup, SecurityPluginStart } from '../../security/public';
import { SecurityPluginSetup, SecurityPluginStart } from '../../security/public';
import { getIsCloudEnabled } from '../common/is_cloud_enabled';
import { ELASTIC_SUPPORT_LINK } from '../common/constants';
import { HomePublicPluginSetup } from '../../../../src/plugins/home/public';
@ -45,14 +45,13 @@ export interface CloudSetup {
export class CloudPlugin implements Plugin<CloudSetup> {
private config!: CloudConfigType;
private isCloudEnabled: boolean;
private authenticatedUserPromise?: Promise<AuthenticatedUser | null>;
constructor(private readonly initializerContext: PluginInitializerContext) {
this.config = this.initializerContext.config.get<CloudConfigType>();
this.isCloudEnabled = false;
}
public setup(core: CoreSetup, { home, security }: CloudSetupDependencies) {
public setup(core: CoreSetup, { home }: CloudSetupDependencies) {
const {
id,
cname,
@ -70,10 +69,6 @@ export class CloudPlugin implements Plugin<CloudSetup> {
}
}
if (security) {
this.authenticatedUserPromise = security.authc.getCurrentUser().catch(() => null);
}
return {
cloudId: id,
cname,
@ -108,7 +103,7 @@ export class CloudPlugin implements Plugin<CloudSetup> {
}
};
this.checkIfAuthorizedForLinks()
this.checkIfAuthorizedForLinks({ http: coreStart.http, security })
.then(setLinks)
// In the event of an unexpected error, fail *open*.
// Cloud admin console will always perform the actual authorization checks.
@ -123,12 +118,21 @@ export class CloudPlugin implements Plugin<CloudSetup> {
* At this point, we do not have enough information to reliably make this determination,
* but we do know that all cloud deployment admins are superusers by default.
*/
private async checkIfAuthorizedForLinks() {
private async checkIfAuthorizedForLinks({
http,
security,
}: {
http: HttpStart;
security?: SecurityPluginStart;
}) {
if (http.anonymousPaths.isAnonymous(window.location.pathname)) {
return false;
}
// Security plugin is disabled
if (!this.authenticatedUserPromise) return true;
if (!security) return true;
// Otherwise check roles. If user is not defined due to an unexpected error, then fail *open*.
// Cloud admin console will always perform the actual authorization checks.
const user = await this.authenticatedUserPromise;
const user = await security.authc.getCurrentUser().catch(() => null);
return user?.roles.includes('superuser') ?? true;
}
}