Spaces:
Runtime error
Runtime error
File size: 6,238 Bytes
9756872 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | "use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoDBAWS = void 0;
const BSON = require("../../bson");
const deps_1 = require("../../deps");
const error_1 = require("../../error");
const utils_1 = require("../../utils");
const auth_provider_1 = require("./auth_provider");
const aws_temporary_credentials_1 = require("./aws_temporary_credentials");
const mongo_credentials_1 = require("./mongo_credentials");
const providers_1 = require("./providers");
const ASCII_N = 110;
const bsonOptions = {
useBigInt64: false,
promoteLongs: true,
promoteValues: true,
promoteBuffers: false,
bsonRegExp: false
};
class MongoDBAWS extends auth_provider_1.AuthProvider {
constructor() {
super();
this.credentialFetcher = aws_temporary_credentials_1.AWSTemporaryCredentialProvider.isAWSSDKInstalled
? new aws_temporary_credentials_1.AWSSDKCredentialProvider()
: new aws_temporary_credentials_1.LegacyAWSTemporaryCredentialProvider();
}
async auth(authContext) {
const { connection } = authContext;
if (!authContext.credentials) {
throw new error_1.MongoMissingCredentialsError('AuthContext must provide credentials.');
}
if ('kModuleError' in deps_1.aws4) {
throw deps_1.aws4['kModuleError'];
}
const { sign } = deps_1.aws4;
if ((0, utils_1.maxWireVersion)(connection) < 9) {
throw new error_1.MongoCompatibilityError('MONGODB-AWS authentication requires MongoDB version 4.4 or later');
}
if (!authContext.credentials.username) {
authContext.credentials = await makeTempCredentials(authContext.credentials, this.credentialFetcher);
}
const { credentials } = authContext;
const accessKeyId = credentials.username;
const secretAccessKey = credentials.password;
// Allow the user to specify an AWS session token for authentication with temporary credentials.
const sessionToken = credentials.mechanismProperties.AWS_SESSION_TOKEN;
// If all three defined, include sessionToken, else include username and pass, else no credentials
const awsCredentials = accessKeyId && secretAccessKey && sessionToken
? { accessKeyId, secretAccessKey, sessionToken }
: accessKeyId && secretAccessKey
? { accessKeyId, secretAccessKey }
: undefined;
const db = credentials.source;
const nonce = await (0, utils_1.randomBytes)(32);
// All messages between MongoDB clients and servers are sent as BSON objects
// in the payload field of saslStart and saslContinue.
const saslStart = {
saslStart: 1,
mechanism: 'MONGODB-AWS',
payload: BSON.serialize({ r: nonce, p: ASCII_N }, bsonOptions)
};
const saslStartResponse = await connection.command((0, utils_1.ns)(`${db}.$cmd`), saslStart, undefined);
const serverResponse = BSON.deserialize(saslStartResponse.payload.buffer, bsonOptions);
const host = serverResponse.h;
const serverNonce = serverResponse.s.buffer;
if (serverNonce.length !== 64) {
// TODO(NODE-3483)
throw new error_1.MongoRuntimeError(`Invalid server nonce length ${serverNonce.length}, expected 64`);
}
if (!utils_1.ByteUtils.equals(serverNonce.subarray(0, nonce.byteLength), nonce)) {
// throw because the serverNonce's leading 32 bytes must equal the client nonce's 32 bytes
// https://github.com/mongodb/specifications/blob/875446db44aade414011731840831f38a6c668df/source/auth/auth.rst#id11
// TODO(NODE-3483)
throw new error_1.MongoRuntimeError('Server nonce does not begin with client nonce');
}
if (host.length < 1 || host.length > 255 || host.indexOf('..') !== -1) {
// TODO(NODE-3483)
throw new error_1.MongoRuntimeError(`Server returned an invalid host: "${host}"`);
}
const body = 'Action=GetCallerIdentity&Version=2011-06-15';
const options = sign({
method: 'POST',
host,
region: deriveRegion(serverResponse.h),
service: 'sts',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': body.length,
'X-MongoDB-Server-Nonce': utils_1.ByteUtils.toBase64(serverNonce),
'X-MongoDB-GS2-CB-Flag': 'n'
},
path: '/',
body
}, awsCredentials);
const payload = {
a: options.headers.Authorization,
d: options.headers['X-Amz-Date']
};
if (sessionToken) {
payload.t = sessionToken;
}
const saslContinue = {
saslContinue: 1,
conversationId: 1,
payload: BSON.serialize(payload, bsonOptions)
};
await connection.command((0, utils_1.ns)(`${db}.$cmd`), saslContinue, undefined);
}
}
exports.MongoDBAWS = MongoDBAWS;
async function makeTempCredentials(credentials, awsCredentialFetcher) {
function makeMongoCredentialsFromAWSTemp(creds) {
// The AWS session token (creds.Token) may or may not be set.
if (!creds.AccessKeyId || !creds.SecretAccessKey) {
throw new error_1.MongoMissingCredentialsError('Could not obtain temporary MONGODB-AWS credentials');
}
return new mongo_credentials_1.MongoCredentials({
username: creds.AccessKeyId,
password: creds.SecretAccessKey,
source: credentials.source,
mechanism: providers_1.AuthMechanism.MONGODB_AWS,
mechanismProperties: {
AWS_SESSION_TOKEN: creds.Token
}
});
}
const temporaryCredentials = await awsCredentialFetcher.getCredentials();
return makeMongoCredentialsFromAWSTemp(temporaryCredentials);
}
function deriveRegion(host) {
const parts = host.split('.');
if (parts.length === 1 || parts[1] === 'amazonaws') {
return 'us-east-1';
}
return parts[1];
}
//# sourceMappingURL=mongodb_aws.js.map |