Merge pull request #29198 from goququ/custom-oidc-timeout
Custom OIDC timeout
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
---
|
||||
'@backstage/plugin-auth-backend-module-oidc-provider': patch
|
||||
---
|
||||
|
||||
Added custom timeout setting for oidc provider
|
||||
|
||||
Here is an example of how to use a custom timeout with the configuration:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
oidc:
|
||||
production:
|
||||
clientId: ${AUTH_GOOGLE_CLIENT_ID}
|
||||
clientSecret: ${AUTH_GOOGLE_CLIENT_SECRET}
|
||||
timeout:
|
||||
seconds: 30
|
||||
```
|
||||
+1
-1
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
|
||||
export interface Config {
|
||||
@@ -33,6 +32,7 @@ export interface Config {
|
||||
tokenSignedResponseAlg?: string;
|
||||
additionalScopes?: string | string[];
|
||||
prompt?: string;
|
||||
timeout?: HumanDuration;
|
||||
signIn?: {
|
||||
resolvers: Array<
|
||||
| {
|
||||
|
||||
@@ -35,8 +35,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
"@backstage/config": "workspace:^",
|
||||
"@backstage/plugin-auth-backend": "workspace:^",
|
||||
"@backstage/plugin-auth-node": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"express": "^4.18.2",
|
||||
"openid-client": "^5.5.0",
|
||||
"passport": "^0.7.0"
|
||||
|
||||
@@ -28,6 +28,7 @@ import { ConfigReader } from '@backstage/config';
|
||||
import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose';
|
||||
import { rest } from 'msw';
|
||||
import express from 'express';
|
||||
import { custom } from 'openid-client';
|
||||
|
||||
describe('oidcAuthenticator', () => {
|
||||
let implementation: any;
|
||||
@@ -169,6 +170,77 @@ describe('oidcAuthenticator', () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('timeout configuration', () => {
|
||||
const TEST_URL = new URL('https://test.com');
|
||||
|
||||
it('should use default timeout when no timeout is configured', async () => {
|
||||
const { promise } = oidcAuthenticator.initialize({
|
||||
callbackUrl: 'https://backstage.test/callback',
|
||||
config: new ConfigReader({
|
||||
metadataUrl: 'https://oidc.test/.well-known/openid-configuration',
|
||||
clientId: 'clientId',
|
||||
clientSecret: 'clientSecret',
|
||||
}),
|
||||
});
|
||||
const { client } = await promise;
|
||||
|
||||
const timeout = client[custom.http_options](TEST_URL, {}).timeout;
|
||||
|
||||
// Check if the HTTP timeout is set to the default value
|
||||
expect(timeout).toBeDefined();
|
||||
expect(timeout).toBe(10000);
|
||||
});
|
||||
|
||||
it('should use configured timeout when provided in the config', async () => {
|
||||
const { promise } = oidcAuthenticator.initialize({
|
||||
callbackUrl: 'https://backstage.test/callback',
|
||||
config: new ConfigReader({
|
||||
metadataUrl: 'https://oidc.test/.well-known/openid-configuration',
|
||||
clientId: 'clientId',
|
||||
clientSecret: 'clientSecret',
|
||||
timeout: {
|
||||
seconds: 30,
|
||||
},
|
||||
}),
|
||||
});
|
||||
const { client } = await promise;
|
||||
|
||||
const timeout = client[custom.http_options](TEST_URL, {}).timeout;
|
||||
|
||||
// Check if the HTTP timeout is set to the configured value (30 seconds)
|
||||
expect(timeout).toBeDefined();
|
||||
expect(timeout).toBe(30000);
|
||||
});
|
||||
|
||||
it('should handle invalid timeout configuration gracefully', async () => {
|
||||
expect(() => {
|
||||
oidcAuthenticator.initialize({
|
||||
callbackUrl: 'https://backstage.test/callback',
|
||||
config: new ConfigReader({
|
||||
metadataUrl: 'https://oidc.test/.well-known/openid-configuration',
|
||||
clientId: 'clientId',
|
||||
clientSecret: 'clientSecret',
|
||||
timeout: 123, // Invalid: should be a duration object
|
||||
}),
|
||||
});
|
||||
}).toThrow();
|
||||
|
||||
expect(() => {
|
||||
oidcAuthenticator.initialize({
|
||||
callbackUrl: 'https://backstage.test/callback',
|
||||
config: new ConfigReader({
|
||||
metadataUrl: 'https://oidc.test/.well-known/openid-configuration',
|
||||
clientId: 'clientId',
|
||||
clientSecret: 'clientSecret',
|
||||
timeout: {
|
||||
invalid: 'value',
|
||||
},
|
||||
}),
|
||||
});
|
||||
}).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#start', () => {
|
||||
let fakeSession: Record<string, any>;
|
||||
let startRequest: OAuthAuthenticatorStartInput;
|
||||
|
||||
@@ -32,14 +32,18 @@ import {
|
||||
PassportOAuthAuthenticatorHelper,
|
||||
PassportOAuthPrivateInfo,
|
||||
} from '@backstage/plugin-auth-node';
|
||||
import { durationToMilliseconds } from '@backstage/types';
|
||||
import { readDurationFromConfig } from '@backstage/config';
|
||||
|
||||
const HTTP_OPTION_TIMEOUT = 10000;
|
||||
const httpOptionsProvider: CustomHttpOptionsProvider = (_url, options) => {
|
||||
return {
|
||||
...options,
|
||||
timeout: HTTP_OPTION_TIMEOUT,
|
||||
const createHttpOptionsProvider =
|
||||
({ timeout }: { timeout?: number }): CustomHttpOptionsProvider =>
|
||||
(_url, options) => {
|
||||
return {
|
||||
...options,
|
||||
timeout: timeout ?? HTTP_OPTION_TIMEOUT,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* authentication result for the OIDC which includes the token set and user
|
||||
@@ -85,6 +89,15 @@ export const oidcAuthenticator = createOAuthAuthenticator({
|
||||
);
|
||||
}
|
||||
|
||||
const timeoutMilliseconds = config.has('timeout')
|
||||
? durationToMilliseconds(
|
||||
readDurationFromConfig(config, { key: 'timeout' }),
|
||||
)
|
||||
: undefined;
|
||||
const httpOptionsProvider = createHttpOptionsProvider({
|
||||
timeout: timeoutMilliseconds,
|
||||
});
|
||||
|
||||
Issuer[custom.http_options] = httpOptionsProvider;
|
||||
const promise = Issuer.discover(metadataUrl).then(issuer => {
|
||||
issuer[custom.http_options] = httpOptionsProvider;
|
||||
|
||||
Reference in New Issue
Block a user