Skip to content

Commit eb66433

Browse files
authored
fix: include username in server metadata key (#194)
This is something we should have ideally always been doing (as hinted at by the doc comment for `getAuthState()`), but which the driver only added back support for in 6.7.0. This shouldn't have an immediate impact on our products, because we already have some mitigations in place for the fact that usernames were previously not being taken into account (e.g. here: https://github.com/mongodb-js/mongosh/blob/adc530e7ffcf092677d944fd69670c5cbd8e103d/packages/service-provider-server/src/cli-service-provider.ts#L172 ), but is semantically the right thing to do and should give us a bit more flexibility in the future. Also, add a test that confirms that changes to server metadata/username actually have the expected effect, and emit a message bus event that shares information about the server metadata, as that may be helpful debugging information.
1 parent e8533b1 commit eb66433

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

src/plugin.spec.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,14 @@ async function fetchBrowser({ url }: OpenBrowserOptions): Promise<void> {
5555
function requestToken(
5656
plugin: MongoDBOIDCPlugin,
5757
oidcParams: IdPServerInfo,
58-
abortSignal?: OIDCAbortSignal
58+
abortSignal?: OIDCAbortSignal,
59+
username?: string
5960
): ReturnType<OIDCCallbackFunction> {
6061
return plugin.mongoClientOptions.authMechanismProperties.OIDC_HUMAN_CALLBACK({
6162
timeoutContext: abortSignal,
6263
version: 1,
6364
idpInfo: oidcParams,
65+
username,
6466
});
6567
}
6668

@@ -500,6 +502,47 @@ describe('OIDC plugin (local OIDC provider)', function () {
500502
expect(pluginOptions.allowedFlows).to.have.been.calledTwice;
501503
});
502504
});
505+
506+
context('when the server metadata/user data changes', function () {
507+
beforeEach(function () {
508+
(pluginOptions.allowedFlows = sinon.stub().resolves(['auth-code'])),
509+
(plugin = createMongoDBOIDCPlugin(pluginOptions));
510+
});
511+
512+
it('it will perform two different auth flows', async function () {
513+
await requestToken(
514+
plugin,
515+
provider.getMongodbOIDCDBInfo(),
516+
undefined,
517+
'usera'
518+
);
519+
expect(pluginOptions.allowedFlows).to.have.callCount(1);
520+
await requestToken(
521+
plugin,
522+
provider.getMongodbOIDCDBInfo(),
523+
undefined,
524+
'userb'
525+
);
526+
expect(pluginOptions.allowedFlows).to.have.callCount(2);
527+
await requestToken(
528+
plugin,
529+
provider.getMongodbOIDCDBInfo(),
530+
undefined,
531+
'userb'
532+
);
533+
expect(pluginOptions.allowedFlows).to.have.callCount(2);
534+
await requestToken(
535+
plugin,
536+
{
537+
...provider.getMongodbOIDCDBInfo(),
538+
extraKey: 'asdf',
539+
} as IdPServerInfo,
540+
undefined,
541+
'userb'
542+
);
543+
expect(pluginOptions.allowedFlows).to.have.callCount(3);
544+
});
545+
});
503546
});
504547

505548
context('when the user aborts an auth code flow', function () {

src/plugin.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ type LastIdTokenClaims =
5252
interface UserOIDCAuthState {
5353
// The information that the driver forwarded to us from the server
5454
// about the OIDC Identity Provider config.
55-
serverOIDCMetadata: IdPServerInfo;
55+
serverOIDCMetadata: IdPServerInfo & Pick<OIDCCallbackParams, 'username'>;
5656
// A Promise that resolves when the current authentication attempt
5757
// is finished, if there is one at the moment.
5858
currentAuthAttempt: Promise<IdPServerResponse> | null;
@@ -288,7 +288,9 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
288288

289289
// Return the current state for a given [server, username] configuration,
290290
// or create a new one if none exists.
291-
private getAuthState(serverMetadata: IdPServerInfo): UserOIDCAuthState {
291+
private getAuthState(
292+
serverMetadata: IdPServerInfo & Pick<OIDCCallbackParams, 'username'>
293+
): UserOIDCAuthState {
292294
if (!serverMetadata.issuer || typeof serverMetadata.issuer !== 'string') {
293295
throw new MongoDBOIDCError(`'issuer' is missing`);
294296
}
@@ -909,6 +911,7 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
909911
public async requestToken(
910912
params: OIDCCallbackParams
911913
): Promise<IdPServerResponse> {
914+
this.logger.emit('mongodb-oidc-plugin:received-server-params', { params });
912915
if (params.version !== 1) {
913916
throw new MongoDBOIDCError(
914917
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
@@ -926,7 +929,10 @@ export class MongoDBOIDCPluginImpl implements MongoDBOIDCPlugin {
926929
throw new MongoDBOIDCError('No IdP information provided');
927930
}
928931

929-
const state = this.getAuthState(params.idpInfo);
932+
const state = this.getAuthState({
933+
...params.idpInfo,
934+
username: params.username,
935+
});
930936

931937
if (state.currentAuthAttempt) {
932938
return await state.currentAuthAttempt;

src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ export interface MongoDBOIDCLogEventsMap {
7575
'mongodb-oidc-plugin:missing-id-token': () => void;
7676
'mongodb-oidc-plugin:outbound-http-request': (event: { url: string }) => void;
7777
'mongodb-oidc-plugin:inbound-http-request': (event: { url: string }) => void;
78+
'mongodb-oidc-plugin:received-server-params': (event: {
79+
params: OIDCCallbackParams;
80+
}) => void;
7881
}
7982

8083
/** @public */

0 commit comments

Comments
 (0)