Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions public/apps/account/account-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ function tenantSpecifiedInUrl() {

export async function setupTopNavButton(coreStart: CoreStart, config: ClientConfigType) {
const accountInfo = (await fetchAccountInfoSafe(coreStart.http))?.data;
const currentTenant = await fetchCurrentTenant(coreStart.http);
if (accountInfo) {
// Missing role error
if (accountInfo.roles.length === 0 && !window.location.href.includes(CUSTOM_ERROR_PAGE_URI)) {
Expand All @@ -46,11 +45,12 @@ export async function setupTopNavButton(coreStart: CoreStart, config: ClientConf
}

let tenant: string | undefined;
if (config.multitenancy.enable_aggregation_view) {
tenant = currentTenant;
if (config.multitenancy.enabled && config.multitenancy.enable_aggregation_view) {
tenant = await fetchCurrentTenant(coreStart.http);
} else {
tenant = accountInfo.user_requested_tenant;
}

let shouldShowTenantPopup = true;

if (tenantSpecifiedInUrl() || getShouldShowTenantPopup() === false) {
Expand Down
8 changes: 5 additions & 3 deletions public/apps/account/tenant-switch-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,11 @@ export function TenantSwitchPanel(props: TenantSwitchPanelProps) {
const currentUserName = accountInfo.data.user_name;
setUsername(currentUserName);

// @ts-ignore
let currentRawTenantName: string | undefined;
if (props.config.multitenancy.enable_aggregation_view) {
if (
props.config.multitenancy.enabled &&
props.config.multitenancy.enable_aggregation_view
) {
currentRawTenantName = props.tenant;
} else {
currentRawTenantName = accountInfo.data.user_requested_tenant;
Expand All @@ -106,7 +108,7 @@ export function TenantSwitchPanel(props: TenantSwitchPanelProps) {
};

fetchData();
}, [props.coreStart.http, props.tenant, props.config.multitenancy.enable_aggregation_view]);
}, [props.coreStart.http, props.tenant, props.config.multitenancy]);

// Custom tenant super select related.
const onCustomTenantChange = (selectedOption: EuiComboBoxOptionOption[]) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function ClusterPermissionPanel(props: {
options={optionUniverse}
selectedOptions={state}
onChange={setState}
id="cluster-permission-box"
id="roles-cluster-permission-box"
/>
</EuiFlexItem>
{/* TODO: 'Browse and select' button with a pop-up modal for selection */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export function IndexPermissionRow(props: {
options={props.permisionOptionsSet}
selectedOptions={props.value}
onChange={props.onChangeHandler}
id="index-permission-box"
id="roles-index-permission-box"
/>
</EuiFlexItem>
{/* TODO: 'Browse and select' button with a pop-up modal for selection */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ function generateTenantPermissionPanels(
onChange={onValueChangeHandler('tenantPatterns')}
onCreateOption={onCreateOptionHandler('tenantPatterns')}
options={permisionOptionsSet}
id="tenant-permission-box"
id="roles-tenant-permission-box"
/>
</EuiFlexItem>
<EuiFlexItem style={{ maxWidth: '170px' }}>
Expand Down
17 changes: 14 additions & 3 deletions public/apps/configuration/utils/tenant-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ import { httpDelete, httpGet, httpPost } from './request-utils';
import { getResourceUrl } from './resource-utils';

export const globalTenantName = 'global_tenant';
export const GLOBAL_TENANT = '';
export const PRIVATE_TENANT = '__user__';
export const DEFAULT_TENANT = 'default';
export const GLOBAL_USER_DICT: { [key: string]: string } = {
Label: 'Global',
Value: '',
Value: GLOBAL_TENANT,
Description: 'Everyone can see it',
};

Expand All @@ -62,10 +65,10 @@ export function transformTenantData(
): Tenant[] {
// @ts-ignore
const tenantList: Tenant[] = map<Tenant, Tenant>(rawTenantData, (v: Tenant, k?: string) => ({
tenant: k === globalTenantName ? GLOBAL_USER_DICT.Label : k || '',
tenant: k === globalTenantName ? GLOBAL_USER_DICT.Label : k || GLOBAL_TENANT,
reserved: v.reserved,
description: k === globalTenantName ? GLOBAL_USER_DICT.Description : v.description,
tenantValue: k === globalTenantName ? GLOBAL_USER_DICT.Value : k || '',
tenantValue: k === globalTenantName ? GLOBAL_USER_DICT.Value : k || GLOBAL_TENANT,
}));
if (isPrivateEnabled) {
// Insert Private Tenant in List
Expand Down Expand Up @@ -170,3 +173,11 @@ export function transformRoleTenantPermissions(
permissionType: getTenantPermissionType(tenantPermission.allowed_actions),
}));
}

export function isPrivateTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant?.startsWith(PRIVATE_TENANT);
}

export function isGlobalTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant === GLOBAL_TENANT;
}
27 changes: 4 additions & 23 deletions public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@
*/

import { BehaviorSubject } from 'rxjs';
import {
SavedObjectsManagementColumn,
SavedObjectsManagementRecord,
} from 'src/plugins/saved_objects_management/public';
import { EuiTableFieldDataColumnType } from '@elastic/eui';
import { string } from 'joi';
import { SavedObjectsManagementColumn } from 'src/plugins/saved_objects_management/public';
import React from 'react';
import { i18n } from '@osd/i18n';
import {
Expand Down Expand Up @@ -53,6 +48,7 @@ import {
} from './types';
import { addTenantToShareURL } from './services/shared-link';
import { interceptError } from './utils/logout-utils';
import { isGlobalTenant, isPrivateTenant } from './apps/configuration/utils/tenant-utils';

async function hasApiPermission(core: CoreSetup): Promise<boolean | undefined> {
try {
Expand All @@ -73,8 +69,6 @@ const APP_ID_OPENSEARCH_DASHBOARDS = 'kibana';
const APP_LIST_FOR_READONLY_ROLE = [APP_ID_HOME, APP_ID_DASHBOARDS, APP_ID_OPENSEARCH_DASHBOARDS];
const GLOBAL_TENANT_RENDERING_TEXT = 'Global';
const PRIVATE_TENANT_RENDERING_TEXT = 'Private';
const GLOBAL_TENANT = '';
const PRIVATE_TENANT = '__user__';

export class SecurityPlugin
implements
Expand Down Expand Up @@ -161,15 +155,15 @@ export class SecurityPlugin
})
);

if (config.multitenancy.enable_aggregation_view) {
if (config.multitenancy.enabled && config.multitenancy.enable_aggregation_view) {
deps.savedObjectsManagement.columns.register(({
id: 'tenant_column',
euiColumn: {
field: 'namespaces',
name: <div>Tenant</div>,
dataType: 'string',
render: (value: any[][]) => {
let text = value[0][0];
let text = value.flat()[0];
if (isGlobalTenant(text)) {
text = GLOBAL_TENANT_RENDERING_TEXT;
} else if (isPrivateTenant(text)) {
Expand Down Expand Up @@ -204,21 +198,8 @@ export class SecurityPlugin
if (config.multitenancy.enabled) {
addTenantToShareURL(core);
}

if (config.multitenancy.enable_aggregation_view) {
const columns = deps.savedObjectsManagement.columns.getAll();
}

return {};
}

public stop() {}
}

function isPrivateTenant(selectedTenant: string) {
return selectedTenant.startsWith('__user__');
}

function isGlobalTenant(selectedTenant: string) {
return selectedTenant === null || selectedTenant === GLOBAL_TENANT;
}
9 changes: 4 additions & 5 deletions server/auth/types/authentication_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
IOpenSearchDashboardsResponse,
AuthResult,
} from 'opensearch-dashboards/server';
import { any } from 'joi';
import { SecurityPluginConfigType } from '../..';
import { SecuritySessionCookie } from '../../session/security_cookie';
import { SecurityClient } from '../../backend/opensearch_security_client';
Expand All @@ -36,6 +35,7 @@ import {
isValidTenant,
} from '../../multitenancy/tenant_resolver';
import { UnauthenticatedError } from '../../errors';
import { GLOBAL_TENANT } from '../../../public/apps/configuration/utils/tenant-utils';

export interface IAuthenticationType {
type: string;
Expand Down Expand Up @@ -102,7 +102,6 @@ export abstract class AuthenticationType implements IAuthenticationType {
}

const authState: OpenSearchDashboardsAuthState = {};
const globalTenant = '';

// if browser request, auth logic is:
// 1. check if request includes auth header or paramter(e.g. jwt in url params) is present, if so, authenticate with auth header.
Expand Down Expand Up @@ -184,9 +183,9 @@ export abstract class AuthenticationType implements IAuthenticationType {
authState.selectedTenant = tenant;

// set tenant in header
if (this.config.multitenancy.enable_aggregation_view) {
if (this.config.multitenancy.enabled && this.config.multitenancy.enable_aggregation_view) {
// Store all saved objects in a single kibana index.
Object.assign(authHeaders, { securitytenant: globalTenant });
Object.assign(authHeaders, { securitytenant: GLOBAL_TENANT });
} else {
Object.assign(authHeaders, { securitytenant: tenant });
}
Expand Down Expand Up @@ -245,7 +244,7 @@ export abstract class AuthenticationType implements IAuthenticationType {
if (!authInfo) {
try {
authInfo = await this.securityClient.authinfo(request, authHeader);
} catch (error) {
} catch (error: any) {
throw new UnauthenticatedError(error);
}
}
Expand Down
11 changes: 6 additions & 5 deletions server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

import { first } from 'rxjs/operators';
import { Observable } from 'rxjs';
import _ from 'lodash';
import {
PluginInitializerContext,
CoreSetup,
Expand Down Expand Up @@ -134,9 +133,9 @@ export class SecurityPlugin implements Plugin<SecurityPluginSetup, SecurityPlugi
setupMultitenantRoutes(router, securitySessionStorageFactory, this.securityClient);
}

if (config.multitenancy.enable_aggregation_view) {
if (config.multitenancy.enabled && config.multitenancy.enable_aggregation_view) {
core.savedObjects.addClientWrapper(
1,
2,
'security-saved-object-client-wrapper',
this.savedObjectClientWrapper.wrapperFactory
);
Expand All @@ -152,10 +151,12 @@ export class SecurityPlugin implements Plugin<SecurityPluginSetup, SecurityPlugi
public async start(core: CoreStart) {
this.logger.debug('opendistro_security: Started');

this.savedObjectClientWrapper.httpStart = core.http;

const config$ = this.initializerContext.config.create<SecurityPluginConfigType>();
const config = await config$.pipe(first()).toPromise();

this.savedObjectClientWrapper.httpStart = core.http;
this.savedObjectClientWrapper.config = config;

if (config.multitenancy?.enabled) {
const globalConfig$: Observable<SharedGlobalConfig> = this.initializerContext.config.legacy
.globalConfig$;
Expand Down
44 changes: 26 additions & 18 deletions server/saved_objects/saved_objects_wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,19 @@ import {
SavedObjectsUpdateOptions,
SavedObjectsUpdateResponse,
} from 'opensearch-dashboards/server';
import { Config } from 'packages/osd-config/target';
import { SecurityPluginConfigType } from '..';
import {
DEFAULT_TENANT,
GLOBAL_TENANT,
isPrivateTenant,
PRIVATE_TENANT,
} from '../../public/apps/configuration/utils/tenant-utils';
import { OpenSearchDashboardsAuthState } from '../auth/types/authentication_type';

export class SecuritySavedObjectsClientWrapper {
public httpStart?: HttpServiceStart;
public config?: SecurityPluginConfigType;

constructor() {}

Expand All @@ -48,9 +57,8 @@ export class SecuritySavedObjectsClientWrapper {

const selectedTenant = state.selectedTenant;
const username = state.authInfo?.user_name;
const globalTenant = '';
const defaultTenant = 'default';
const privateTenant = '__user__';
const isGlobalEnabled = this.config!.multitenancy.tenants.enable_global;
const isPrivateEnabled = this.config!.multitenancy.tenants.enable_private;

let namespaceValue = selectedTenant;

Expand All @@ -59,7 +67,7 @@ export class SecuritySavedObjectsClientWrapper {
attributes: T,
options?: SavedObjectsCreateOptions
) => {
if (selectedTenant !== undefined && isPrivateTenant(selectedTenant)) {
if (selectedTenant !== undefined && isPrivateEnabled && isPrivateTenant(selectedTenant)) {
namespaceValue = selectedTenant + username;
}
_.assign(options, { namespace: [namespaceValue] });
Expand All @@ -70,7 +78,7 @@ export class SecuritySavedObjectsClientWrapper {
objects: SavedObjectsBulkGetObject[] = [],
options: SavedObjectsBaseOptions = {}
): Promise<SavedObjectsBulkResponse<T>> => {
if (selectedTenant !== undefined && isPrivateTenant(selectedTenant)) {
if (selectedTenant !== undefined && isPrivateEnabled && isPrivateTenant(selectedTenant)) {
namespaceValue = selectedTenant + username;
}
_.assign(options, { namespace: [namespaceValue] });
Expand All @@ -82,9 +90,13 @@ export class SecuritySavedObjectsClientWrapper {
): Promise<SavedObjectsFindResponse<T>> => {
const tenants = state.authInfo?.tenants;
const availableTenantNames = Object.keys(tenants!);
availableTenantNames.push(defaultTenant);
availableTenantNames.push(globalTenant);
availableTenantNames.push(privateTenant + state.authInfo?.user_name);
availableTenantNames.push(DEFAULT_TENANT);
if (isGlobalEnabled) {
availableTenantNames.push(GLOBAL_TENANT);
}
if (isPrivateEnabled) {
availableTenantNames.push(PRIVATE_TENANT + state.authInfo?.user_name);
}
_.assign(options, { namespaces: availableTenantNames });
return await wrapperOptions.client.find(options);
};
Expand All @@ -94,7 +106,7 @@ export class SecuritySavedObjectsClientWrapper {
id: string,
options: SavedObjectsBaseOptions = {}
): Promise<SavedObject<T>> => {
if (selectedTenant !== undefined && isPrivateTenant(selectedTenant)) {
if (selectedTenant !== undefined && isPrivateEnabled && isPrivateTenant(selectedTenant)) {
namespaceValue = selectedTenant + username;
}
_.assign(options, { namespace: [namespaceValue] });
Expand All @@ -107,7 +119,7 @@ export class SecuritySavedObjectsClientWrapper {
attributes: Partial<T>,
options: SavedObjectsUpdateOptions = {}
): Promise<SavedObjectsUpdateResponse<T>> => {
if (selectedTenant !== undefined && isPrivateTenant(selectedTenant)) {
if (selectedTenant !== undefined && isPrivateEnabled && isPrivateTenant(selectedTenant)) {
namespaceValue = selectedTenant + username;
}
_.assign(options, { namespace: [namespaceValue] });
Expand All @@ -118,7 +130,7 @@ export class SecuritySavedObjectsClientWrapper {
objects: Array<SavedObjectsBulkCreateObject<T>>,
options?: SavedObjectsCreateOptions
): Promise<SavedObjectsBulkResponse<T>> => {
if (selectedTenant !== undefined && isPrivateTenant(selectedTenant)) {
if (selectedTenant !== undefined && isPrivateEnabled && isPrivateTenant(selectedTenant)) {
namespaceValue = selectedTenant + username;
}
_.assign(options, { namespace: [namespaceValue] });
Expand All @@ -129,7 +141,7 @@ export class SecuritySavedObjectsClientWrapper {
objects: Array<SavedObjectsBulkUpdateObject<T>>,
options?: SavedObjectsBulkUpdateOptions
): Promise<SavedObjectsBulkUpdateResponse<T>> => {
if (selectedTenant !== undefined && isPrivateTenant(selectedTenant)) {
if (selectedTenant !== undefined && isPrivateEnabled && isPrivateTenant(selectedTenant)) {
namespaceValue = selectedTenant + username;
}
_.assign(options, { namespace: [namespaceValue] });
Expand All @@ -141,7 +153,7 @@ export class SecuritySavedObjectsClientWrapper {
id: string,
options: SavedObjectsDeleteOptions = {}
) => {
if (selectedTenant !== undefined && isPrivateTenant(selectedTenant)) {
if (selectedTenant !== undefined && isPrivateEnabled && isPrivateTenant(selectedTenant)) {
namespaceValue = selectedTenant + username;
}
_.assign(options, { namespace: [namespaceValue] });
Expand All @@ -152,7 +164,7 @@ export class SecuritySavedObjectsClientWrapper {
objects: SavedObjectsCheckConflictsObject[] = [],
options: SavedObjectsBaseOptions = {}
): Promise<SavedObjectsCheckConflictsResponse> => {
if (selectedTenant !== undefined && isPrivateTenant(selectedTenant)) {
if (selectedTenant !== undefined && isPrivateEnabled && isPrivateTenant(selectedTenant)) {
namespaceValue = selectedTenant + username;
}
_.assign(options, { namespace: [namespaceValue] });
Expand All @@ -176,7 +188,3 @@ export class SecuritySavedObjectsClientWrapper {
};
};
}

function isPrivateTenant(selectedTenant: string | undefined) {
return selectedTenant === '__user__';
}