Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add MongoOption builder logic #2623

Merged
merged 26 commits into from
Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions src/cmap/auth/defaultAuthProviders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@ import { MongoDBAWS } from './mongodb_aws';
import type { AuthProvider } from './auth_provider';

/** @public */
export enum AuthMechanism {
MONGODB_AWS = 'MONGODB-AWS',
MONGODB_CR = 'MONGODB-CR',
MONGODB_DEFAULT = 'DEFAULT',
MONGODB_GSSAPI = 'GSSAPI',
MONGODB_PLAIN = 'PLAIN',
MONGODB_SCRAM_SHA1 = 'SCRAM-SHA-1',
MONGODB_SCRAM_SHA256 = 'SCRAM-SHA-256',
MONGODB_X509 = 'MONGODB-X509'
}
export const AuthMechanism = {
MONGODB_AWS: 'MONGODB-AWS',
MONGODB_CR: 'MONGODB-CR',
MONGODB_DEFAULT: 'DEFAULT',
MONGODB_GSSAPI: 'GSSAPI',
MONGODB_PLAIN: 'PLAIN',
MONGODB_SCRAM_SHA1: 'SCRAM-SHA-1',
MONGODB_SCRAM_SHA256: 'SCRAM-SHA-256',
MONGODB_X509: 'MONGODB-X509'
} as const;

/** @public */
export type AuthMechanismId = typeof AuthMechanism[keyof typeof AuthMechanism];

