Skip to content

Commit

Permalink
Add Proxy Auth to Multi Auth Options
Browse files Browse the repository at this point in the history
Signed-off-by: Stephen Crawford <[email protected]>
  • Loading branch information
stephen-crawford committed Jul 30, 2024
1 parent 0ed2cf2 commit ab5cad2
Show file tree
Hide file tree
Showing 5 changed files with 395 additions and 3 deletions.
5 changes: 4 additions & 1 deletion public/apps/login/login-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ export function LoginPage(props: LoginPageDeps) {
);
}

if (authOpts.length > 1) {
if (authOpts.length > 1 && (!authOpts.includes(AuthType.PROXY) || authOpts.length !== 2)) {

Check failure on line 240 in public/apps/login/login-page.tsx

View workflow job for this annotation

GitHub Actions / Run unit tests (ubuntu-latest)

Replace `authOpts.length·>·1·&&·(!authOpts.includes(AuthType.PROXY)·||·authOpts.length·!==·2)` with `⏎············authOpts.length·>·1·&&⏎············(!authOpts.includes(AuthType.PROXY)·||·authOpts.length·!==·2)⏎··········`

Check failure on line 240 in public/apps/login/login-page.tsx

View workflow job for this annotation

GitHub Actions / Run unit tests (windows-latest)

Replace `authOpts.length·>·1·&&·(!authOpts.includes(AuthType.PROXY)·||·authOpts.length·!==·2)` with `␍⏎············authOpts.length·>·1·&&␍⏎············(!authOpts.includes(AuthType.PROXY)·||·authOpts.length·!==·2)␍⏎··········`
formBody.push(<EuiSpacer size="xs" />);
formBody.push(<EuiHorizontalRule size="full" margin="xl" />);
formBody.push(<EuiSpacer size="xs" />);
Expand All @@ -258,6 +258,9 @@ export function LoginPage(props: LoginPageDeps) {
formBodyOp.push(renderLoginButton(AuthType.SAML, samlAuthLoginUrl, samlConfig));
break;
}
case AuthType.PROXY: {
break;
}
default: {
setloginFailed(true);
setloginError(
Expand Down
17 changes: 15 additions & 2 deletions server/auth/types/multiple/multi_auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { AuthType, LOGIN_PAGE_URI } from '../../../../common';
import { composeNextUrlQueryParam } from '../../../utils/next_url';
import { MultiAuthRoutes } from './routes';
import { SecuritySessionCookie } from '../../../session/security_cookie';
import { BasicAuthentication, OpenIdAuthentication, SamlAuthentication } from '../../types';
import { BasicAuthentication, OpenIdAuthentication, ProxyAuthentication, SamlAuthentication } from '../../types';

Check failure on line 32 in server/auth/types/multiple/multi_auth.ts

View workflow job for this annotation

GitHub Actions / Run unit tests (ubuntu-latest)

Replace `·BasicAuthentication,·OpenIdAuthentication,·ProxyAuthentication,·SamlAuthentication·` with `⏎··BasicAuthentication,⏎··OpenIdAuthentication,⏎··ProxyAuthentication,⏎··SamlAuthentication,⏎`

Check failure on line 32 in server/auth/types/multiple/multi_auth.ts

View workflow job for this annotation

GitHub Actions / Run unit tests (windows-latest)

Replace `·BasicAuthentication,·OpenIdAuthentication,·ProxyAuthentication,·SamlAuthentication·` with `␍⏎··BasicAuthentication,␍⏎··OpenIdAuthentication,␍⏎··ProxyAuthentication,␍⏎··SamlAuthentication,␍⏎`

export class MultipleAuthentication extends AuthenticationType {
private authTypes: string | string[];
Expand Down Expand Up @@ -93,6 +93,19 @@ export class MultipleAuthentication extends AuthenticationType {
this.authHandlers.set(AuthType.SAML, SamlAuth);
break;
}
case AuthType.PROXY: {
const ProxyAuth = new ProxyAuthentication(
this.config,
this.sessionStorageFactory,
this.router,
this.esClient,
this.coreSetup,
this.logger
);
await ProxyAuth.init();
this.authHandlers.set(AuthType.PROXY, ProxyAuth);
break;
}
default: {
throw new Error(`Unsupported authentication type: ${this.authTypes[i]}`);
}
Expand All @@ -115,7 +128,7 @@ export class MultipleAuthentication extends AuthenticationType {
async getAdditionalAuthHeader(
request: OpenSearchDashboardsRequest<unknown, unknown, unknown, any>
): Promise<any> {
// To Do: refactor this method to improve the effiency to get cookie, get cookie from input parameter
// To Do: refactor this method to improve the efficiency to get cookie, get cookie from input parameter
const cookie = await this.sessionStorageFactory.asScoped(request).get();
const reqAuthType = cookie?.authType?.toLowerCase();

Expand Down
4 changes: 4 additions & 0 deletions test/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ export const ADMIN_PASSWORD: string = process.env.ADMIN_PASSWORD || 'admin';
const ADMIN_USER_PASS: string = `${ADMIN_USER}:${ADMIN_PASSWORD}`;
export const ADMIN_CREDENTIALS: string = `Basic ${Buffer.from(ADMIN_USER_PASS).toString('base64')}`;
export const AUTHORIZATION_HEADER_NAME: string = 'Authorization';

export const PROXY_USER: string = 'x-proxy-user';
export const PROXY_ROLE: string = 'x-proxy-roles';
export const PROXY_ADMIN_ROLE: string = 'admin';
101 changes: 101 additions & 0 deletions test/jest_integration/proxy_auth.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* 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 * as osdTestServer from '../../../../src/core/test_helpers/osd_server';
import { Root } from '../../../../src/core/server/root';
import { resolve } from 'path';
import { describe, expect, it, beforeAll, afterAll } from '@jest/globals';
import {
OPENSEARCH_DASHBOARDS_SERVER_USER,
OPENSEARCH_DASHBOARDS_SERVER_PASSWORD,
ADMIN_USER,
PROXY_USER,
PROXY_ROLE,
PROXY_ADMIN_ROLE,
} from '../constant';

describe('start OpenSearch Dashboards server', () => {
let root: Root;

beforeAll(async () => {
root = osdTestServer.createRootWithSettings(
{
plugins: {
scanDirs: [resolve(__dirname, '../..')],
},
opensearch: {
hosts: ['https://localhost:9200'],
ignoreVersionMismatch: true,
ssl: { verificationMode: 'none' },
username: OPENSEARCH_DASHBOARDS_SERVER_USER,
password: OPENSEARCH_DASHBOARDS_SERVER_PASSWORD,
requestHeadersAllowlist: [
'securitytenant',
'Authorization',
'x-forwarded-for',
'x-proxy-user',
'x-proxy-roles',
],
},
opensearch_security: {
auth: {
type: 'proxy',
},
proxycache: {
user_header: 'x-proxy-user',
roles_header: 'x-proxy-roles',
},
},
},
{
// to make ignoreVersionMismatch setting work
// can be removed when we have corresponding ES version
dev: true,
}
);
});

afterAll(async () => {
// shutdown OpenSearchDashboards server
await root.shutdown();
});

it('can access home page with proxy header', async () => {
const response = await osdTestServer.request
.get(root, 'app/home#/')
.set(PROXY_USER, ADMIN_USER)
.set(PROXY_ROLE, PROXY_ADMIN_ROLE);
expect(response.status).toEqual(200);
});

it('cannot access home page without proxy header', async () => {
const response = await osdTestServer.request.get(root, 'app/home#/');
expect(response.status).toEqual(401);
});

it('cannot access home page with partial proxy header', async () => {
const response = await osdTestServer.request
.get(root, 'app/home#/')
.set(PROXY_USER, ADMIN_USER);
expect(response.status).toEqual(401);
});

it('cannot access home page with partial proxy header2', async () => {
const response = await osdTestServer.request
.get(root, 'app/home#/')
.set(PROXY_ROLE, PROXY_ADMIN_ROLE);
expect(response.status).toEqual(401);
});
});
Loading

0 comments on commit ab5cad2

Please sign in to comment.