Skip to content

Commit

Permalink
[FAB-4131] Enhance FabricCAClientImpl with persistence
Browse files Browse the repository at this point in the history
The ability to construct KeyValueStore objects is missing from
this package. as a result the application is not able to solely
use fabric-ca-client to handle user object persistence (which
requires a KeyValueStore instance)

Also cleaned up logging in SDK and test code to use debug
statements instead of info, and save debug logs in a file

Change-Id: I2d908303bd8ec74058b689526894c79eab4144ae
Signed-off-by: Jim Zhang <jzhang@us.ibm.com>
  • Loading branch information
jimthematrix committed Jun 2, 2017
1 parent a494295 commit f306afe
Show file tree
Hide file tree
Showing 68 changed files with 812 additions and 898 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ fabric-ca-client/node_modules/*
examples/balance-transfer/node_modules/*
fabric-ca-client/lib/api.js
fabric-ca-client/lib/utils.js
fabric-ca-client/lib/BaseClient.js
fabric-ca-client/lib/Config.js
fabric-ca-client/lib/Remote.js
fabric-ca-client/lib/User.js
fabric-ca-client/lib/msp/*
fabric-ca-client/lib/protos/*
fabric-ca-client/lib/hash.js
fabric-ca-client/lib/impl/*
npm-shrinkwrap.json
Expand Down
8 changes: 7 additions & 1 deletion build/tasks/ca.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ const DEPS = [
'fabric-client/lib/api.js',
'fabric-client/lib/hash.js',
'fabric-client/lib/utils.js',
'fabric-client/lib/BaseClient.js',
'fabric-client/lib/Config.js',
'fabric-client/lib/Remote.js',
'fabric-client/lib/User.js',
'fabric-client/lib/impl/CouchDBKeyValueStore.js',
'fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js',
'fabric-client/lib/impl/ecdsa/*',
'fabric-client/lib/impl/CryptoKeyStore.js',
'fabric-client/lib/impl/FileKeyValueStore.js'
'fabric-client/lib/impl/FileKeyValueStore.js',
'fabric-client/lib/msp/identity.js',
'fabric-client/lib/msp/msp.js',
'fabric-client/lib/protos/msp/identities.proto',
'fabric-client/lib/protos/msp/msp_config.proto'
];

gulp.task('ca', function() {
Expand Down
31 changes: 10 additions & 21 deletions build/tasks/doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,20 @@

var gulp = require('gulp');
var jsdoc = require('gulp-jsdoc3');
var del = require('del');

gulp.task('doc', function () {
gulp.task('clean', function(){
return del('./docs/gen/**', {force:true});
});

gulp.task('doc', ['clean'], function () {
gulp.src([
'docs/index.md',
'fabric-client/index.js',
'fabric-client/lib/api.js',
'fabric-client/lib/impl/FileKeyValueStore.js',
'fabric-client/lib/impl/CouchDBKeyValueStore.js',
'fabric-client/lib/impl/CryptoKeyStore.js',
'fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js',
'fabric-client/lib/impl/ecdsa/key.js',
'fabric-client/lib/impl/bccsp_pkcs11.js',
'fabric-client/lib/impl/ecdsa/*',
'fabric-client/lib/impl/aes/*',
'fabric-client/lib/BlockDecoder.js',
'fabric-client/lib/msp/msp.js',
'fabric-client/lib/Channel.js',
'fabric-client/lib/Orderer.js',
'fabric-client/lib/Peer.js',
'fabric-client/lib/Policy.js',
'fabric-client/lib/User.js',
'fabric-client/lib/Client.js',
'fabric-client/lib/EventHub.js',
'fabric-client/lib/Remote.js',
'fabric-client/lib/X509Certificate.js',
'fabric-client/lib/**/*.js',
'!fabric-client/lib/protos/**',
'!fabric-client/lib/hash.js',
'!fabric-client/lib/utils.js',
'fabric-ca-client/index.js',
'fabric-ca-client/lib/FabricCAClientImpl.js'
], { read: false })
Expand Down
1 change: 1 addition & 0 deletions build/tasks/eslint.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ gulp.task('lint', function () {
'fabric-client/**/*.js',
'fabric-ca-client/lib/*.js',
'examples/**/*.js',
'!examples/balance-transfer/node_modules/**',
'!node_modules/**',
'!fabric-client/node_modules/**',
'!fabric-ca-client/node_modules/**',
Expand Down
25 changes: 22 additions & 3 deletions build/tasks/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@ var gulp = require('gulp');
var tape = require('gulp-tape');
var tapColorize = require('tap-colorize');
var istanbul = require('gulp-istanbul');
var addsrc = require('gulp-add-src');

var fs = require('fs-extra');
var path = require('path');
var os = require('os');
var util = require('util');
var shell = require('gulp-shell');
var testConstants = require('../../test/unit/constants.js');

// by default for running the tests print debug to a file
var debugPath = path.join(testConstants.tempdir, 'test-log/debug.log');
process.env.HFC_LOGGING = util.format('{"debug":"%s"}', debugPath);
console.log('\n####################################################');
console.log(util.format('# debug log: %s', debugPath));
console.log('####################################################\n');

gulp.task('pre-test', function() {
return gulp.src([
'node_modules/fabric-client/lib/**/*.js',
Expand All @@ -21,7 +31,8 @@ gulp.task('pre-test', function() {
gulp.task('clean-up', function() {
// some tests create temporary files or directories
// they are all created in the same temp folder
return fs.removeSync(testConstants.tempdir);
fs.removeSync(testConstants.tempdir);
return fs.ensureFileSync(debugPath);
});

gulp.task('docker-clean', shell.task([
Expand All @@ -47,16 +58,17 @@ gulp.task('test', ['clean-up', 'lint', 'docker-clean', 'pre-test', 'ca'], functi
'test/unit/**/*.js',
'!test/unit/constants.js',
'!test/unit/util.js',
'!test/unit/logger.js',
'test/integration/e2e.js',
'test/integration/query.js',
'test/integration/fabric-ca-services-tests.js',
'test/integration/client.js',
'test/integration/orderer-channel-tests.js',
'test/integration/cloudant-fabricca-tests.js',
'test/integration/couchdb-fabricca-tests.js',
'test/integration/fileKeyValueStore-fabricca-tests.js',
'test/integration/e2e.js',
'test/integration/install.js',
'test/integration/events.js',
'test/integration/query.js',
'test/integration/upgrade.js',
'test/integration/get-config.js',
'test/integration/create-configtx-channel.js',
Expand All @@ -66,6 +78,9 @@ gulp.task('test', ['clean-up', 'lint', 'docker-clean', 'pre-test', 'ca'], functi
'test/integration/e2e/query.js',
'test/integration/grpc.js'
]))
.pipe(addsrc.append(
'test/unit/logger.js' // put this to the last so the debugging levels are not mixed up
))
.pipe(tape({
reporter: tapColorize()
}))
Expand All @@ -85,7 +100,11 @@ gulp.task('test-headless', ['clean-up', 'lint', 'pre-test', 'ca'], function() {
'test/unit/**/*.js',
'!test/unit/constants.js',
'!test/unit/util.js',
'!test/unit/logger.js'
]))
.pipe(addsrc.append(
'test/unit/logger.js' // put this to the last so the debugging levels are not mixed up
))
.pipe(tape({
reporter: tapColorize()
}))
Expand Down
74 changes: 13 additions & 61 deletions fabric-ca-client/lib/FabricCAClientImpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

var api = require('./api.js');
var utils = require('./utils.js');
var BaseClient = require('./BaseClient.js');
var util = require('util');
var path = require('path');
var http = require('http');
Expand All @@ -36,8 +37,9 @@ var logger = utils.getLogger('FabricCAClientImpl.js');
/**
* This is an implementation of the member service client which communicates with the Fabric CA server.
* @class
* @extends BaseClient
*/
var FabricCAServices = class {
var FabricCAServices = class extends BaseClient {

/**
* constructor
Expand All @@ -57,14 +59,15 @@ var FabricCAServices = class {
* such as a file-based store or a database-based one. The specific implementation is determined by the value of this configuration setting.
*/
constructor(url, tlsOptions, caName, cryptoSuite) {
super();

var endpoint = FabricCAServices._parseURL(url);

if (!!cryptoSuite) {
this.cryptoPrimitives = cryptoSuite;
this.setCryptoSuite(cryptoSuite);
} else {
this.cryptoPrimitives = utils.newCryptoSuite();
this.cryptoPrimitives.setCryptoKeyStore(utils.newCryptoKeyStore());
this.setCryptoSuite(utils.newCryptoSuite());
this.getCryptoSuite().setCryptoKeyStore(utils.newCryptoKeyStore());
}

this._fabricCAClient = new FabricCAClient({
Expand All @@ -73,63 +76,12 @@ var FabricCAServices = class {
hostname: endpoint.hostname,
port: endpoint.port,
tlsOptions: tlsOptions
}, this.cryptoPrimitives);
}, this.getCryptoSuite());

logger.info('Successfully constructed Fabric CA service client: endpoint - %j', endpoint);
logger.debug('Successfully constructed Fabric CA service client: endpoint - %j', endpoint);

}

/**
* Returns a new instance of the CryptoSuite API implementation
*
* If not specified, an instance of {@link CryptoSuite} will be constructed based on the current configuration settings:
* <br> - crypto-hsm: use an implementation for Hardware Security Module (if set to true) or software-based key management (if set to false)
* <br> - crypto-keysize: security level, or key size, to use with the digital signature public key algorithm. Currently ECDSA
* is supported and the valid key sizes are 256 and 384
* <br> - crypto-hash-algo: hashing algorithm
* <br> - key-value-store: some CryptoSuite implementation requires a key store to persist private keys. A {@link CryptoKeyStore}
* is provided for this purpose, which can be used on top of any implementation of the {@link KeyValueStore} interface,
* such as a file-based store or a database-based one. The specific implementation is determined by the value of this configuration setting.
*
* @param {object} setting This optional parameter is an object with the following optional properties:
* <br> - software {boolean}: Whether to load a software-based implementation (true) or HSM implementation (false)
* default is true (for software based implementation), specific implementation module is specified
* in the setting 'crypto-suite-software'
* <br> - keysize {number}: The key size to use for the crypto suite instance. default is value of the setting 'crypto-keysize'
* <br> - algorithm {string}: Digital signature algorithm, currently supporting ECDSA only with value "EC"
* <br> - hash {string}: 'SHA2' or 'SHA3'
* @param {function} KVSImplClass Optional. The built-in key store saves private keys. The key store may be backed by different
* {@link KeyValueStore} implementations. If specified, the value of the argument must point to a module implementing the
* KeyValueStore interface.
* @param {object} opts Implementation-specific option object used in the constructor
* @returns a new instance of the CryptoSuite API implementation
*/
static newCryptoSuite(setting, KVSImplClass, opts) {
return utils.newCryptoSuite(setting, KVSImplClass, opts);
}

getCrypto() {
return this.cryptoPrimitives;
}

/**
* Returns a new instance of the CryptoKeyStore.
*
* When the application needs to use a key store other than the default,
* it should create a new CryptoKeyStore and set it on the CryptoSuite.
*
* <br><br><code>cryptosuite.setCryptoKeyStore(CAClient.newCryptoKeyStore(KVSImplClass, opts))</code>
*
* @param {function} KVSImplClass Optional. The built-in key store saves private keys. The key store may be backed by different
* {@link KeyValueStore} implementations. If specified, the value of the argument must point to a module implementing the
* KeyValueStore interface.
* @param {object} opts Implementation-specific option object used in the constructor
* @returns a new instance of the CryptoKeystore
*/
static newCryptoKeyStore (KVSImplClass, opts) {
return utils.newCryptoKeyStore(KVSImplClass, opts);
}

/**
* Register the member and return an enrollment secret.
* @param {Object} req Registration request with the following fields:
Expand Down Expand Up @@ -193,12 +145,12 @@ var FabricCAServices = class {

//generate enrollment certificate pair for signing
var opts;
if (self.cryptoPrimitives._cryptoKeyStore) {
if (self.getCryptoSuite()._cryptoKeyStore) {
opts = {ephemeral: false};
} else {
opts = {ephemeral: true};
}
self.cryptoPrimitives.generateKey(opts)
self.getCryptoSuite().generateKey(opts)
.then(
function (privateKey) {
//generate CSR using enrollmentID for the subject
Expand Down Expand Up @@ -270,7 +222,7 @@ var FabricCAServices = class {

return new Promise(function (resolve, reject) {
//generate enrollment certificate pair for signing
self.cryptoPrimitives.generateKey()
self.getCryptoSuite().generateKey()
.then(
function (privateKey) {
//generate CSR using the subject of the current user's certificate
Expand Down Expand Up @@ -471,7 +423,7 @@ var FabricCAClient = class {

this._cryptoPrimitives = cryptoPrimitives;

logger.info('Successfully constructed Fabric CA client from options - %j', connect_opts);
logger.debug('Successfully constructed Fabric CA client from options - %j', connect_opts);
}

/**
Expand Down
Loading

0 comments on commit f306afe

Please sign in to comment.