From bd7ed219d7c1aac97a8b18d48c09ba925fae4854 Mon Sep 17 00:00:00 2001 From: Basit <1305718+mabaasit@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:06:06 +0200 Subject: [PATCH] feat!(devtools-connect): update oidc MONGOSH-1790 (#347) oidc update --- package-lock.json | 58 ++++--------------- packages/devtools-connect/package.json | 4 +- .../src/ipc-rpc-state-share.spec.ts | 52 ++++++++--------- .../src/ipc-rpc-state-share.ts | 40 +++++-------- 4 files changed, 49 insertions(+), 105 deletions(-) diff --git a/package-lock.json b/package-lock.json index cf190edb..e99d18ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5766,18 +5766,17 @@ "link": true }, "node_modules/@mongodb-js/oidc-plugin": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/oidc-plugin/-/oidc-plugin-0.4.0.tgz", - "integrity": "sha512-tinXSz6O2AmgMAgorXUcCJtDhayghkmsXVVTd5UiXhzSA/NNVtlleZXSVkG6tr46WXGzLISgVX+lUzzcEIiwJQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/oidc-plugin/-/oidc-plugin-1.0.0.tgz", + "integrity": "sha512-fWEvEzBKRN3HmYw0AHpPLPGp81TwdP7CrtTnqlW+yzH/m6HnnqkYPzaPur2nVOKCpRaxufFlKXx3jg0klgf/uA==", "dev": true, "dependencies": { - "abort-controller": "^3.0.0", "express": "^4.18.2", "open": "^9.1.0", "openid-client": "^5.6.4" }, "engines": { - "node": ">= 14.18.0" + "node": ">= 16.20.1" } }, "node_modules/@mongodb-js/oidc-plugin/node_modules/define-lazy-prop": { @@ -7877,18 +7876,6 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -12047,15 +12034,6 @@ "es5-ext": "~0.10.14" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -24521,7 +24499,7 @@ "system-ca": "^1.0.2" }, "devDependencies": { - "@mongodb-js/oidc-plugin": "^0.4.0", + "@mongodb-js/oidc-plugin": "^1.0.0", "@mongodb-js/saslprep": "^1.1.7", "@types/lodash.merge": "^4.6.7", "@types/mocha": "^9.0.0", @@ -24554,7 +24532,7 @@ "resolve-mongodb-srv": "^1.1.1" }, "peerDependencies": { - "@mongodb-js/oidc-plugin": "^0.4.0", + "@mongodb-js/oidc-plugin": "^1.0.0", "mongodb": "^5.8.1 || ^6.0.0", "mongodb-log-writer": "^1.4.2" } @@ -31005,7 +30983,7 @@ "version": "file:packages/devtools-connect", "requires": { "@mongodb-js/oidc-http-server-pages": "1.1.1", - "@mongodb-js/oidc-plugin": "^0.4.0", + "@mongodb-js/oidc-plugin": "^1.0.0", "@mongodb-js/saslprep": "^1.1.7", "@types/lodash.merge": "^4.6.7", "@types/mocha": "^9.0.0", @@ -31966,12 +31944,11 @@ } }, "@mongodb-js/oidc-plugin": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/oidc-plugin/-/oidc-plugin-0.4.0.tgz", - "integrity": "sha512-tinXSz6O2AmgMAgorXUcCJtDhayghkmsXVVTd5UiXhzSA/NNVtlleZXSVkG6tr46WXGzLISgVX+lUzzcEIiwJQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/oidc-plugin/-/oidc-plugin-1.0.0.tgz", + "integrity": "sha512-fWEvEzBKRN3HmYw0AHpPLPGp81TwdP7CrtTnqlW+yzH/m6HnnqkYPzaPur2nVOKCpRaxufFlKXx3jg0klgf/uA==", "dev": true, "requires": { - "abort-controller": "^3.0.0", "express": "^4.18.2", "open": "^9.1.0", "openid-client": "^5.6.4" @@ -34004,15 +33981,6 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, - "requires": { - "event-target-shim": "^5.0.0" - } - }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -37115,12 +37083,6 @@ "es5-ext": "~0.10.14" } }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true - }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", diff --git a/packages/devtools-connect/package.json b/packages/devtools-connect/package.json index 00d90b79..614dd81a 100644 --- a/packages/devtools-connect/package.json +++ b/packages/devtools-connect/package.json @@ -54,12 +54,12 @@ "system-ca": "^1.0.2" }, "peerDependencies": { - "@mongodb-js/oidc-plugin": "^0.4.0", + "@mongodb-js/oidc-plugin": "^1.0.0", "mongodb": "^5.8.1 || ^6.0.0", "mongodb-log-writer": "^1.4.2" }, "devDependencies": { - "@mongodb-js/oidc-plugin": "^0.4.0", + "@mongodb-js/oidc-plugin": "^1.0.0", "@mongodb-js/saslprep": "^1.1.7", "@types/lodash.merge": "^4.6.7", "@types/mocha": "^9.0.0", diff --git a/packages/devtools-connect/src/ipc-rpc-state-share.spec.ts b/packages/devtools-connect/src/ipc-rpc-state-share.spec.ts index 9f107a00..55b01f06 100644 --- a/packages/devtools-connect/src/ipc-rpc-state-share.spec.ts +++ b/packages/devtools-connect/src/ipc-rpc-state-share.spec.ts @@ -102,27 +102,22 @@ describe('IPC RPC state sharing', function () { describe('StateShareServer/StateShareClient', function () { let fakeState: DevtoolsConnectionState; - let request: sinon.SinonStub; - let refresh: sinon.SinonStub; + let callback: sinon.SinonStub; let server: StateShareServer; let client: StateShareClient; beforeEach(function () { - request = sinon.stub(); - refresh = sinon.stub(); + callback = sinon.stub(); fakeState = { productName: 'MongoDB Something', oidcPlugin: { mongoClientOptions: { authMechanismProperties: { - REFRESH_TOKEN_CALLBACK: refresh, - REQUEST_TOKEN_CALLBACK: request, + OIDC_HUMAN_CALLBACK: callback, }, }, }, } as unknown as DevtoolsConnectionState; - request.resolves({ accessToken: 'req-accesstoken' }); - refresh.resolves({ accessToken: 'ref-accesstoken' }); }); afterEach(async function () { @@ -130,43 +125,42 @@ describe('IPC RPC state sharing', function () { }); it('can be used to share OIDC state', async function () { + callback.resolves({ accessToken: 'req-accesstoken' }); server = await StateShareServer.create(fakeState); client = new StateShareClient(server.handle); const result = - await client.oidcPlugin.mongoClientOptions.authMechanismProperties.REQUEST_TOKEN_CALLBACK( + await client.oidcPlugin.mongoClientOptions.authMechanismProperties.OIDC_HUMAN_CALLBACK( { - issuer: 'http://localhost/', - clientId: 'clientId', - }, - { - version: 0, + idpInfo: { + issuer: 'http://localhost/', + clientId: 'clientId', + }, + version: 1, } ); expect(result).to.deep.equal({ accessToken: 'req-accesstoken' }); }); it('supports timeoutContext', async function () { - refresh.callsFake( - (_idpInfo: unknown, ctx: { timeoutContext: AbortSignal }) => { - return new Promise((resolve, reject) => - ctx.timeoutContext.addEventListener('abort', () => - reject(new Error('aborted')) - ) - ); - } - ); + callback.callsFake((params: { timeoutContext: AbortSignal }) => { + return new Promise((resolve, reject) => + params.timeoutContext.addEventListener('abort', () => + reject(new Error('aborted')) + ) + ); + }); server = await StateShareServer.create(fakeState); client = new StateShareClient(server.handle); const abortController = new AbortController(); const result = - client.oidcPlugin.mongoClientOptions.authMechanismProperties.REFRESH_TOKEN_CALLBACK( - { - issuer: 'http://localhost/', - clientId: 'clientId', - }, + client.oidcPlugin.mongoClientOptions.authMechanismProperties.OIDC_HUMAN_CALLBACK( { - version: 0, + idpInfo: { + issuer: 'http://localhost/', + clientId: 'clientId', + }, + version: 1, timeoutContext: abortController.signal, } ); diff --git a/packages/devtools-connect/src/ipc-rpc-state-share.ts b/packages/devtools-connect/src/ipc-rpc-state-share.ts index 7213fa11..067d5082 100644 --- a/packages/devtools-connect/src/ipc-rpc-state-share.ts +++ b/packages/devtools-connect/src/ipc-rpc-state-share.ts @@ -1,8 +1,7 @@ import type { MongoDBOIDCPlugin, - IdPServerInfo, IdPServerResponse, - OIDCCallbackContext, + OIDCCallbackParams, } from '@mongodb-js/oidc-plugin'; import type { DevtoolsConnectionState } from './connect'; import { createServer as createHTTPServer, request } from 'http'; @@ -225,26 +224,21 @@ export class StateShareServer extends RpcServer { // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types protected async handleRpc(content: any): Promise> { - const oidcCallbacks = - this.state.oidcPlugin.mongoClientOptions.authMechanismProperties; - let oidcMethod: keyof typeof oidcCallbacks; switch (content.method) { case 'oidc:_abort': this.abortContexts.get(content.timeoutContextId)?.abort(); return {}; - case 'oidc:REQUEST_TOKEN_CALLBACK': - oidcMethod = 'REQUEST_TOKEN_CALLBACK'; - // fallthrough - case 'oidc:REFRESH_TOKEN_CALLBACK': { - oidcMethod ??= 'REFRESH_TOKEN_CALLBACK'; - + case 'oidc:OIDC_HUMAN_CALLBACK': { const abortController = new AbortController(); this.abortContexts.set(content.timeoutContextId, abortController); try { - const result = await oidcCallbacks[oidcMethod](content.info, { - ...content.context, - timeoutContext: abortController.signal, - }); + const result = + await this.state.oidcPlugin.mongoClientOptions.authMechanismProperties.OIDC_HUMAN_CALLBACK( + { + ...content.callbackParams, + timeoutContext: abortController.signal, + } + ); return { result }; } finally { this.abortContexts.delete(content.timeoutContextId); @@ -275,13 +269,9 @@ export class StateShareClient extends RpcClient { logger: new EventEmitter(), mongoClientOptions: { authMechanismProperties: { - REQUEST_TOKEN_CALLBACK: this._oidcCallback.bind( - this, - 'oidc:REQUEST_TOKEN_CALLBACK' - ), - REFRESH_TOKEN_CALLBACK: this._oidcCallback.bind( + OIDC_HUMAN_CALLBACK: this._oidcCallback.bind( this, - 'oidc:REFRESH_TOKEN_CALLBACK' + 'oidc:OIDC_HUMAN_CALLBACK' ), }, }, @@ -290,13 +280,12 @@ export class StateShareClient extends RpcClient { private async _oidcCallback( method: string, - info: IdPServerInfo, - _context: OIDCCallbackContext + params: OIDCCallbackParams ): Promise { const timeoutContextId = (await promisify(crypto.randomBytes)(16)).toString( 'base64' ); - const { timeoutContext, ...context } = _context; + const { timeoutContext, ...callbackParams } = params; const abort = async () => { await this.makeRpcCall({ method: 'oidc:_abort', @@ -308,8 +297,7 @@ export class StateShareClient extends RpcClient { const { result } = await this.makeRpcCall({ method, timeoutContextId, - context, - info, + callbackParams, }); return result as IdPServerResponse; } finally {