mirror of https://github.com/mongodb/mongo
193 lines
5.7 KiB
JavaScript
193 lines
5.7 KiB
JavaScript
/**
|
|
* Starts a mock OCSP Server to test
|
|
* OCSP certificate revocation.
|
|
*/
|
|
import {getPython3Binary} from "jstests/libs/python.js";
|
|
import {
|
|
OCSP_CA_CERT,
|
|
OCSP_CA_KEY,
|
|
OCSP_CA_PEM,
|
|
OCSP_INTERMEDIATE_CA_ONLY_CERT,
|
|
OCSP_INTERMEDIATE_CA_ONLY_KEY,
|
|
OCSP_INTERMEDIATE_CA_WITH_ROOT_PEM,
|
|
OCSP_RESPONDER_CERT,
|
|
OCSP_RESPONDER_KEY,
|
|
} from "jstests/ocsp/lib/ocsp_helpers.js";
|
|
|
|
// These are a list of faults to match the list of faults
|
|
// in ocsp_mock.py.
|
|
export const FAULT_REVOKED = "revoked";
|
|
|
|
export const FAULT_UNKNOWN = "unknown";
|
|
export const OCSP_PROGRAM = "jstests/ocsp/lib/ocsp_mock.py";
|
|
|
|
export class ResponderCertSet {
|
|
/**
|
|
* Set of certificates for the OCSP responder.'
|
|
* @param {string} cafile
|
|
* @param {string} certfile
|
|
* @param {string} keyfile
|
|
*/
|
|
constructor(cafile, certfile, keyfile) {
|
|
this.cafile = cafile;
|
|
this.certfile = certfile;
|
|
this.keyfile = keyfile;
|
|
}
|
|
}
|
|
|
|
export const OCSP_DELEGATE_RESPONDER = new ResponderCertSet(OCSP_CA_PEM, OCSP_RESPONDER_CERT, OCSP_RESPONDER_KEY);
|
|
|
|
export const OCSP_CA_RESPONDER = new ResponderCertSet(OCSP_CA_PEM, OCSP_CA_CERT, OCSP_CA_KEY);
|
|
|
|
export const OCSP_INTERMEDIATE_RESPONDER = new ResponderCertSet(
|
|
OCSP_INTERMEDIATE_CA_WITH_ROOT_PEM,
|
|
OCSP_INTERMEDIATE_CA_ONLY_CERT,
|
|
OCSP_INTERMEDIATE_CA_ONLY_KEY,
|
|
);
|
|
|
|
export class MockOCSPServer {
|
|
/**
|
|
* Create a new OCSP Server.
|
|
*
|
|
* @param {string} fault_type
|
|
* @param {number} next_update_secs
|
|
* @param {object} responder_certificate_set
|
|
*/
|
|
constructor(
|
|
fault_type,
|
|
next_update_secs,
|
|
responder_certificate_set = OCSP_DELEGATE_RESPONDER,
|
|
response_delay_secs = 0,
|
|
include_extraneous_status = false,
|
|
issuer_hash_algorithm = "",
|
|
) {
|
|
this.python = getPython3Binary();
|
|
this.fault_type = fault_type;
|
|
|
|
this.ca_file = responder_certificate_set.cafile;
|
|
this.ocsp_cert_file = responder_certificate_set.certfile;
|
|
this.ocsp_cert_key = responder_certificate_set.keyfile;
|
|
|
|
print("Using python interpreter: " + this.python);
|
|
// The port must be hard coded to match the port of the
|
|
// responder in the certificates.
|
|
this.port = 8100;
|
|
this.next_update_secs = next_update_secs;
|
|
this.response_delay_secs = response_delay_secs;
|
|
this.include_extraneous_status = include_extraneous_status;
|
|
this.issuer_hash_algorithm = issuer_hash_algorithm;
|
|
}
|
|
|
|
start() {
|
|
print("Mock OCSP Server will listen on port: " + this.port);
|
|
let args = [
|
|
this.python,
|
|
"-u",
|
|
OCSP_PROGRAM,
|
|
"--port=" + this.port,
|
|
"--ca_file=" + this.ca_file,
|
|
"--ocsp_responder_cert=" + this.ocsp_cert_file,
|
|
"--ocsp_responder_key=" + this.ocsp_cert_key,
|
|
"--verbose",
|
|
];
|
|
|
|
if (this.fault_type) {
|
|
args.push("--fault=" + this.fault_type);
|
|
}
|
|
|
|
if (this.next_update_secs || this.next_update_secs === 0) {
|
|
args.push("--next_update_seconds=" + this.next_update_secs);
|
|
}
|
|
|
|
if (this.response_delay_secs) {
|
|
args.push("--response_delay_seconds=" + this.response_delay_secs);
|
|
}
|
|
|
|
if (this.include_extraneous_status) {
|
|
args.push("--include_extraneous_status");
|
|
}
|
|
|
|
if (this.issuer_hash_algorithm) {
|
|
args.push("--issuer_hash_algorithm=" + this.issuer_hash_algorithm);
|
|
}
|
|
|
|
const MAX_ATTEMPTS = 10;
|
|
let backoff_ms = 1000;
|
|
let portInUse = false;
|
|
for (let attempts = 0; attempts < MAX_ATTEMPTS; attempts++) {
|
|
clearRawMongoProgramOutput();
|
|
|
|
const pid = _startMongoProgram({args: args});
|
|
assert(checkProgram(pid).alive);
|
|
|
|
portInUse = false;
|
|
assert.soon(function () {
|
|
// Change this line if the OCSP endpoint changes
|
|
let output = rawMongoProgramOutput(".*");
|
|
portInUse = output.search("Address already in use") !== -1;
|
|
return portInUse || output.search("Running on http") !== -1;
|
|
});
|
|
|
|
if (!portInUse) {
|
|
this.pid = pid;
|
|
break;
|
|
}
|
|
|
|
assert.soon(function () {
|
|
return !checkProgram(pid).alive;
|
|
});
|
|
print(`Retrying OCSP mock responder startup after ${backoff_ms / 1000} seconds.`);
|
|
sleep(backoff_ms);
|
|
backoff_ms *= 2;
|
|
}
|
|
|
|
assert(!portInUse);
|
|
sleep(2000);
|
|
}
|
|
|
|
/**
|
|
* Get the URL.
|
|
*
|
|
* @return {string} url of http server
|
|
*/
|
|
getURL() {
|
|
return "http://localhost:" + this.port;
|
|
}
|
|
|
|
/**
|
|
* Stop the web server
|
|
*/
|
|
stop() {
|
|
if (!this.pid) {
|
|
print("Not stopping Mock OCSP Server, it was never started");
|
|
return;
|
|
}
|
|
|
|
print("Stopping Mock OCSP Server");
|
|
|
|
if (_isWindows()) {
|
|
// we use taskkill because we need to kill children
|
|
waitProgram(_startMongoProgram("taskkill", "/F", "/T", "/PID", this.pid));
|
|
// waitProgram to ignore error code
|
|
waitProgram(this.pid);
|
|
} else {
|
|
const kSIGINT = 2;
|
|
stopMongoProgramByPid(this.pid, kSIGINT);
|
|
|
|
for (let i = 0; i < 50; i++) {
|
|
if (!checkProgram(this.pid).alive) {
|
|
print("Mock OCSP Server stop complete");
|
|
return;
|
|
}
|
|
sleep(100);
|
|
}
|
|
|
|
// Mock could be caught in a hang, force terminate it
|
|
const kSIGKILL = 9;
|
|
stopMongoProgramByPid(this.pid, kSIGKILL);
|
|
}
|
|
|
|
print("Mock OCSP Server stop complete");
|
|
}
|
|
}
|