Skip to content

Commit

Permalink
fix privileges
Browse files Browse the repository at this point in the history
  • Loading branch information
walterra committed Aug 11, 2023
1 parent feb2493 commit 1223700
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 102 deletions.
Expand Up @@ -12,6 +12,11 @@ import { cloneDeep } from 'lodash';
import { APP_INDEX_PRIVILEGES } from '../constants';
import { Privileges } from '../types/privileges';

export interface PrivilegesAndCapabilities {
privileges: Privileges;
capabilities: Capabilities;
}

export interface TransformCapabilities {
canGetTransform: boolean;
canDeleteTransform: boolean;
Expand Down Expand Up @@ -89,7 +94,7 @@ export const getPrivilegesAndCapabilities = (
clusterPrivileges: Record<string, boolean>,
hasOneIndexWithAllPrivileges: boolean,
hasAllPrivileges: boolean
) => {
): PrivilegesAndCapabilities => {
const privilegesResult: Privileges = {
hasAllPrivileges: true,
missingPrivileges: {
Expand Down
5 changes: 0 additions & 5 deletions x-pack/plugins/transform/public/__mocks__/shared_imports.ts
Expand Up @@ -8,11 +8,6 @@
// actual mocks
export const expandLiteralStrings = jest.fn();
export const XJsonMode = jest.fn();
export const useRequest = jest.fn(() => ({
isLoading: false,
error: null,
data: undefined,
}));
export const getSavedSearch = jest.fn();

// just passing through the reimports
Expand Down
33 changes: 17 additions & 16 deletions x-pack/plugins/transform/public/app/app.tsx
Expand Up @@ -7,14 +7,13 @@

import React, { useContext, FC } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { Router, Routes, Route } from '@kbn/shared-ux-router';

import { ScopedHistory } from '@kbn/core/public';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

import { EuiErrorBoundary } from '@elastic/eui';

import { Router, Routes, Route } from '@kbn/shared-ux-router';
import { ScopedHistory } from '@kbn/core/public';
import { FormattedMessage } from '@kbn/i18n-react';

import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';

import { addInternalBasePath } from '../../common/constants';
Expand All @@ -23,7 +22,6 @@ import { SectionError } from './components';
import { SECTION_SLUG } from './common/constants';
import { AuthorizationContext, AuthorizationProvider } from './lib/authorization';
import { AppDependencies } from './app_dependencies';

import { CloneTransformSection } from './sections/clone_transform';
import { CreateTransformSection } from './sections/create_transform';
import { TransformManagementSection } from './sections/transform_management';
Expand Down Expand Up @@ -63,20 +61,23 @@ export const App: FC<{ history: ScopedHistory }> = ({ history }) => {

export const renderApp = (element: HTMLElement, appDependencies: AppDependencies) => {
const I18nContext = appDependencies.i18n.Context;
const queryClient = new QueryClient();

render(
<EuiErrorBoundary>
<KibanaThemeProvider theme$={appDependencies.theme.theme$}>
<KibanaContextProvider services={appDependencies}>
<AuthorizationProvider
privilegesEndpoint={{ path: addInternalBasePath(`privileges`), version: '1' }}
>
<I18nContext>
<App history={appDependencies.history} />
</I18nContext>
</AuthorizationProvider>
</KibanaContextProvider>
</KibanaThemeProvider>
<QueryClientProvider client={queryClient}>
<KibanaThemeProvider theme$={appDependencies.theme.theme$}>
<KibanaContextProvider services={appDependencies}>
<AuthorizationProvider
privilegesEndpoint={{ path: addInternalBasePath(`privileges`), version: '1' }}
>
<I18nContext>
<App history={appDependencies.history} />
</I18nContext>
</AuthorizationProvider>
</KibanaContextProvider>
</KibanaThemeProvider>
</QueryClientProvider>
</EuiErrorBoundary>,
element
);
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/transform/public/app/hooks/index.ts
Expand Up @@ -12,4 +12,3 @@ export { useResetTransforms } from './use_reset_transform';
export { useScheduleNowTransforms } from './use_schedule_now_transform';
export { useStartTransforms } from './use_start_transform';
export { useStopTransforms } from './use_stop_transform';
export { useRequest } from './use_request';
15 changes: 0 additions & 15 deletions x-pack/plugins/transform/public/app/hooks/use_request.ts

This file was deleted.

Expand Up @@ -6,16 +6,20 @@
*/

import React, { createContext } from 'react';
import { useQuery } from '@tanstack/react-query';

import { Privileges } from '../../../../../common/types/privileges';
import type { IHttpFetchError } from '@kbn/core-http-browser';

import { useRequest } from '../../../hooks';
import type { Privileges } from '../../../../../common/types/privileges';

import {
TransformCapabilities,
type PrivilegesAndCapabilities,
type TransformCapabilities,
INITIAL_CAPABILITIES,
} from '../../../../../common/privilege/has_privilege_factory';

import { useAppDependencies } from '../../../app_dependencies';

interface Authorization {
isLoading: boolean;
apiError: Error | null;
Expand All @@ -41,22 +45,36 @@ interface Props {
}

export const AuthorizationProvider = ({ privilegesEndpoint, children }: Props) => {
const { http } = useAppDependencies();

const { path, version } = privilegesEndpoint;

const {
isLoading,
error,
data: privilegesData,
} = useRequest({
path,
version,
method: 'get',
});
} = useQuery<PrivilegesAndCapabilities, IHttpFetchError>(
['transform-privileges-and-capabilities'],
async ({ signal }) => {
return await http.fetch<PrivilegesAndCapabilities>(path, {
version,
method: 'GET',
signal,
});
}
);

const value = {
isLoading,
privileges: isLoading ? { ...initialValue.privileges } : privilegesData.privileges,
capabilities: isLoading ? { ...INITIAL_CAPABILITIES } : privilegesData.capabilities,
apiError: error ? (error as Error) : null,
privileges:
isLoading || privilegesData === undefined
? { ...initialValue.privileges }
: privilegesData.privileges,
capabilities:
isLoading || privilegesData === undefined
? { ...INITIAL_CAPABILITIES }
: privilegesData.capabilities,
apiError: error ? error : null,
};

return (
Expand Down
2 changes: 0 additions & 2 deletions x-pack/plugins/transform/public/shared_imports.ts
Expand Up @@ -6,8 +6,6 @@
*/

export { XJsonMode } from '@kbn/ace';
export type { UseRequestConfig } from '@kbn/es-ui-shared-plugin/public';
export { useRequest } from '@kbn/es-ui-shared-plugin/public';

export type { GetMlSharedImportsReturnType } from '@kbn/ml-plugin/public';
export { getMlSharedImports } from '@kbn/ml-plugin/public';
Expand Down
100 changes: 49 additions & 51 deletions x-pack/plugins/transform/server/routes/api/privileges.ts
Expand Up @@ -5,15 +5,17 @@
* 2.0.
*/

import type { IScopedClusterClient } from '@kbn/core/server';
import type { IKibanaResponse, IScopedClusterClient } from '@kbn/core/server';
import type { SecurityHasPrivilegesResponse } from '@elastic/elasticsearch/lib/api/types';
import { getPrivilegesAndCapabilities } from '../../../common/privilege/has_privilege_factory';
import {
getPrivilegesAndCapabilities,
type PrivilegesAndCapabilities,
} from '../../../common/privilege/has_privilege_factory';
import {
addInternalBasePath,
APP_CLUSTER_PRIVILEGES,
APP_INDEX_PRIVILEGES,
} from '../../../common/constants';
import type { Privileges } from '../../../common/types/privileges';

import type { RouteDependencies } from '../../types';

Expand All @@ -23,64 +25,60 @@ export function registerPrivilegesRoute({ router, license }: RouteDependencies)
path: addInternalBasePath('privileges'),
access: 'internal',
})
.addVersion(
.addVersion<undefined, undefined, undefined>(
{
version: '1',
validate: false,
},
license.guardApiRoute(async (ctx, req, res) => {
const privilegesResult: Privileges = {
hasAllPrivileges: true,
missingPrivileges: {
cluster: [],
index: [],
},
};

if (license.getStatus().isSecurityEnabled === false) {
// If security isn't enabled, let the user use app.
return res.ok({ body: privilegesResult });
}
license.guardApiRoute<undefined, undefined, undefined>(
async (ctx, req, res): Promise<IKibanaResponse<PrivilegesAndCapabilities>> => {
if (license.getStatus().isSecurityEnabled === false) {
// If security isn't enabled, let the user use app.
return res.ok({
body: getPrivilegesAndCapabilities({}, true, true),
});
}

const esClient: IScopedClusterClient = (await ctx.core).elasticsearch.client;
const esClient: IScopedClusterClient = (await ctx.core).elasticsearch.client;

const esClusterPrivilegesReq: Promise<SecurityHasPrivilegesResponse> =
esClient.asCurrentUser.security.hasPrivileges({
body: {
cluster: APP_CLUSTER_PRIVILEGES,
},
});
const [esClusterPrivileges, userPrivileges] = await Promise.all([
// Get cluster privileges
esClusterPrivilegesReq,
// // Get all index privileges the user has
esClient.asCurrentUser.security.getUserPrivileges(),
]);
const esClusterPrivilegesReq: Promise<SecurityHasPrivilegesResponse> =
esClient.asCurrentUser.security.hasPrivileges({
body: {
cluster: APP_CLUSTER_PRIVILEGES,
},
});
const [esClusterPrivileges, userPrivileges] = await Promise.all([
// Get cluster privileges
esClusterPrivilegesReq,
// // Get all index privileges the user has
esClient.asCurrentUser.security.getUserPrivileges(),
]);

const { has_all_requested: hasAllPrivileges, cluster } = esClusterPrivileges;
const { indices } = userPrivileges;
const { has_all_requested: hasAllPrivileges, cluster } = esClusterPrivileges;
const { indices } = userPrivileges;

// Check if they have all the required index privileges for at least one index
const hasOneIndexWithAllPrivileges =
indices.find(({ privileges }: { privileges: string[] }) => {
if (privileges.includes('all')) {
return true;
}
// Check if they have all the required index privileges for at least one index
const hasOneIndexWithAllPrivileges =
indices.find(({ privileges }: { privileges: string[] }) => {
if (privileges.includes('all')) {
return true;
}

const indexHasAllPrivileges = APP_INDEX_PRIVILEGES.every((privilege) =>
privileges.includes(privilege)
);
const indexHasAllPrivileges = APP_INDEX_PRIVILEGES.every((privilege) =>
privileges.includes(privilege)
);

return indexHasAllPrivileges;
}) !== undefined;
return indexHasAllPrivileges;
}) !== undefined;

return res.ok({
body: getPrivilegesAndCapabilities(
cluster,
hasOneIndexWithAllPrivileges,
hasAllPrivileges
),
});
})
return res.ok({
body: getPrivilegesAndCapabilities(
cluster,
hasOneIndexWithAllPrivileges,
hasAllPrivileges
),
});
}
)
);
}

0 comments on commit 1223700

Please sign in to comment.