Skip to content

Commit

Permalink
[Backport 1.3] Add the tenant into the short URL once the short URL i…
Browse files Browse the repository at this point in the history
…s resolved (#1462) (#1516)

* Add the tenant into the short URL once the short URL is resolved (#1462)

* More information added

Signed-off-by: leanneeliatra <[email protected]>

* More information added

Signed-off-by: leanneeliatra <[email protected]>

* fixed linting errors

Signed-off-by: leanneeliatra <[email protected]>

* Removing Prerequisite Checks Workflow (#1456)

Signed-off-by: Ryan Liang <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

* Removing Prerequisite Checks Workflow (#1456)

Signed-off-by: Ryan Liang <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

* Removing Prerequisite Checks Workflow (#1456)

Signed-off-by: Ryan Liang <[email protected]>
Signed-off-by: Ryan Liang <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

* Extracting function to tenant_resolver and adding more appropriate comments.

Signed-off-by: leanneeliatra <[email protected]>

* lint errors fixed

Signed-off-by: leanneeliatra <[email protected]>

* Use version from package.json for integration tests (#1463)

* Use version from package.json for integration tests

Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

* Adds 2.8 release notes (#1464)

Signed-off-by: Darshit Chanpura <[email protected]>
Co-authored-by: Ryan Liang <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

* Cleaning up comments

Signed-off-by: Leanne Lacey-Byrne <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

* linting issues resolved

Signed-off-by: leanneeliatra <[email protected]>

* Removing Prerequisite Checks Workflow (#1456)

Signed-off-by: Ryan Liang <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

* Removing Prerequisite Checks Workflow (#1456)

Signed-off-by: Ryan Liang <[email protected]>
Signed-off-by: Ryan Liang <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

* Update server/multitenancy/tenant_resolver.ts

Co-authored-by: Darshit Chanpura <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

* comments addressed & linting amended

Signed-off-by: leanneeliatra <[email protected]>

* integration test fix following rebase

Signed-off-by: leanneeliatra <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>

---------

Signed-off-by: leanneeliatra <[email protected]>
Signed-off-by: Ryan Liang <[email protected]>
Signed-off-by: Ryan Liang <[email protected]>
Signed-off-by: Craig Perkins <[email protected]>
Signed-off-by: Darshit Chanpura <[email protected]>
Signed-off-by: Leanne Lacey-Byrne <[email protected]>
Signed-off-by: leanneeliatra <[email protected]>
Co-authored-by: Ryan Liang <[email protected]>
Co-authored-by: Craig Perkins <[email protected]>
Co-authored-by: Darshit Chanpura <[email protected]>
(cherry picked from commit e9f9576)

* Linter fix

Signed-off-by: Darshit Chanpura <[email protected]>

---------

Signed-off-by: Darshit Chanpura <[email protected]>
Co-authored-by: leanneeliatra <[email protected]>
  • Loading branch information
DarshitChanpura and leanneeliatra authored Jul 20, 2023
1 parent 390fd60 commit cac8e3f
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 4 deletions.
11 changes: 11 additions & 0 deletions common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ export const ERROR_MISSING_ROLE_PATH = '/missing-role';

export const MAX_INTEGER = 2147483647;

export const GLOBAL_TENANT_SYMBOL = '';
export const PRIVATE_TENANT_SYMBOL = '__user__';
export const DEFAULT_TENANT = 'default';
export const GLOBAL_TENANT_RENDERING_TEXT = 'Global';
export const PRIVATE_TENANT_RENDERING_TEXT = 'Private';
export const globalTenantName = 'global_tenant';

export enum AuthType {
BASIC = 'basicauth',
OPEN_ID = 'openid',
Expand All @@ -48,3 +55,7 @@ export function isValidResourceName(resourceName: string): boolean {
// see: https://javascript.info/regexp-unicode
return !/[\p{C}%]/u.test(resourceName) && resourceName.length > 0;
}

export function isGlobalTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant === GLOBAL_TENANT_SYMBOL;
}
88 changes: 88 additions & 0 deletions server/multitenancy/tenant_resolver.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright OpenSearch Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import { httpServerMock } from '../../../../src/core/server/mocks';
import { OpenSearchDashboardsRequest } from '../../../../src/core/server';
import { addTenantParameterToResolvedShortLink } from './tenant_resolver';
import { Request, ResponseObject } from '@hapi/hapi';

describe('Preserve the tenant parameter in short urls', () => {
it(`adds the tenant as a query parameter for goto short links`, async () => {
const resolvedUrl = '/url/resolved';
const rawRequest = httpServerMock.createRawRequest({
url: {
pathname: '/goto/123',
},
headers: {
securitytenant: 'dummy_tenant',
},
response: {
headers: {
location: resolvedUrl,
},
},
}) as Request;

const osRequest = OpenSearchDashboardsRequest.from(rawRequest);
addTenantParameterToResolvedShortLink(osRequest);

expect((rawRequest.response as ResponseObject).headers.location).toEqual(
resolvedUrl + '?security_tenant=dummy_tenant'
);
});

it(`ignores links not starting with /goto`, async () => {
const resolvedUrl = '/url/resolved';
const rawRequest = httpServerMock.createRawRequest({
url: {
pathname: '/dontgoto/123',
},
headers: {
securitytenant: 'dummy_tenant',
},
response: {
headers: {
location: resolvedUrl,
},
},
}) as Request;

const osRequest = OpenSearchDashboardsRequest.from(rawRequest);
addTenantParameterToResolvedShortLink(osRequest);

expect((rawRequest.response as ResponseObject).headers.location).toEqual(resolvedUrl);
});

it(`checks that a redirect location is present before applying the query parameter`, async () => {
const rawRequest = httpServerMock.createRawRequest({
url: {
pathname: '/goto/123',
},
headers: {
securitytenant: 'dummy_tenant',
},
response: {
headers: {
someotherheader: 'abc',
},
},
}) as Request;

const osRequest = OpenSearchDashboardsRequest.from(rawRequest);
addTenantParameterToResolvedShortLink(osRequest);

expect((rawRequest.response as ResponseObject).headers.location).toBeFalsy();
});
});
36 changes: 32 additions & 4 deletions server/multitenancy/tenant_resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
*/

import { isEmpty, findKey, cloneDeep } from 'lodash';
import { OpenSearchDashboardsRequest } from '../../../../src/core/server';
import { OpenSearchDashboardsRequest } from 'opensearch-dashboards/server';
import { ResponseObject } from '@hapi/hapi';
import { SecuritySessionCookie } from '../session/security_cookie';
import { GLOBAL_TENANT_SYMBOL, PRIVATE_TENANT_SYMBOL, globalTenantName } from '../../common';
import { modifyUrl } from '../../../../packages/osd-std';
import { ensureRawRequest } from '../../../../src/core/server/http/router';
import { GOTO_PREFIX } from '../../../../src/plugins/share/common/short_url_routes';
import { SecurityPluginConfigType } from '..';

const PRIVATE_TENANT_SYMBOL: string = '__user__';
const GLOBAL_TENANT_SYMBOL: string = '';

export const PRIVATE_TENANTS: string[] = [PRIVATE_TENANT_SYMBOL, 'private'];
export const GLOBAL_TENANTS: string[] = ['global', GLOBAL_TENANT_SYMBOL];
/**
Expand Down Expand Up @@ -170,3 +172,29 @@ function resolve(
export function isValidTenant(tenant: string | undefined | null): boolean {
return tenant !== undefined && tenant !== null;
}

/**
* If multitenancy is enabled & the URL entered starts with /goto,
* We will modify the rawResponse to add a new parameter to the URL, the security_tenant (or value for tenant when in multitenancy)
* With the security_tenant added, the resolved short URL now contains the security_tenant information (so the short URL retains the tenant information).
**/

export function addTenantParameterToResolvedShortLink(request: OpenSearchDashboardsRequest) {
if (request.url.pathname.startsWith(`${GOTO_PREFIX}/`)) {
const rawRequest = ensureRawRequest(request);
const rawResponse = rawRequest.response as ResponseObject;

// Make sure the request really should redirect
if (rawResponse.headers.location) {
const modifiedUrl = modifyUrl(rawResponse.headers.location as string, (parts) => {
if (parts.query.security_tenant === undefined) {
parts.query.security_tenant = request.headers.securitytenant as string;
}
// Mutating the headers toolkit.next({headers: ...}) logs a warning about headers being overwritten
});
rawResponse.headers.location = modifiedUrl;
}
}

return request;
}
10 changes: 10 additions & 0 deletions server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import { first } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { ResponseObject } from '@hapi/hapi';
import {
PluginInitializerContext,
CoreSetup,
Expand Down Expand Up @@ -43,6 +44,7 @@ import { getAuthenticationHandler } from './auth/auth_handler_factory';
import { setupMultitenantRoutes } from './multitenancy/routes';
import { defineAuthTypeRoutes } from './routes/auth_type_routes';
import { createMigrationOpenSearchClient } from '../../../src/core/server/saved_objects/migrations/core';
import { addTenantParameterToResolvedShortLink } from './multitenancy/tenant_resolver';

export interface SecurityPluginRequestContext {
logger: Logger;
Expand Down Expand Up @@ -118,6 +120,14 @@ export class SecurityPlugin implements Plugin<SecurityPluginSetup, SecurityPlugi
);
core.http.registerAuth(auth.authHandler);

/* Here we check if multitenancy is enabled to ensure if it is, we insert the tenant info (security_tenant) into the resolved, short URL so the page can correctly load with the right tenant information [Fix for issue 1203](https://github.com/opensearch-project/security-dashboards-plugin/issues/1203 */
if (config.multitenancy?.enabled) {
core.http.registerOnPreResponse((request, preResponse, toolkit) => {
addTenantParameterToResolvedShortLink(request);
return toolkit.next();
});
}

// Register server side APIs
defineRoutes(router);
defineAuthTypeRoutes(router, config);
Expand Down

0 comments on commit cac8e3f

Please sign in to comment.