Skip to content

Commit 624034d

Browse files
committed
Add unit tests and rename env var to GRIST_OIDC_SP_HTTP_TIMEOUT
1 parent 246e9eb commit 624034d

File tree

2 files changed

+60
-11
lines changed

2 files changed

+60
-11
lines changed

app/server/lib/OIDCConfig.ts

+9-10
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@
4747
* A JSON object with extra client metadata to pass to openid-client. Optional.
4848
* Be aware that setting this object may override any other values passed to the openid client.
4949
* More info: https://github.com/panva/node-openid-client/tree/main/docs#new-clientmetadata-jwks-options
50-
* env GRIST_OIDC_HTTP_TIMEOUT
51-
* The timeout in milliseconds for HTTP requests to the IdP. Defaults to 3500.
50+
* env GRIST_OIDC_SP_HTTP_TIMEOUT
51+
* The timeout in milliseconds for HTTP requests to the IdP. The default value is set to 3500 by the
52+
* openid-client library. See: https://github.com/panva/node-openid-client/blob/main/docs/README.md#customizing-http-requests
5253
*
5354
* This version of OIDCConfig has been tested with Keycloak OIDC IdP following the instructions
5455
* at:
@@ -67,7 +68,8 @@
6768
import * as express from 'express';
6869
import { GristLoginSystem, GristServer } from './GristServer';
6970
import {
70-
Client, ClientMetadata, custom, Issuer, errors as OIDCError, TokenSet, UserinfoResponse
71+
Client, ClientMetadata, custom, HttpOptions as OIDCHttpOptions,
72+
Issuer, errors as OIDCError, TokenSet, UserinfoResponse
7173
} from 'openid-client';
7274
import { Sessions } from './Sessions';
7375
import log from 'app/server/lib/log';
@@ -139,10 +141,7 @@ export class OIDCConfig {
139141
censor: true,
140142
});
141143
const httpTimeout = section.flag('httpTimeout').readInt({
142-
envVar: 'GRIST_OIDC_HTTP_TIMEOUT',
143-
// Default value matching that of node-openid-client
144-
// See https://github.com/panva/node-openid-client/blob/main/docs/README.md#customizing-http-requests for more details.
145-
defaultValue: 3500,
144+
envVar: 'GRIST_OIDC_SP_HTTP_TIMEOUT',
146145
});
147146
this._namePropertyKey = section.flag('namePropertyKey').readString({
148147
envVar: 'GRIST_OIDC_SP_PROFILE_NAME_ATTR',
@@ -181,10 +180,10 @@ export class OIDCConfig {
181180

182181
this._redirectUrl = new URL(CALLBACK_URL, spHost).href;
183182
await this._initClient({ issuerUrl, clientId, clientSecret, extraMetadata });
184-
185-
custom.setHttpOptionsDefaults({
186-
timeout: httpTimeout,
183+
this._client[custom.http_options] = (): OIDCHttpOptions => ({
184+
...(httpTimeout !== undefined ? {timeout: httpTimeout} : {})
187185
});
186+
188187
if (this._client.issuer.metadata.end_session_endpoint === undefined &&
189188
!this._endSessionEndpoint && !this._skipEndSessionEndpoint) {
190189
throw new Error('The Identity provider does not propose end_session_endpoint. ' +

test/server/lib/OIDCConfig.ts

+51-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {Sessions} from "app/server/lib/Sessions";
55
import log from "app/server/lib/log";
66
import {assert} from "chai";
77
import Sinon from "sinon";
8-
import {Client, generators, errors as OIDCError} from "openid-client";
8+
import {Client, custom, CustomHttpOptionsProvider, generators, errors as OIDCError} from "openid-client";
99
import express from "express";
1010
import _ from "lodash";
1111
import {RequestWithLogin} from "app/server/lib/Authorizer";
@@ -38,6 +38,7 @@ class ClientStub {
3838
public callback = Sinon.stub().returns({});
3939
public userinfo = Sinon.stub().returns(undefined);
4040
public endSessionUrl = Sinon.stub().returns(undefined);
41+
public [custom.http_options]: CustomHttpOptionsProvider;
4142
public issuer: {
4243
metadata: {
4344
end_session_endpoint: string | undefined;
@@ -192,6 +193,55 @@ describe('OIDCConfig', () => {
192193
});
193194
});
194195
});
196+
197+
describe('GRIST_OIDC_SP_HTTP_TIMEOUT', function () {
198+
[
199+
{
200+
itMsg: 'when omitted should not override openid-client default value',
201+
expectedUserDefinedHttpOptions: {}
202+
},
203+
{
204+
itMsg: 'should reject when the provided value is not a number',
205+
env: {
206+
GRIST_OIDC_SP_HTTP_TIMEOUT: '__NOT_A_NUMBER__',
207+
},
208+
expectedErrorMsg: /__NOT_A_NUMBER__ does not look like a number/,
209+
},
210+
{
211+
itMsg: 'should override openid-client timeout accordingly to the provided value',
212+
env: {
213+
GRIST_OIDC_SP_HTTP_TIMEOUT: '10000',
214+
},
215+
shouldSetTimeout: true,
216+
expectedUserDefinedHttpOptions: {
217+
timeout: 10000
218+
}
219+
},
220+
{
221+
itMsg: 'should allow disabling the timeout by having its value set to 0',
222+
env: {
223+
GRIST_OIDC_SP_HTTP_TIMEOUT: '0',
224+
},
225+
expectedUserDefinedHttpOptions: {
226+
timeout: 0
227+
}
228+
}
229+
].forEach(ctx => {
230+
it(ctx.itMsg, async () => {
231+
setEnvVars();
232+
Object.assign(process.env, ctx.env);
233+
const clientStub = new ClientStub();
234+
const promise = OIDCConfigStubbed.buildWithStub(clientStub.asClient());
235+
if (ctx.expectedErrorMsg) {
236+
await assert.isRejected(promise, ctx.expectedErrorMsg);
237+
} else {
238+
await assert.isFulfilled(promise, 'initOIDC should have been fulfilled');
239+
const userDefinedOptions = (clientStub[custom.http_options] as Function)();
240+
assert.deepEqual(userDefinedOptions, ctx.expectedUserDefinedHttpOptions);
241+
}
242+
});
243+
});
244+
});
195245
});
196246

197247
describe('GRIST_OIDC_IDP_ENABLED_PROTECTIONS', () => {

0 commit comments

Comments
 (0)