mirror of https://github.com/grpc/grpc-node.git
grpc-js: add ServerCredentials support
This commit adds ServerCredentials to the pure JS implementation.
This commit is contained in:
parent
f345593d1d
commit
40eef7af22
|
@ -27,6 +27,7 @@ import {LogVerbosity, Status} from './constants';
|
|||
import * as logging from './logging';
|
||||
import {Deserialize, loadPackageDefinition, makeClientConstructor, Serialize} from './make-client';
|
||||
import {Metadata} from './metadata';
|
||||
import {KeyCertPair, ServerCredentials} from './server-credentials';
|
||||
import {StatusBuilder} from './status-builder';
|
||||
|
||||
const supportedNodeVersions = '^8.11.2 || >=9.4';
|
||||
|
@ -226,15 +227,9 @@ export const Server = (options: any) => {
|
|||
throw new Error('Not yet implemented');
|
||||
};
|
||||
|
||||
export const ServerCredentials = {
|
||||
createSsl:
|
||||
(rootCerts: any, keyCertPairs: any, checkClientCertificate: any) => {
|
||||
throw new Error('Not yet implemented');
|
||||
},
|
||||
createInsecure: () => {
|
||||
throw new Error('Not yet implemented');
|
||||
}
|
||||
};
|
||||
export {ServerCredentials};
|
||||
export {KeyCertPair};
|
||||
|
||||
|
||||
export const getClientChannel = (client: Client) => {
|
||||
return Client.prototype.getChannel.call(client);
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2019 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 {SecureServerOptions} from 'http2';
|
||||
|
||||
|
||||
export type KeyCertPair = {
|
||||
private_key: Buffer,
|
||||
cert_chain: Buffer
|
||||
};
|
||||
|
||||
|
||||
export abstract class ServerCredentials {
|
||||
abstract _isSecure(): boolean;
|
||||
abstract _getSettings(): SecureServerOptions|null;
|
||||
|
||||
static createInsecure(): ServerCredentials {
|
||||
return new InsecureServerCredentials();
|
||||
}
|
||||
|
||||
static createSsl(
|
||||
rootCerts: Buffer|null, keyCertPairs: KeyCertPair[],
|
||||
checkClientCertificate = false): ServerCredentials {
|
||||
if (rootCerts !== null && !Buffer.isBuffer(rootCerts)) {
|
||||
throw new TypeError('rootCerts must be null or a Buffer');
|
||||
}
|
||||
|
||||
if (!Array.isArray(keyCertPairs)) {
|
||||
throw new TypeError('keyCertPairs must be an array');
|
||||
}
|
||||
|
||||
if (typeof checkClientCertificate !== 'boolean') {
|
||||
throw new TypeError('checkClientCertificate must be a boolean');
|
||||
}
|
||||
|
||||
const cert = [];
|
||||
const key = [];
|
||||
|
||||
for (let i = 0; i < keyCertPairs.length; i++) {
|
||||
const pair = keyCertPairs[i];
|
||||
|
||||
if (pair === null || typeof pair !== 'object') {
|
||||
throw new TypeError(`keyCertPair[${i}] must be an object`);
|
||||
}
|
||||
|
||||
if (!Buffer.isBuffer(pair.private_key)) {
|
||||
throw new TypeError(`keyCertPair[${i}].private_key must be a Buffer`);
|
||||
}
|
||||
|
||||
if (!Buffer.isBuffer(pair.cert_chain)) {
|
||||
throw new TypeError(`keyCertPair[${i}].cert_chain must be a Buffer`);
|
||||
}
|
||||
|
||||
cert.push(pair.cert_chain);
|
||||
key.push(pair.private_key);
|
||||
}
|
||||
|
||||
return new SecureServerCredentials({
|
||||
ca: rootCerts || undefined,
|
||||
cert,
|
||||
key,
|
||||
requestCert: checkClientCertificate
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class InsecureServerCredentials extends ServerCredentials {
|
||||
_isSecure(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
_getSettings(): null {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SecureServerCredentials extends ServerCredentials {
|
||||
private options: SecureServerOptions;
|
||||
|
||||
constructor(options: SecureServerOptions) {
|
||||
super();
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
_isSecure(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
_getSettings(): SecureServerOptions {
|
||||
return this.options;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright 2019 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// Allow `any` data type for testing runtime type checking.
|
||||
// tslint:disable no-any
|
||||
import * as assert from 'assert';
|
||||
import {readFileSync} from 'fs';
|
||||
import {join} from 'path';
|
||||
import {ServerCredentials} from '../src';
|
||||
|
||||
const ca = readFileSync(join(__dirname, 'fixtures', 'ca.pem'));
|
||||
const key = readFileSync(join(__dirname, 'fixtures', 'server1.key'));
|
||||
const cert = readFileSync(join(__dirname, 'fixtures', 'server1.pem'));
|
||||
|
||||
describe('Server Credentials', () => {
|
||||
describe('createInsecure', () => {
|
||||
it('creates insecure credentials', () => {
|
||||
const creds = ServerCredentials.createInsecure();
|
||||
|
||||
assert.strictEqual(creds._isSecure(), false);
|
||||
assert.strictEqual(creds._getSettings(), null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createSsl', () => {
|
||||
it('accepts a buffer and array as the first two arguments', () => {
|
||||
const creds = ServerCredentials.createSsl(ca, []);
|
||||
|
||||
assert.strictEqual(creds._isSecure(), true);
|
||||
assert.deepStrictEqual(
|
||||
creds._getSettings(), {ca, cert: [], key: [], requestCert: false});
|
||||
});
|
||||
|
||||
it('accepts a boolean as the third argument', () => {
|
||||
const creds = ServerCredentials.createSsl(ca, [], true);
|
||||
|
||||
assert.strictEqual(creds._isSecure(), true);
|
||||
assert.deepStrictEqual(
|
||||
creds._getSettings(), {ca, cert: [], key: [], requestCert: true});
|
||||
});
|
||||
|
||||
it('accepts an object with two buffers in the second argument', () => {
|
||||
const keyCertPairs = [{private_key: key, cert_chain: cert}];
|
||||
const creds = ServerCredentials.createSsl(null, keyCertPairs);
|
||||
|
||||
assert.strictEqual(creds._isSecure(), true);
|
||||
assert.deepStrictEqual(
|
||||
creds._getSettings(),
|
||||
{ca: undefined, cert: [cert], key: [key], requestCert: false});
|
||||
});
|
||||
|
||||
it('accepts multiple objects in the second argument', () => {
|
||||
const keyCertPairs = [
|
||||
{private_key: key, cert_chain: cert},
|
||||
{private_key: key, cert_chain: cert}
|
||||
];
|
||||
const creds = ServerCredentials.createSsl(null, keyCertPairs, false);
|
||||
|
||||
assert.strictEqual(creds._isSecure(), true);
|
||||
assert.deepStrictEqual(creds._getSettings(), {
|
||||
ca: undefined,
|
||||
cert: [cert, cert],
|
||||
key: [key, key],
|
||||
requestCert: false
|
||||
});
|
||||
});
|
||||
|
||||
it('fails if the second argument is not an Array', () => {
|
||||
assert.throws(() => {
|
||||
ServerCredentials.createSsl(ca, 'test' as any);
|
||||
}, /TypeError: keyCertPairs must be an array/);
|
||||
});
|
||||
|
||||
it('fails if the first argument is a non-Buffer value', () => {
|
||||
assert.throws(() => {
|
||||
ServerCredentials.createSsl('test' as any, []);
|
||||
}, /TypeError: rootCerts must be null or a Buffer/);
|
||||
});
|
||||
|
||||
it('fails if the third argument is a non-boolean value', () => {
|
||||
assert.throws(() => {
|
||||
ServerCredentials.createSsl(ca, [], 'test' as any);
|
||||
}, /TypeError: checkClientCertificate must be a boolean/);
|
||||
});
|
||||
|
||||
it('fails if the array elements are not objects', () => {
|
||||
assert.throws(() => {
|
||||
ServerCredentials.createSsl(ca, ['test'] as any);
|
||||
}, /TypeError: keyCertPair\[0\] must be an object/);
|
||||
|
||||
assert.throws(() => {
|
||||
ServerCredentials.createSsl(ca, [null] as any);
|
||||
}, /TypeError: keyCertPair\[0\] must be an object/);
|
||||
});
|
||||
|
||||
it('fails if the object does not have a Buffer private key', () => {
|
||||
const keyCertPairs: any = [{private_key: 'test', cert_chain: cert}];
|
||||
|
||||
assert.throws(() => {
|
||||
ServerCredentials.createSsl(null, keyCertPairs);
|
||||
}, /TypeError: keyCertPair\[0\].private_key must be a Buffer/);
|
||||
});
|
||||
|
||||
it('fails if the object does not have a Buffer cert chain', () => {
|
||||
const keyCertPairs: any = [{private_key: key, cert_chain: 'test'}];
|
||||
|
||||
assert.throws(() => {
|
||||
ServerCredentials.createSsl(null, keyCertPairs);
|
||||
}, /TypeError: keyCertPair\[0\].cert_chain must be a Buffer/);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue