Skip to content

Commit

Permalink
Merge branch 'main' into release-ftr-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
derek-ho authored Jun 13, 2024
2 parents 2d68089 + 208089e commit 0163999
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 88 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
"resolutions": {
"selenium-webdriver": "4.10.0",
"glob-parent": "^5.1.2",
"debug": "^4.3.4"
"debug": "^4.3.4",
"ejs": "^3.1.10",
"express": "^4.19.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ export function AuditLogging(props: AuditLoggingProps) {
/>
<EuiPageHeader>
<EuiTitle size="l">
<h1>Audit Logging</h1>
<h3>Audit logging</h3>
</EuiTitle>
</EuiPageHeader>
<EuiSpacer />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,9 @@ exports[`Audit logs render when AuditLoggingSettings.enabled is true 1`] = `
<EuiTitle
size="l"
>
<h1>
Audit Logging
</h1>
<h3>
Audit logging
</h3>
</EuiTitle>
</EuiPageHeader>
<EuiSpacer />
Expand Down Expand Up @@ -670,9 +670,9 @@ exports[`Audit logs should load access error component 1`] = `
<EuiTitle
size="l"
>
<h1>
Audit Logging
</h1>
<h3>
Audit logging
</h3>
</EuiTitle>
</EuiPageHeader>
<EuiSpacer />
Expand Down
2 changes: 1 addition & 1 deletion public/apps/configuration/panels/user-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export function UserList(props: AppDependencies) {
href={buildHashUrl(ResourceType.users, Action.create)}
data-test-subj="create-user"
>
Create user account
Create internal user
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
3 changes: 1 addition & 2 deletions public/apps/login/login-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import React, { useState } from 'react';
import {
EuiText,
EuiFieldText,
EuiIcon,
EuiSpacer,
EuiButton,
EuiImage,
Expand Down Expand Up @@ -194,7 +193,7 @@ export function LoginPage(props: LoginPageDeps) {
data-test-subj="user-name"
aria-label="username_input"
placeholder="Username"
prepend={<EuiIcon type="user" />}
icon="user"
onChange={(e) => setUsername(e.target.value)}
value={username}
isInvalid={usernameValidationFailed}
Expand Down
48 changes: 8 additions & 40 deletions public/apps/login/test/__snapshots__/login-page.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,10 @@ exports[`Login page renders renders with config value for multiauth 1`] = `
<EuiFieldText
aria-label="username_input"
data-test-subj="user-name"
icon="user"
isInvalid={false}
onChange={[Function]}
placeholder="Username"
prepend={
<EuiIcon
type="user"
/>
}
value=""
/>
</EuiFormRow>
Expand Down Expand Up @@ -195,14 +191,10 @@ exports[`Login page renders renders with config value for multiauth with anonymo
<EuiFieldText
aria-label="username_input"
data-test-subj="user-name"
icon="user"
isInvalid={false}
onChange={[Function]}
placeholder="Username"
prepend={
<EuiIcon
type="user"
/>
}
value=""
/>
</EuiFormRow>
Expand Down Expand Up @@ -364,14 +356,10 @@ exports[`Login page renders renders with config value with anonymous auth enable
<EuiFieldText
aria-label="username_input"
data-test-subj="user-name"
icon="user"
isInvalid={false}
onChange={[Function]}
placeholder="Username"
prepend={
<EuiIcon
type="user"
/>
}
value=""
/>
</EuiFormRow>
Expand Down Expand Up @@ -483,14 +471,10 @@ exports[`Login page renders renders with config value with anonymous auth enable
<EuiFieldText
aria-label="username_input"
data-test-subj="user-name"
icon="user"
isInvalid={false}
onChange={[Function]}
placeholder="Username"
prepend={
<EuiIcon
type="user"
/>
}
value=""
/>
</EuiFormRow>
Expand Down Expand Up @@ -602,14 +586,10 @@ exports[`Login page renders renders with config value: string 1`] = `
<EuiFieldText
aria-label="username_input"
data-test-subj="user-name"
icon="user"
isInvalid={false}
onChange={[Function]}
placeholder="Username"
prepend={
<EuiIcon
type="user"
/>
}
value=""
/>
</EuiFormRow>
Expand Down Expand Up @@ -703,14 +683,10 @@ exports[`Login page renders renders with config value: string array 1`] = `
<EuiFieldText
aria-label="username_input"
data-test-subj="user-name"
icon="user"
isInvalid={false}
onChange={[Function]}
placeholder="Username"
prepend={
<EuiIcon
type="user"
/>
}
value=""
/>
</EuiFormRow>
Expand Down Expand Up @@ -804,14 +780,10 @@ exports[`Login page renders renders with default value: string 1`] = `
<EuiFieldText
aria-label="username_input"
data-test-subj="user-name"
icon="user"
isInvalid={false}
onChange={[Function]}
placeholder="Username"
prepend={
<EuiIcon
type="user"
/>
}
value=""
/>
</EuiFormRow>
Expand Down Expand Up @@ -905,14 +877,10 @@ exports[`Login page renders renders with default value: string array 1`] = `
<EuiFieldText
aria-label="username_input"
data-test-subj="user-name"
icon="user"
isInvalid={false}
onChange={[Function]}
placeholder="Username"
prepend={
<EuiIcon
type="user"
/>
}
value=""
/>
</EuiFormRow>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Version 2.15.0 Release Notes

Compatible with OpenSearch and OpenSearch Dashboards version 2.15.0

### Enhancements
* Remove tenant tab when disabled via yaml ([#1960](https://github.com/opensearch-project/security-dashboards-plugin/pull/1960))
* Always show security screen and shows error page when trying to access forbidden data-source ([#1964](https://github.com/opensearch-project/security-dashboards-plugin/pull/1964))
* Provide ability to view password ([#1980](https://github.com/opensearch-project/security-dashboards-plugin/pull/1980))
* Make login screen input feels consistent ([#1993](https://github.com/opensearch-project/security-dashboards-plugin/pull/1993))

### Bug Fixes
* Fix bugs where pages were stuck in error state ([#1944](https://github.com/opensearch-project/security-dashboards-plugin/pull/1944))
* Fix issue when using OpenID Authentication with serverBasePath ([#1899](https://github.com/opensearch-project/security-dashboards-plugin/pull/1899))
* Fixes issue with expiryTime of OIDC cookie that causes refreshToken workflow to be skipped ([#1990](https://github.com/opensearch-project/security-dashboards-plugin/pull/1990))

### Maintenance
* Updating security reachout email ([#1948](https://github.com/opensearch-project/security-dashboards-plugin/pull/1948))
* Bump ejs and express versions to address CVEs ([#1988](https://github.com/opensearch-project/security-dashboards-plugin/pull/1988))
77 changes: 73 additions & 4 deletions server/auth/types/openid/openid_auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ interface Logger {
fatal(message: string): void;
}

const mockClient = { post: jest.fn() };

jest.mock('@hapi/wreck', () => ({
defaults: jest.fn(() => mockClient),
}));

describe('test OpenId authHeaderValue', () => {
let router: IRouter;
let core: CoreSetup;
Expand Down Expand Up @@ -208,7 +214,7 @@ describe('test OpenId authHeaderValue', () => {
expect(wreckHttpsOptions.passphrase).toBeUndefined();
});

test('Ensure expiryTime is being used to test validity of cookie', async () => {
test('Ensure accessToken expiryTime is being used to test validity of cookie', async () => {
const realDateNow = Date.now.bind(global.Date);
const dateNowStub = jest.fn(() => 0);
global.Date.now = dateNowStub;
Expand All @@ -229,22 +235,84 @@ describe('test OpenId authHeaderValue', () => {
const testCookie: SecuritySessionCookie = {
credentials: {
authHeaderValue: 'Bearer eyToken',
expiry_time: -1,
expiryTime: 200,
},
expiryTime: 2000,
expiryTime: 10000,
username: 'admin',
authType: 'openid',
};

// Credentials are valid because 0 < 200
expect(await openIdAuthentication.isValidCookie(testCookie, {})).toBe(true);
global.Date.now = realDateNow;
});

test('Ensure refreshToken workflow is called if current time is after access token expiry, but before session expiry', async () => {
const realDateNow = Date.now.bind(global.Date);
const dateNowStub = jest.fn(() => 300);
global.Date.now = dateNowStub;
const oidcConfig: unknown = {
openid: {
header: 'authorization',
scope: [],
extra_storage: {
cookie_prefix: 'testcookie',
additional_cookies: 0,
},
},
};

const openIdAuthentication = new OpenIdAuthentication(
oidcConfig as SecurityPluginConfigType,
sessionStorageFactory,
router,
esClient,
core,
logger
);
const testCookie: SecuritySessionCookie = {
credentials: {
authHeaderValue: 'Bearer eyToken',
expiryTime: 200,
refresh_token: 'refreshToken',
},
expiryTime: 10000,
username: 'admin',
authType: 'openid',
};

const mockRequestPayload = JSON.stringify({
grant_type: 'refresh_token',
client_id: 'clientId',
client_secret: 'clientSecret',
refresh_token: 'refreshToken',
});
const mockResponsePayload = JSON.stringify({
id_token: '.eyJleHAiOiIwLjUifQ.', // Translates to {"exp":"0.5"}
access_token: 'accessToken',
refresh_token: 'refreshToken',
});
mockClient.post.mockResolvedValue({
res: { statusCode: 200 },
payload: mockResponsePayload,
});

expect(await openIdAuthentication.isValidCookie(testCookie, {})).toBe(true);
expect(mockClient.post).toBeCalledTimes(1);
global.Date.now = realDateNow;
});

test('getKeepAliveExpiry', () => {
const realDateNow = Date.now.bind(global.Date);
const dateNowStub = jest.fn(() => 300);
global.Date.now = dateNowStub;
const oidcConfig: unknown = {
openid: {
scope: [],
},
session: {
ttl: 3600,
},
};

const openIdAuthentication = new OpenIdAuthentication(
Expand All @@ -262,6 +330,7 @@ describe('test OpenId authHeaderValue', () => {
expiryTime: 1000,
};

expect(openIdAuthentication.getKeepAliveExpiry(testCookie, {})).toBe(1000);
expect(openIdAuthentication.getKeepAliveExpiry(testCookie, {})).toBe(3900);
global.Date.now = realDateNow;
});
});
7 changes: 3 additions & 4 deletions server/auth/types/openid/openid_auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,11 @@ export class OpenIdAuthentication extends AuthenticationType {
};
}

// OIDC expiry time is set by the IDP and refreshed via refreshTokens
getKeepAliveExpiry(
cookie: SecuritySessionCookie,
request: OpenSearchDashboardsRequest<unknown, unknown, unknown, any>
): number {
return cookie.expiryTime!;
return Date.now() + this.config.session.ttl;
}

// TODO: Add token expiration check here
Expand All @@ -272,7 +271,7 @@ export class OpenIdAuthentication extends AuthenticationType {
return false;
}

if (cookie.expiryTime > Date.now()) {
if (cookie.credentials.expiryTime > Date.now()) {
return true;
}

Expand All @@ -296,8 +295,8 @@ export class OpenIdAuthentication extends AuthenticationType {
cookie.credentials = {
authHeaderValueExtra: true,
refresh_token: refreshTokenResponse.refreshToken,
expiryTime: getExpirationDate(refreshTokenResponse),
};
cookie.expiryTime = getExpirationDate(refreshTokenResponse);

setExtraAuthStorage(
request,
Expand Down
3 changes: 2 additions & 1 deletion server/auth/types/openid/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,10 @@ export class OpenIdAuthRoutes {
username: user.username,
credentials: {
authHeaderValueExtra: true,
expiryTime: getExpirationDate(tokenResponse),
},
authType: AuthType.OPEN_ID,
expiryTime: getExpirationDate(tokenResponse),
expiryTime: Date.now() + this.config.session.ttl,
};
if (this.config.openid?.refresh_tokens && tokenResponse.refreshToken) {
Object.assign(sessionStorage.credentials, {
Expand Down
Loading

0 comments on commit 0163999

Please sign in to comment.