@mongodb-js/oidc-plugin 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/util.js ADDED
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.timeoutSignal = exports.AbortSignal = exports.AbortController = exports.errorString = exports.withAbortCheck = exports.throwIfAborted = void 0;
4
+ class AbortError extends Error {
5
+ constructor() {
6
+ super('The operation was aborted');
7
+ }
8
+ }
9
+ function throwIfAborted(signal) {
10
+ if (signal?.aborted)
11
+ throw signal.reason ?? new AbortError();
12
+ }
13
+ exports.throwIfAborted = throwIfAborted;
14
+ async function withAbortCheck(signal, fn) {
15
+ const signalCheck = () => throwIfAborted(signal);
16
+ let reject;
17
+ const signalPromise = new Promise((resolve, rej) => {
18
+ reject = rej;
19
+ });
20
+ function listener() {
21
+ reject(signal?.reason ?? new AbortError());
22
+ }
23
+ signalPromise.catch(() => {
24
+ /* squelch UnhandledPromiseRejectionWarning */
25
+ });
26
+ signalCheck();
27
+ signal?.addEventListener('abort', listener, { once: true });
28
+ try {
29
+ return await fn({ signalCheck, signalPromise });
30
+ }
31
+ finally {
32
+ signal?.removeEventListener('abort', listener);
33
+ }
34
+ }
35
+ exports.withAbortCheck = withAbortCheck;
36
+ function errorString(err) {
37
+ return String(typeof err === 'object' && err && 'message' in err ? err.message : err);
38
+ }
39
+ exports.errorString = errorString;
40
+ exports.AbortController =
41
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
42
+ globalThis.AbortController ?? require('abort-controller').AbortController;
43
+ exports.AbortSignal =
44
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
45
+ globalThis.AbortSignal ?? require('abort-controller').AbortSignal;
46
+ // AbortSignal.timeout, but consistently .unref()ed
47
+ function timeoutSignal(ms) {
48
+ const controller = new exports.AbortController();
49
+ setTimeout(() => controller.abort(), ms).unref();
50
+ return controller.signal;
51
+ }
52
+ exports.timeoutSignal = timeoutSignal;
53
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;AAEA,MAAM,UAAW,SAAQ,KAAK;IAC5B;QACE,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACrC,CAAC;CACF;AAED,SAAgB,cAAc,CAAC,MAAwB;IACrD,IAAI,MAAM,EAAE,OAAO;QAAE,MAAM,MAAM,CAAC,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;AAC/D,CAAC;AAFD,wCAEC;AAMM,KAAK,UAAU,cAAc,CAGlC,MAAmC,EAAE,EAAK;IAC1C,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD,IAAI,MAA8B,CAAC;IACnC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;QACxD,MAAM,GAAG,GAAG,CAAC;IACf,CAAC,CAAC,CAAC;IACH,SAAS,QAAQ;QACf,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,aAAa,CAAC,KAAK,CAAC,GAAG,EAAE;QACvB,8CAA8C;IAChD,CAAC,CAAC,CAAC;IAEH,WAAW,EAAE,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,IAAI;QACF,OAAO,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC,CAAC;KACjD;YAAS;QACR,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;KAChD;AACH,CAAC;AAvBD,wCAuBC;AAED,SAAgB,WAAW,CAAC,GAAY;IACtC,OAAO,MAAM,CACX,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,IAAI,SAAS,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CACvE,CAAC;AACJ,CAAC;AAJD,kCAIC;AAEY,QAAA,eAAe;AAC1B,8DAA8D;AAC9D,UAAU,CAAC,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC,eAAe,CAAC;AAC/D,QAAA,WAAW;AACtB,8DAA8D;AAC9D,UAAU,CAAC,WAAW,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC,WAAW,CAAC;AAEpE,mDAAmD;AACnD,SAAgB,aAAa,CAAC,EAAU;IACtC,MAAM,UAAU,GAAG,IAAI,uBAAe,EAAE,CAAC;IACzC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;IACjD,OAAO,UAAU,CAAC,MAAM,CAAC;AAC3B,CAAC;AAJD,sCAIC"}
File without changes
package/index.d.ts ADDED
@@ -0,0 +1,287 @@
1
+ /// <reference types="node" />
2
+
3
+ import type { IncomingMessage } from 'http';
4
+ import type { ServerResponse } from 'http';
5
+
6
+ /** @public */
7
+ export declare type AuthFlowType = 'auth-code' | 'device-auth';
8
+
9
+ /**
10
+ * Create a new OIDC plugin instance that can be passed to the Node.js MongoDB
11
+ * driver's MongoClientOptions struct.
12
+ *
13
+ * This plugin instance can be passed to multiple MongoClient instances.
14
+ * It caches credentials based on cluster ID and username. If no username is
15
+ * provided when connecting to the MongoDB instance, the cache will be shared
16
+ * across all MongoClients that use this plugin instance.
17
+ *
18
+ * @public
19
+ */
20
+ export declare function createMongoDBOIDCPlugin(options: Readonly<MongoDBOIDCPluginOptions>): MongoDBOIDCPlugin;
21
+
22
+ /**
23
+ * Information that the application needs to show to users when using the
24
+ * Device Authorization flow.
25
+ *
26
+ * @public
27
+ */
28
+ export declare interface DeviceFlowInformation {
29
+ verificationUrl: string;
30
+ userCode: string;
31
+ }
32
+
33
+ /** @public */
34
+ export declare class MongoDBOIDCError extends Error {
35
+ /* Excluded from this release type: [MongoDBOIDCErrorTag] */
36
+ constructor(message: string);
37
+ static isMongoDBOIDCError(value: unknown): value is MongoDBOIDCError;
38
+ }
39
+
40
+ /* Excluded from this release type: MongoDBOIDCErrorTag */
41
+
42
+ /** @public */
43
+ export declare interface MongoDBOIDCLogEventsMap {
44
+ 'mongodb-oidc-plugin:local-redirect-accessed': (event: {
45
+ id: string;
46
+ }) => void;
47
+ 'mongodb-oidc-plugin:oidc-callback-accepted': (event: {
48
+ method: string;
49
+ hasBody: boolean;
50
+ errorCode?: string;
51
+ }) => void;
52
+ 'mongodb-oidc-plugin:oidc-callback-rejected': (event: {
53
+ method: string;
54
+ hasBody: boolean;
55
+ errorCode: string;
56
+ isAcceptedOIDCResponse: boolean;
57
+ }) => void;
58
+ 'mongodb-oidc-plugin:unknown-url-accessed': (event: {
59
+ method: string;
60
+ path: string;
61
+ }) => void;
62
+ 'mongodb-oidc-plugin:local-listen-started': (event: {
63
+ url: string;
64
+ }) => void;
65
+ 'mongodb-oidc-plugin:local-listen-failed': (event: {
66
+ url: string;
67
+ }) => void;
68
+ 'mongodb-oidc-plugin:local-listen-succeeded': (event: {
69
+ url: string;
70
+ interfaces: string[];
71
+ }) => void;
72
+ 'mongodb-oidc-plugin:local-server-close': (event: {
73
+ url: string;
74
+ }) => void;
75
+ 'mongodb-oidc-plugin:open-browser': (event: {
76
+ customOpener: boolean;
77
+ }) => void;
78
+ 'mongodb-oidc-plugin:notify-device-flow': () => void;
79
+ 'mongodb-oidc-plugin:auth-attempt-started': (event: {
80
+ flow: string;
81
+ }) => void;
82
+ 'mongodb-oidc-plugin:auth-attempt-succeeded': () => void;
83
+ 'mongodb-oidc-plugin:auth-attempt-failed': (event: {
84
+ error: string;
85
+ }) => void;
86
+ 'mongodb-oidc-plugin:refresh-failed': (event: {
87
+ error: string;
88
+ }) => void;
89
+ 'mongodb-oidc-plugin:skip-auth-attempt': (event: {
90
+ reason: string;
91
+ }) => void;
92
+ 'mongodb-oidc-plugin:auth-failed': (event: {
93
+ error: string;
94
+ }) => void;
95
+ 'mongodb-oidc-plugin:auth-succeeded': (event: {
96
+ hasRefreshToken: boolean;
97
+ expiresAt: string | null;
98
+ }) => void;
99
+ }
100
+
101
+ /** @public */
102
+ export declare interface MongoDBOIDCPlugin {
103
+ /**
104
+ * A subset of MongoClientOptions that need to be set in order
105
+ * for the MongoClient to an instance of this plugin.
106
+ *
107
+ * This object should be deep-merged with other, pre-existing
108
+ * MongoClient driver options.
109
+ */
110
+ readonly mongoClientOptions: {
111
+ readonly authMechanismProperties: {
112
+ readonly REQUEST_TOKEN_CALLBACK: OIDCRequestFunction;
113
+ readonly REFRESH_TOKEN_CALLBACK: OIDCRefreshFunction;
114
+ };
115
+ };
116
+ /**
117
+ * The logger instance passed in the options, or a default one otherwise.
118
+ */
119
+ readonly logger: TypedEventEmitter<MongoDBOIDCLogEventsMap>;
120
+ }
121
+
122
+ /** @public */
123
+ export declare interface MongoDBOIDCPluginOptions {
124
+ /**
125
+ * A local URL to listen on. If this is not provided, a default URL
126
+ * standardized for MongoDB applications is used.
127
+ *
128
+ * This is only used when the Authorization Code flow is enabled,
129
+ * and when it is possible to open a browser.
130
+ */
131
+ redirectURI?: string;
132
+ /**
133
+ * A function that opens an URL in a browser window. If this is `false`,
134
+ * then all flows involving automatic browser operation (currently
135
+ * Authorization Code flow) are disabled.
136
+ *
137
+ * If a `{ command: string }` object is provided, `command` will be spawned
138
+ * inside a shell and receive the target URL as an argument. If `abortable`
139
+ * is set, then a possible AbortSignal will be passed on and the child
140
+ * process will be killed once that is reached. (This does not typically
141
+ * make sense for GUI browsers, but can for command-line browsers.)
142
+ *
143
+ * If this option is missing or undefined, the default behavior is to use
144
+ * `shell.openExternal()` if this is running inside of electron, and
145
+ * the `open` package otherwise.
146
+ */
147
+ openBrowser?: undefined | false | {
148
+ command: string;
149
+ abortable?: boolean;
150
+ } | ((options: OpenBrowserOptions) => Promise<OpenBrowserReturnType>);
151
+ /**
152
+ * The maximum time that the plugin waits for an opened browser to access
153
+ * the URL that was passed to it, in milliseconds. The default is 10 seconds.
154
+ * Passing a value of zero will disable the timeout altogether.
155
+ */
156
+ openBrowserTimeout?: number;
157
+ /**
158
+ * A callback to provide users with the information required to operate
159
+ * the Device Authorization flow.
160
+ */
161
+ notifyDeviceFlow?: (information: DeviceFlowInformation) => Promise<void> | void;
162
+ /**
163
+ * Restrict possible OIDC authorization flows to a subset.
164
+ */
165
+ allowedFlows?: AuthFlowType[];
166
+ /**
167
+ * An optional EventEmitter that can be used for recording log events.
168
+ */
169
+ logger?: TypedEventEmitter<MongoDBOIDCLogEventsMap>;
170
+ /**
171
+ * An AbortSignal that can be used to explicitly cancel authentication
172
+ * attempts, for example if a user intentionally aborts a connection
173
+ * attempt.
174
+ *
175
+ * Note that the driver also registers its own AbortSignal with individual
176
+ * authentication attempts in order to enforce a timeout, which has the
177
+ * same effect for authentication attempts from that driver MongoClient
178
+ * instance (but does not prevent other MongoClients from using this
179
+ * plugin instance to authenticate).
180
+ */
181
+ signal?: OIDCAbortSignal;
182
+ /**
183
+ * A custom handler for providing HTTP responses for requests to the
184
+ * redirect HTTP server used in the Authorization Code Flow.
185
+ *
186
+ * The default handler serves simple text/plain messages.
187
+ */
188
+ redirectServerRequestHandler?: RedirectServerRequestHandler;
189
+ }
190
+
191
+ /** @public */
192
+ export declare type OIDCAbortSignal = {
193
+ aborted: boolean;
194
+ reason?: unknown;
195
+ addEventListener(type: 'abort', callback: () => void, options?: {
196
+ once: boolean;
197
+ }): void;
198
+ removeEventListener(type: 'abort', callback: () => void): void;
199
+ };
200
+
201
+ /**
202
+ * A copy of the Node.js driver's `OIDCMechanismServerStep1`
203
+ * @public
204
+ */
205
+ export declare interface OIDCMechanismServerStep1 {
206
+ authorizationEndpoint?: string;
207
+ tokenEndpoint?: string;
208
+ deviceAuthorizationEndpoint?: string;
209
+ clientId: string;
210
+ clientSecret?: string;
211
+ requestScopes?: string[];
212
+ }
213
+
214
+ /**
215
+ * A copy of the Node.js driver's `OIDCRefreshFunction`
216
+ * @public
217
+ */
218
+ export declare type OIDCRefreshFunction = (principalName: string | undefined, idl: OIDCMechanismServerStep1, result: OIDCRequestTokenResult, abortSignal?: OIDCAbortSignal | number) => Promise<OIDCRequestTokenResult>;
219
+
220
+ /**
221
+ * A copy of the Node.js driver's `OIDCRequestFunction`
222
+ * @public
223
+ */
224
+ export declare type OIDCRequestFunction = (principalName: string | undefined, idl: OIDCMechanismServerStep1, abortSignal?: OIDCAbortSignal | number) => Promise<OIDCRequestTokenResult>;
225
+
226
+ /**
227
+ * A copy of the Node.js driver's `OIDCRequestTokenResult`
228
+ * @public
229
+ */
230
+ export declare interface OIDCRequestTokenResult {
231
+ accessToken: string;
232
+ expiresInSeconds?: number;
233
+ refreshToken?: string;
234
+ }
235
+
236
+ /** @public */
237
+ export declare interface OpenBrowserOptions {
238
+ /**
239
+ * The URL to open the browser with.
240
+ */
241
+ url: string;
242
+ /**
243
+ * A signal that is aborted when the user or the driver abort
244
+ * an authentication attempt.
245
+ */
246
+ signal: AbortSignal;
247
+ }
248
+
249
+ /** @public */
250
+ export declare type OpenBrowserReturnType = void | undefined | TypedEventEmitter<{
251
+ exit(exitCode: number): void;
252
+ error(err: unknown): void;
253
+ }>;
254
+
255
+ /** @public */
256
+ export declare type RedirectServerRequestHandler = (data: RedirectServerRequestInfo) => void;
257
+
258
+ /** @public */
259
+ export declare type RedirectServerRequestInfo = {
260
+ /** The incoming HTTP request. */
261
+ req: IncomingMessage;
262
+ /** The outgoing HTTP response. */
263
+ res: ServerResponse;
264
+ /** The suggested HTTP status code. For unknown-url, this is 404. */
265
+ status: number;
266
+ } & ({
267
+ result: 'rejected';
268
+ /** Error information reported by the IdP as defined in RFC6749 section 4.1.2.1 */
269
+ error?: string;
270
+ /** Error information reported by the IdP as defined in RFC6749 section 4.1.2.1 */
271
+ errorDescription?: string;
272
+ /** Error information reported by the IdP as defined in RFC6749 section 4.1.2.1 */
273
+ errorURI?: string;
274
+ } | {
275
+ result: 'accepted';
276
+ } | {
277
+ result: 'unknown-url';
278
+ });
279
+
280
+ /** @public */
281
+ export declare interface TypedEventEmitter<EventMap extends object> {
282
+ on<K extends keyof EventMap>(event: K, listener: EventMap[K]): this;
283
+ once<K extends keyof EventMap>(event: K, listener: EventMap[K]): this;
284
+ emit<K extends keyof EventMap>(event: K, ...args: EventMap[K] extends (...args: infer P) => any ? P : never): unknown;
285
+ }
286
+
287
+ export { }
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "@mongodb-js/oidc-plugin",
3
+ "description": "MongoDB OIDC plugin for the Node.js driver",
4
+ "author": {
5
+ "name": "MongoDB Inc",
6
+ "email": "compass@mongodb.com"
7
+ },
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "bugs": {
12
+ "url": "https://jira.mongodb.org/projects/COMPASS/issues",
13
+ "email": "compass@mongodb.com"
14
+ },
15
+ "homepage": "https://github.com/mongodb-js/oidc-plugin",
16
+ "version": "0.1.0-alpha.0",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/mongodb-js/oidc-plugin.git"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "index.d.ts",
24
+ "README.md"
25
+ ],
26
+ "license": "Apache-2.0",
27
+ "main": "dist/index.js",
28
+ "exports": {
29
+ "require": "./dist/index.js",
30
+ "import": "./dist/.esm-wrapper.mjs"
31
+ },
32
+ "engines": {
33
+ "node": ">= 14.18.0"
34
+ },
35
+ "types": "./index.d.ts",
36
+ "scripts": {
37
+ "bootstrap": "npm run compile",
38
+ "prepublishOnly": "npm run compile",
39
+ "compile": "tsc -p tsconfig.json && api-extractor run && rimraf 'dist/**/*.d.ts*' && gen-esm-wrapper . ./dist/.esm-wrapper.mjs",
40
+ "typecheck": "tsc --noEmit",
41
+ "eslint": "eslint",
42
+ "prettier": "prettier",
43
+ "lint": "npm run eslint . && npm run prettier -- --check .",
44
+ "depcheck": "depcheck",
45
+ "check": "npm run typecheck && npm run lint && npm run depcheck",
46
+ "check-ci": "npm run check",
47
+ "test": "xvfb-maybe --auto-servernum -- mocha",
48
+ "test-electron": "xvfb-maybe --auto-servernum -- electron-mocha",
49
+ "test-cov": "nyc -x \"**/*.spec.*\" --reporter=lcov --reporter=text --reporter=html npm run test",
50
+ "test-watch": "npm run test -- --watch",
51
+ "test-ci": "npm run test-cov",
52
+ "reformat": "npm run prettier -- --write . && npm run eslint . -- --fix"
53
+ },
54
+ "devDependencies": {
55
+ "@microsoft/api-extractor": "^7.34.4",
56
+ "@mongodb-js/mocha-config-compass": "^0.10.0",
57
+ "@mongodb-js/prettier-config-compass": "^0.5.0",
58
+ "@mongodb-js/tsconfig-compass": "^0.6.0",
59
+ "@types/chai": "^4.2.21",
60
+ "@types/express": "^4.17.17",
61
+ "@types/mocha": "^9.0.0",
62
+ "@types/node": "^18.13.0",
63
+ "@types/oidc-provider": "^8.1.1",
64
+ "@types/sinon-chai": "^3.2.5",
65
+ "@typescript-eslint/eslint-plugin": "^5.52.0",
66
+ "@typescript-eslint/parser": "^5.54.1",
67
+ "chai": "^4.3.6",
68
+ "depcheck": "^1.4.1",
69
+ "electron": "^23.1.2",
70
+ "electron-mocha": "^11.0.2",
71
+ "eslint": "^7.25.0",
72
+ "eslint-config-prettier": "^8.7.0",
73
+ "eslint-plugin-mocha": "^10.1.0",
74
+ "gen-esm-wrapper": "^1.1.0",
75
+ "mocha": "^10.2.0",
76
+ "node-fetch": "^3.3.1",
77
+ "nyc": "^15.1.0",
78
+ "oidc-provider": "https://github.com/panva/node-oidc-provider/archive/refs/tags/v7.14.3.tar.gz",
79
+ "prettier": "2.3.2",
80
+ "rimraf": "^4.4.0",
81
+ "sinon": "^9.2.3",
82
+ "typescript": "^4.9.5",
83
+ "webdriverio": "^8.5.9",
84
+ "xvfb-maybe": "^0.2.1"
85
+ },
86
+ "dependencies": {
87
+ "abort-controller": "^3.0.0",
88
+ "express": "^4.18.2",
89
+ "open": "^8.4.1",
90
+ "openid-client": "^5.4.0"
91
+ }
92
+ }