Skip to content

Commit 5e6225f

Browse files
opensearch-trigger-bot[bot]derek-hoDarshitChanpura
authored
Fix cookie expiry issues from IDP/JWT auth methods, disables keepalive for JWT/IDP (#1773) (#1806)
Signed-off-by: Derek Ho <dxho@amazon.com> (cherry picked from commit 0f1efc2) Co-authored-by: Derek Ho <dxho@amazon.com> Co-authored-by: Darshit Chanpura <35282393+DarshitChanpura@users.noreply.github.com>
1 parent 3536d7d commit 5e6225f

16 files changed

+617
-44
lines changed

server/auth/types/authentication_type.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616
import { SecurityPluginConfigType } from '../..';
1717
import { AuthenticationType } from './authentication_type';
1818
import { httpServerMock } from '../../../../../src/core/server/mocks';
19+
import { OpenSearchDashboardsRequest } from '../../../../../src/core/server';
1920

2021
class DummyAuthType extends AuthenticationType {
22+
authNotRequired(request: OpenSearchDashboardsRequest): boolean {
23+
return false;
24+
}
2125
buildAuthHeaderFromCookie() {}
2226
getAdditionalAuthHeader() {}
2327
handleUnauthedRequest() {}

server/auth/types/authentication_type.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export abstract class AuthenticationType implements IAuthenticationType {
160160

161161
// extend session expiration time
162162
if (this.config.session.keepalive) {
163-
cookie!.expiryTime = Date.now() + this.config.session.ttl;
163+
cookie!.expiryTime = this.getKeepAliveExpiry(cookie!, request);
164164
this.sessionStorageFactory.asScoped(request).set(cookie!);
165165
}
166166
// cookie is valid
@@ -266,6 +266,13 @@ export abstract class AuthenticationType implements IAuthenticationType {
266266
});
267267
}
268268

269+
public getKeepAliveExpiry(
270+
cookie: SecuritySessionCookie,
271+
request: OpenSearchDashboardsRequest
272+
): number {
273+
return Date.now() + this.config.session.ttl;
274+
}
275+
269276
isPageRequest(request: OpenSearchDashboardsRequest) {
270277
const path = request.url.pathname || '/';
271278
return path.startsWith('/app/') || path === '/' || path.startsWith('/goto/');
@@ -286,5 +293,10 @@ export abstract class AuthenticationType implements IAuthenticationType {
286293
response: LifecycleResponseFactory,
287294
toolkit: AuthToolkit
288295
): IOpenSearchDashboardsResponse | AuthResult;
296+
public abstract requestIncludesAuthInfo(request: OpenSearchDashboardsRequest): boolean;
297+
public abstract buildAuthHeaderFromCookie(
298+
cookie: SecuritySessionCookie,
299+
request: OpenSearchDashboardsRequest
300+
): any;
289301
public abstract init(): Promise<void>;
290302
}
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
import { httpServerMock } from '../../../../../../src/core/server/http/http_server.mocks';
17+
18+
import { SecurityPluginConfigType } from '../../../index';
19+
import { SecuritySessionCookie } from '../../../session/security_cookie';
20+
import {
21+
IRouter,
22+
CoreSetup,
23+
ILegacyClusterClient,
24+
Logger,
25+
SessionStorageFactory,
26+
} from '../../../../../../src/core/server';
27+
import { BasicAuthentication } from './basic_auth';
28+
29+
describe('Basic auth tests', () => {
30+
let router: IRouter;
31+
let core: CoreSetup;
32+
let esClient: ILegacyClusterClient;
33+
let sessionStorageFactory: SessionStorageFactory<SecuritySessionCookie>;
34+
let logger: Logger;
35+
36+
const config = {
37+
session: {
38+
ttl: 1000,
39+
},
40+
} as SecurityPluginConfigType;
41+
42+
test('getKeepAliveExpiry', () => {
43+
const realDateNow = Date.now.bind(global.Date);
44+
const dateNowStub = jest.fn(() => 0);
45+
global.Date.now = dateNowStub;
46+
const basicAuthentication = new BasicAuthentication(
47+
config,
48+
sessionStorageFactory,
49+
router,
50+
esClient,
51+
core,
52+
logger
53+
);
54+
55+
const cookie: SecuritySessionCookie = {
56+
credentials: {
57+
authHeaderValueExtra: true,
58+
},
59+
expiryTime: 0,
60+
};
61+
62+
const request = httpServerMock.createOpenSearchDashboardsRequest({
63+
path: '/internal/v1',
64+
});
65+
66+
expect(basicAuthentication.getKeepAliveExpiry(cookie, request)).toBe(1000);
67+
global.Date.now = realDateNow;
68+
});
69+
});

server/auth/types/basic/basic_auth.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,10 @@ export class BasicAuthentication extends AuthenticationType {
133133
}
134134
}
135135

136-
buildAuthHeaderFromCookie(cookie: SecuritySessionCookie): any {
136+
buildAuthHeaderFromCookie(
137+
cookie: SecuritySessionCookie,
138+
request: OpenSearchDashboardsRequest
139+
): any {
137140
if (this.config.auth.anonymous_auth_enabled && cookie.isAnonymousAuth) {
138141
return {};
139142
}

server/auth/types/jwt/jwt_auth.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
getExtraAuthStorageValue,
3636
setExtraAuthStorage,
3737
} from '../../../session/cookie_splitter';
38+
import { getExpirationDate } from './jwt_helper';
3839

3940
export const JWT_DEFAULT_EXTRA_STORAGE_OPTIONS: ExtraAuthStorageOptions = {
4041
cookiePrefix: 'security_authentication_jwt',
@@ -154,13 +155,17 @@ export class JwtAuthentication extends AuthenticationType {
154155
this.getBearerToken(request) || '',
155156
this.getExtraAuthStorageOptions()
156157
);
158+
157159
return {
158160
username: authInfo.user_name,
159161
credentials: {
160162
authHeaderValueExtra: true,
161163
},
162164
authType: this.type,
163-
expiryTime: Date.now() + this.config.session.ttl,
165+
expiryTime: getExpirationDate(
166+
this.getBearerToken(request),
167+
Date.now() + this.config.session.ttl
168+
),
164169
};
165170
}
166171

@@ -175,6 +180,13 @@ export class JwtAuthentication extends AuthenticationType {
175180
);
176181
}
177182

183+
getKeepAliveExpiry(cookie: SecuritySessionCookie, request: OpenSearchDashboardsRequest): number {
184+
return getExpirationDate(
185+
this.buildAuthHeaderFromCookie(cookie, request)[this.authHeaderName],
186+
Date.now() + this.config.session.ttl
187+
);
188+
}
189+
178190
handleUnauthedRequest(
179191
request: OpenSearchDashboardsRequest,
180192
response: LifecycleResponseFactory,

0 commit comments

Comments
 (0)