Skip to content

Commit 806e07d

Browse files
committed
feat(NODE-5464): removing caching mechanism
1 parent 82f7938 commit 806e07d

10 files changed

+170
-753
lines changed

src/cmap/auth/mongo_credentials.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
MongoMissingCredentialsError
99
} from '../../error';
1010
import { GSSAPICanonicalizationValue } from './gssapi';
11-
import type { OIDCRefreshFunction, OIDCRequestFunction } from './mongodb_oidc';
11+
import type { OIDCRequestFunction } from './mongodb_oidc';
1212
import { AUTH_MECHS_AUTH_SRC_EXTERNAL, AuthMechanism } from './providers';
1313

1414
// https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst
@@ -59,8 +59,6 @@ export interface AuthMechanismProperties extends Document {
5959
/** @experimental */
6060
REQUEST_TOKEN_CALLBACK?: OIDCRequestFunction;
6161
/** @experimental */
62-
REFRESH_TOKEN_CALLBACK?: OIDCRefreshFunction;
63-
/** @experimental */
6462
PROVIDER_NAME?: 'aws' | 'azure';
6563
/** @experimental */
6664
ALLOWED_HOSTS?: string[];

src/cmap/auth/mongodb_oidc.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,6 @@ export type OIDCRequestFunction = (
5252
context: OIDCCallbackContext
5353
) => Promise<IdPServerResponse>;
5454

55-
/**
56-
* @public
57-
* @experimental
58-
*/
59-
export type OIDCRefreshFunction = (
60-
info: IdPServerInfo,
61-
context: OIDCCallbackContext
62-
) => Promise<IdPServerResponse>;
63-
6455
type ProviderName = 'aws' | 'azure' | 'callback';
6556

6657
export interface Workflow {

src/cmap/auth/mongodb_oidc/callback_lock_cache.ts

Lines changed: 0 additions & 114 deletions
This file was deleted.

src/cmap/auth/mongodb_oidc/callback_workflow.ts

Lines changed: 30 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
import { Binary, BSON, type Document } from 'bson';
22

3-
import { MONGODB_ERROR_CODES, MongoError, MongoMissingCredentialsError } from '../../../error';
3+
import { MongoMissingCredentialsError } from '../../../error';
44
import { ns } from '../../../utils';
55
import type { Connection } from '../../connection';
66
import type { MongoCredentials } from '../mongo_credentials';
77
import type {
88
IdPServerInfo,
99
IdPServerResponse,
1010
OIDCCallbackContext,
11-
OIDCRefreshFunction,
1211
OIDCRequestFunction,
1312
Workflow
1413
} from '../mongodb_oidc';
1514
import { AuthMechanism } from '../providers';
16-
import { CallbackLockCache } from './callback_lock_cache';
17-
import { TokenEntryCache } from './token_entry_cache';
1815

1916
/** The current version of OIDC implementation. */
2017
const OIDC_VERSION = 0;
@@ -29,22 +26,13 @@ const RESULT_PROPERTIES = ['accessToken', 'expiresInSeconds', 'refreshToken'];
2926
const CALLBACK_RESULT_ERROR =
3027
'User provided OIDC callbacks must return a valid object with an accessToken.';
3128

29+
const NO_REQUEST_CALLBACK = 'No REQUEST_TOKEN_CALLBACK provided for callback workflow.';
30+
3231
/**
3332
* OIDC implementation of a callback based workflow.
3433
* @internal
3534
*/
3635
export class CallbackWorkflow implements Workflow {
37-
cache: TokenEntryCache;
38-
callbackCache: CallbackLockCache;
39-
40-
/**
41-
* Instantiate the workflow
42-
*/
43-
constructor() {
44-
this.cache = new TokenEntryCache();
45-
this.callbackCache = new CallbackLockCache();
46-
}
47-
4836
/**
4937
* Get the document to add for speculative authentication. This also needs
5038
* to add a db field from the credentials source.
@@ -64,87 +52,32 @@ export class CallbackWorkflow implements Workflow {
6452
reauthenticating: boolean,
6553
response?: Document
6654
): Promise<Document> {
67-
// Get the callbacks with locks from the callback lock cache.
68-
const { requestCallback, refreshCallback, callbackHash } = this.callbackCache.getEntry(
55+
const requestCallback = credentials.mechanismProperties.REQUEST_TOKEN_CALLBACK;
56+
if (!requestCallback) {
57+
throw new MongoMissingCredentialsError(NO_REQUEST_CALLBACK);
58+
}
59+
// No entry in the cache requires us to do all authentication steps
60+
// from start to finish, including getting a fresh token for the cache.
61+
const startDocument = await this.startAuthentication(
6962
connection,
70-
credentials
63+
credentials,
64+
reauthenticating,
65+
response
66+
);
67+
const conversationId = startDocument.conversationId;
68+
const serverResult = BSON.deserialize(startDocument.payload.buffer) as IdPServerInfo;
69+
const tokenResult = await this.fetchAccessToken(
70+
connection,
71+
credentials,
72+
serverResult,
73+
requestCallback
74+
);
75+
const result = await this.finishAuthentication(
76+
connection,
77+
credentials,
78+
tokenResult,
79+
conversationId
7180
);
72-
// Look for an existing entry in the cache.
73-
const entry = this.cache.getEntry(connection.address, credentials.username, callbackHash);
74-
let result;
75-
if (entry) {
76-
// Reauthentication cannot use a token from the cache since the server has
77-
// stated it is invalid by the request for reauthentication.
78-
if (entry.isValid() && !reauthenticating) {
79-
// Presence of a valid cache entry means we can skip to the finishing step.
80-
result = await this.finishAuthentication(
81-
connection,
82-
credentials,
83-
entry.tokenResult,
84-
response?.speculativeAuthenticate?.conversationId
85-
);
86-
} else {
87-
// Presence of an expired cache entry means we must fetch a new one and
88-
// then execute the final step.
89-
const tokenResult = await this.fetchAccessToken(
90-
connection,
91-
credentials,
92-
entry.serverInfo,
93-
reauthenticating,
94-
callbackHash,
95-
requestCallback,
96-
refreshCallback
97-
);
98-
try {
99-
result = await this.finishAuthentication(
100-
connection,
101-
credentials,
102-
tokenResult,
103-
reauthenticating ? undefined : response?.speculativeAuthenticate?.conversationId
104-
);
105-
} catch (error) {
106-
// If we are reauthenticating and this errors with reauthentication
107-
// required, we need to do the entire process over again and clear
108-
// the cache entry.
109-
if (
110-
reauthenticating &&
111-
error instanceof MongoError &&
112-
error.code === MONGODB_ERROR_CODES.Reauthenticate
113-
) {
114-
this.cache.deleteEntry(connection.address, credentials.username, callbackHash);
115-
result = await this.execute(connection, credentials, reauthenticating);
116-
} else {
117-
throw error;
118-
}
119-
}
120-
}
121-
} else {
122-
// No entry in the cache requires us to do all authentication steps
123-
// from start to finish, including getting a fresh token for the cache.
124-
const startDocument = await this.startAuthentication(
125-
connection,
126-
credentials,
127-
reauthenticating,
128-
response
129-
);
130-
const conversationId = startDocument.conversationId;
131-
const serverResult = BSON.deserialize(startDocument.payload.buffer) as IdPServerInfo;
132-
const tokenResult = await this.fetchAccessToken(
133-
connection,
134-
credentials,
135-
serverResult,
136-
reauthenticating,
137-
callbackHash,
138-
requestCallback,
139-
refreshCallback
140-
);
141-
result = await this.finishAuthentication(
142-
connection,
143-
credentials,
144-
tokenResult,
145-
conversationId
146-
);
147-
}
14881
return result;
14982
}
15083

@@ -197,50 +130,16 @@ export class CallbackWorkflow implements Workflow {
197130
connection: Connection,
198131
credentials: MongoCredentials,
199132
serverInfo: IdPServerInfo,
200-
reauthenticating: boolean,
201-
callbackHash: string,
202-
requestCallback: OIDCRequestFunction,
203-
refreshCallback?: OIDCRefreshFunction
133+
requestCallback: OIDCRequestFunction
204134
): Promise<IdPServerResponse> {
205-
// Get the token from the cache.
206-
const entry = this.cache.getEntry(connection.address, credentials.username, callbackHash);
207-
let result;
208135
const context: OIDCCallbackContext = { timeoutSeconds: TIMEOUT_S, version: OIDC_VERSION };
209-
// Check if there's a token in the cache.
210-
if (entry) {
211-
// If the cache entry is valid, return the token result.
212-
if (entry.isValid() && !reauthenticating) {
213-
return entry.tokenResult;
214-
}
215-
// If the cache entry is not valid, remove it from the cache and first attempt
216-
// to use the refresh callback to get a new token. If no refresh callback
217-
// exists, then fallback to the request callback.
218-
if (refreshCallback) {
219-
context.refreshToken = entry.tokenResult.refreshToken;
220-
result = await refreshCallback(serverInfo, context);
221-
} else {
222-
result = await requestCallback(serverInfo, context);
223-
}
224-
} else {
225-
// With no token in the cache we use the request callback.
226-
result = await requestCallback(serverInfo, context);
227-
}
136+
// With no token in the cache we use the request callback.
137+
const result = await requestCallback(serverInfo, context);
228138
// Validate that the result returned by the callback is acceptable. If it is not
229139
// we must clear the token result from the cache.
230140
if (isCallbackResultInvalid(result)) {
231-
this.cache.deleteEntry(connection.address, credentials.username, callbackHash);
232141
throw new MongoMissingCredentialsError(CALLBACK_RESULT_ERROR);
233142
}
234-
// Cleanup the cache.
235-
this.cache.deleteExpiredEntries();
236-
// Put the new entry into the cache.
237-
this.cache.addEntry(
238-
connection.address,
239-
credentials.username || '',
240-
callbackHash,
241-
result,
242-
serverInfo
243-
);
244143
return result;
245144
}
246145
}

0 commit comments

Comments
 (0)