export const AUTH_PROVIDERS = {
[AuthMechanism.MONGODB_AWS]: new MongoDBAWS(),
Expand Down
60 changes: 55 additions & 5 deletions src/cmap/auth/mongo_credentials.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// Resolves the default auth mechanism according to

import type { Document } from '../../bson';
import { AuthMechanism } from './defaultAuthProviders';
import { AuthMechanismId, AuthMechanism } from './defaultAuthProviders';

// https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst
function getDefaultAuthMechanism(ismaster?: Document): AuthMechanism {
function getDefaultAuthMechanism(ismaster?: Document): AuthMechanismId {
if (ismaster) {
// If ismaster contains saslSupportedMechs, use scram-sha-256
// if it is available, else scram-sha-1
if (Array.isArray(ismaster.saslSupportedMechs)) {
return ismaster.saslSupportedMechs.indexOf('SCRAM-SHA-256') >= 0
return ismaster.saslSupportedMechs.includes(AuthMechanism.MONGODB_SCRAM_SHA256)
? AuthMechanism.MONGODB_SCRAM_SHA256
: AuthMechanism.MONGODB_SCRAM_SHA1;
}
Expand All @@ -30,7 +30,7 @@ export interface MongoCredentialsOptions {
password: string;
source: string;
db?: string;
mechanism?: AuthMechanism;
mechanism?: AuthMechanismId;
mechanismProperties: Document;
}

Expand All @@ -46,7 +46,7 @@ export class MongoCredentials {
/** The database that the user should authenticate against */
readonly source: string;
/** The method used to authenticate */
readonly mechanism: AuthMechanism;
readonly mechanism: AuthMechanismId;
/** Special properties used by some types of auth mechanisms */
readonly mechanismProperties: Document;

Expand Down Expand Up @@ -108,4 +108,54 @@ export class MongoCredentials {

return this;
}

validate(): void {
if (
(this.mechanism === AuthMechanism.MONGODB_GSSAPI ||
this.mechanism === AuthMechanism.MONGODB_CR ||
this.mechanism === AuthMechanism.MONGODB_PLAIN ||
this.mechanism === AuthMechanism.MONGODB_SCRAM_SHA1 ||
this.mechanism === AuthMechanism.MONGODB_SCRAM_SHA256) &&
!this.username
) {
throw new TypeError(`Username required for mechanism '${this.mechanism}'`);
}

if (
this.mechanism === AuthMechanism.MONGODB_GSSAPI ||
this.mechanism === AuthMechanism.MONGODB_AWS ||
this.mechanism === AuthMechanism.MONGODB_X509
) {
if (this.source != null && this.source !== '$external') {
throw new TypeError(
`Invalid source '${this.source}' for mechanism '${this.mechanism}' specified.`
);
}
}

if (this.mechanism === AuthMechanism.MONGODB_PLAIN && this.source == null) {
throw new TypeError('PLAIN Authentication Mechanism needs an auth source');
}

if (this.mechanism === AuthMechanism.MONGODB_X509 && this.password != null) {
if (this.password === '') {
Reflect.set(this, 'password', undefined);
return;
}
throw new TypeError(`Password not allowed for mechanism MONGODB-X509`);
}
}

static merge(
creds: MongoCredentials,
options: Partial<MongoCredentialsOptions>
): MongoCredentials {
return new MongoCredentials({
username: options.username ?? creds.username,
password: options.password ?? creds.password,
mechanism: options.mechanism ?? creds.mechanism,
mechanismProperties: options.mechanismProperties ?? creds.mechanismProperties,
source: options.source ?? creds.source ?? options.db
});
Comment on lines +149 to +159
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mbroadst
Sorry about my git fu, I can't reply to your comment about the credentials issue. I've gone ahead with the merge solution, lmk what you think. For what its worth I think we were safe with the spread solution because typescript would not permit us to have a property missing, it just so happens that MongoCredentials and MongoCredentialOptions share all their properties and mandate that they are defined, but ofc better to be safe and box up more complex functionality, so .merge seems like a good solution .

}
}
4 changes: 3 additions & 1 deletion src/cmap/auth/scram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { MongoCredentials } from './mongo_credentials';
import type { HandshakeDocument } from '../connect';

import { saslprep } from '../../deps';
import { AuthMechanism } from './defaultAuthProviders';

type CryptoMethod = 'sha1' | 'sha256';

Expand Down Expand Up @@ -83,7 +84,8 @@ function makeFirstMessage(
nonce: Buffer
) {
const username = cleanUsername(credentials.username);
const mechanism = cryptoMethod === 'sha1' ? 'SCRAM-SHA-1' : 'SCRAM-SHA-256';
const mechanism =
cryptoMethod === 'sha1' ? AuthMechanism.MONGODB_SCRAM_SHA1 : AuthMechanism.MONGODB_SCRAM_SHA256;

// NOTE: This is done b/c Javascript uses UTF-16, but the server is hashing in UTF-8.
// Since the username is not sasl-prep-d, we need to do this here.
Expand Down
8 changes: 4 additions & 4 deletions src/cmap/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ import type { Server } from '../sdam/server';
import type { MongoCredentials } from './auth/mongo_credentials';
import type { CommandOptions } from './wire_protocol/command';
import type { GetMoreOptions } from './wire_protocol/get_more';
import type { InsertOptions, UpdateOptions, RemoveOptions } from './wire_protocol/index';
import type { Stream } from './connect';
import type { LoggerOptions } from '../logger';
import type { QueryOptions } from './wire_protocol/query';
import type { WriteCommandOptions } from './wire_protocol/write_command';

const kStream = Symbol('stream');
const kQueue = Symbol('queue');
Expand Down Expand Up @@ -280,17 +280,17 @@ export class Connection extends EventEmitter {
}

/** @internal */
insert(ns: string, ops: Document[], options: InsertOptions, callback: Callback): void {
insert(ns: string, ops: Document[], options: WriteCommandOptions, callback: Callback): void {
wp.insert(makeServerTrampoline(this), ns, ops, options, callback);
}

/** @internal */
update(ns: string, ops: Document[], options: UpdateOptions, callback: Callback): void {
update(ns: string, ops: Document[], options: WriteCommandOptions, callback: Callback): void {
wp.update(makeServerTrampoline(this), ns, ops, options, callback);
}

/** @internal */
remove(ns: string, ops: Document[], options: RemoveOptions, callback: Callback): void {
remove(ns: string, ops: Document[], options: WriteCommandOptions, callback: Callback): void {
wp.remove(makeServerTrampoline(this), ns, ops, options, callback);
}
}
Expand Down
15 changes: 3 additions & 12 deletions src/cmap/wire_protocol/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,31 @@ import type { Callback } from '../../utils';

export { writeCommand };

/** @internal */
export type InsertOptions = WriteCommandOptions;

export function insert(
server: Server,
ns: string,
ops: Document[],
options: InsertOptions,
options: WriteCommandOptions,
callback: Callback
): void {
writeCommand(server, 'insert', 'documents', ns, ops, options, callback);
}

/** @internal */
export type UpdateOptions = WriteCommandOptions;

export function update(
server: Server,
ns: string,
ops: Document[],
options: UpdateOptions,
options: WriteCommandOptions,
callback: Callback
): void {
writeCommand(server, 'update', 'updates', ns, ops, options, callback);
}

/** @internal */
export type RemoveOptions = WriteCommandOptions;

export function remove(
server: Server,
ns: string,
ops: Document[],
options: RemoveOptions,
options: WriteCommandOptions,
callback: Callback
): void {
writeCommand(server, 'delete', 'deletes', ns, ops, options, callback);
Expand Down
Loading