grpc-node/packages/grpc-js/test/test-certificate-provider.ts

156 lines
5.8 KiB
TypeScript

/*
* Copyright 2024 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import * as assert from 'assert';
import * as path from 'path';
import * as fs from 'fs/promises';
import { experimental } from '../src';
describe('Certificate providers', () => {
describe('File watcher', () => {
const [caPath, keyPath, certPath] = ['ca.pem', 'server1.key', 'server1.pem'].map(file => path.join(__dirname, 'fixtures', file));
let caData: Buffer, keyData: Buffer, certData: Buffer;
before(async () => {
[caData, keyData, certData] = await Promise.all([caPath, keyPath, certPath].map(filePath => fs.readFile(filePath)));
});
it('Should reject a config with no files', () => {
const config: experimental.FileWatcherCertificateProviderConfig = {
refreshIntervalMs: 1000
};
assert.throws(() => {
new experimental.FileWatcherCertificateProvider(config);
});
});
it('Should accept a config with just a CA certificate', () => {
const config: experimental.FileWatcherCertificateProviderConfig = {
caCertificateFile: caPath,
refreshIntervalMs: 1000
};
assert.doesNotThrow(() => {
new experimental.FileWatcherCertificateProvider(config);
});
});
it('Should accept a config with just a key and certificate', () => {
const config: experimental.FileWatcherCertificateProviderConfig = {
certificateFile: certPath,
privateKeyFile: keyPath,
refreshIntervalMs: 1000
};
assert.doesNotThrow(() => {
new experimental.FileWatcherCertificateProvider(config);
});
});
it('Should accept a config with all files', () => {
const config: experimental.FileWatcherCertificateProviderConfig = {
caCertificateFile: caPath,
certificateFile: certPath,
privateKeyFile: keyPath,
refreshIntervalMs: 1000
};
assert.doesNotThrow(() => {
new experimental.FileWatcherCertificateProvider(config);
});
});
it('Should reject a config with a key but no certificate', () => {
const config: experimental.FileWatcherCertificateProviderConfig = {
caCertificateFile: caPath,
privateKeyFile: keyPath,
refreshIntervalMs: 1000
};
assert.throws(() => {
new experimental.FileWatcherCertificateProvider(config);
});
});
it('Should reject a config with a certificate but no key', () => {
const config: experimental.FileWatcherCertificateProviderConfig = {
caCertificateFile: caPath,
privateKeyFile: keyPath,
refreshIntervalMs: 1000
};
assert.throws(() => {
new experimental.FileWatcherCertificateProvider(config);
});
});
it('Should find the CA file when configured for it', done => {
const config: experimental.FileWatcherCertificateProviderConfig = {
caCertificateFile: caPath,
refreshIntervalMs: 1000
};
const provider = new experimental.FileWatcherCertificateProvider(config);
const listener: experimental.CaCertificateUpdateListener = update => {
if (update) {
provider.removeCaCertificateListener(listener);
assert(update.caCertificate.equals(caData));
done();
}
};
provider.addCaCertificateListener(listener);
});
it('Should find the identity certificate files when configured for it', done => {
const config: experimental.FileWatcherCertificateProviderConfig = {
certificateFile: certPath,
privateKeyFile: keyPath,
refreshIntervalMs: 1000
};
const provider = new experimental.FileWatcherCertificateProvider(config);
const listener: experimental.IdentityCertificateUpdateListener = update => {
if (update) {
provider.removeIdentityCertificateListener(listener);
assert(update.certificate.equals(certData));
assert(update.privateKey.equals(keyData));
done();
}
};
provider.addIdentityCertificateListener(listener);
});
it('Should find all files when configured for it', done => {
const config: experimental.FileWatcherCertificateProviderConfig = {
caCertificateFile: caPath,
certificateFile: certPath,
privateKeyFile: keyPath,
refreshIntervalMs: 1000
};
const provider = new experimental.FileWatcherCertificateProvider(config);
let seenCaUpdate = false;
let seenIdentityUpdate = false;
const caListener: experimental.CaCertificateUpdateListener = update => {
if (update) {
provider.removeCaCertificateListener(caListener);
assert(update.caCertificate.equals(caData));
seenCaUpdate = true;
if (seenIdentityUpdate) {
done();
}
}
};
const identityListener: experimental.IdentityCertificateUpdateListener = update => {
if (update) {
provider.removeIdentityCertificateListener(identityListener);
assert(update.certificate.equals(certData));
assert(update.privateKey.equals(keyData));
seenIdentityUpdate = true;
if (seenCaUpdate) {
done();
}
}
};
provider.addCaCertificateListener(caListener);
provider.addIdentityCertificateListener(identityListener);
});
});
});