Skip to content

Commit

Permalink
[FAB-2760] Update fabric-ca-client
Browse files Browse the repository at this point in the history
Several of the fabric-ca APIs were changed and
fabric-ca-client had not been updated. The following
changes were made:

- fix the register API
- fix the enroll API
- modify the revoke API to to prepend a 0 to the
hex string for the serial number to match the
fabric-ca
- updated integration tests to work with current
fabric-ca master

Change-Id: Ie03f7c8bf1e0c09d52edc8ccacf0401e72dd204e
Signed-off-by: Gari Singh <[email protected]>
  • Loading branch information
mastersingh24 committed Mar 14, 2017
1 parent e2edc9b commit add5598
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 31 deletions.
2 changes: 2 additions & 0 deletions build/tasks/eslint.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ gulp.task('lint', function () {
'fabric-ca-client/lib/*.js',
'examples/**/*.js',
'!node_modules/**',
'!fabric-client/node_modules/**',
'!fabric-ca-client/node_modules/**',
'!docs/**',
'!coverage/**',
'!tmp/**'
Expand Down
54 changes: 40 additions & 14 deletions fabric-ca-client/lib/FabricCAClientImpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ var FabricCAServices = class {
* @param {Object} req Registration request with the following fields:
* <br> - enrollmentID {string}. ID which will be used for enrollment
* <br> - role {string}. An arbitrary string representing a role value for the user
* <br> - group {string}. Group to which this user will be assigned, like a company or an organization
* <br> - affiliation {string}. Affiliation with which this user will be associated, like a company or an organization
* <br> - maxEnrollments {number}. The maximum number of times this user will be permitted to enroll
* <br> - attrs {{@link KeyValueAttribute}[]}. Array of key/value attributes to assign to the user.
* @param registrar {User}. The identity of the registrar (i.e. who is performing the registration)
* @returns {Promise} The enrollment secret to use when this user enrolls
Expand All @@ -90,9 +91,15 @@ var FabricCAServices = class {
throw new Error('Missing required argument "request.enrollmentID"');
}

if (typeof req.maxEnrollments === 'undefined' || req.maxEnrollments === null) {
// set maxEnrollments to 1
req.maxEnrollments = 1;
}

checkRegistrar(registrar);

return this._fabricCAClient.register(req.enrollmentID, req.role, req.group, req.attrs, registrar.getSigningIdentity());
return this._fabricCAClient.register(req.enrollmentID, req.role, req.affiliation, req.maxEnrollments, req.attrs,
registrar.getSigningIdentity());
}

/**
Expand Down Expand Up @@ -128,10 +135,11 @@ var FabricCAServices = class {
var csr = privateKey.generateCSR('CN=' + req.enrollmentID);
self._fabricCAClient.enroll(req.enrollmentID, req.enrollmentSecret, csr)
.then(
function (csrPEM) {
function (enrollResponse) {
return resolve({
key: privateKey,
certificate: csrPEM
certificate: enrollResponse.enrollmentCert,
rootCertificate: enrollResponse.caCertChain
});
},
function (err) {
Expand Down Expand Up @@ -298,33 +306,35 @@ var FabricCAClient = class {
* Register a new user and return the enrollment secret
* @param {string} enrollmentID ID which will be used for enrollment
* @param {string} role Type of role for this user
* @param {string} group Group to which this user will be assigned
* @param {string} affiliation Affiliation with which this user will be associated
* @param {number} maxEnrollments The maximum number of times the user is permitted to enroll
* @param {KeyValueAttribute[]} attrs Array of key/value attributes to assign to the user
* @param {SigningIdentity} signingIdentity The instance of a SigningIdentity encapsulating the
* signing certificate, hash algorithm and signature algorithm
* @returns {Promise} The enrollment secret to use when this user enrolls
*/
register(enrollmentID, role, group, attrs, signingIdentity) {
register(enrollmentID, role, affiliation, maxEnrollments, attrs, signingIdentity) {

var self = this;
var numArgs = arguments.length;
//all arguments are required
if (numArgs < 5) {
throw new Error('Missing required parameters. \'enrollmentID\', \'role\', \'group\', \'attrs\', \
throw new Error('Missing required parameters. \'enrollmentID\', \'role\', \'affiliation\', \'attrs\', \
and \'signingIdentity\' are all required.');
}

return new Promise(function (resolve, reject) {
var regRequest = {
'id': enrollmentID,
'type': role ? role : 'client',
'group': group,
'affiliation': affiliation,
'max_enrollments': maxEnrollments,
'attrs': attrs
};

return self.post('register', regRequest, signingIdentity)
.then(function (response) {
return resolve(response.result.credential);
return resolve(response.result.secret);
}).catch(function (err) {
return reject(err);
});
Expand Down Expand Up @@ -358,10 +368,15 @@ var FabricCAClient = class {

return new Promise(function (resolve, reject) {

if (serial!=null){
if (serial.length < 80){
serial = '0' + serial;
}
}
var regRequest = {
'id': enrollmentID,
'aki': aki,
'serial': parseInt(serial, 16) + '', // per CFSSL, serial numbers are saved as decimals instead of hex strings in cert database
'serial': serial,
'reason': reason
};

Expand Down Expand Up @@ -446,12 +461,19 @@ var FabricCAClient = class {
return cert + '.' + b64Sign;
}

/**
* @typedef {Object} EnrollmentResponse
* @property {string} enrollmentCert PEM-encoded X509 enrollment certificate
* @property {string} caCertChain PEM-encoded X509 certificate chain for the issuing
* certificate authority
*/

/**
* Enroll a registered user in order to receive a signed X509 certificate
* @param {string} enrollmentID The registered ID to use for enrollment
* @param {string} enrollmentSecret The secret associated with the enrollment ID
* @param {string} csr PEM-encoded PKCS#10 certificate signing request
* @returns {Promise} PEM-encoded X509 certificate
* @returns {Promise} {@link EnrollmentResponse}
* @throws Will throw an error if all parameters are not provided
* @throws Will throw an error if calling the enroll API fails for any reason
*/
Expand Down Expand Up @@ -495,10 +517,14 @@ var FabricCAClient = class {
}
//response should be JSON
try {
var enrollResponse = JSON.parse(payload);
if (enrollResponse.success) {
var res = JSON.parse(payload);
if (res.success) {
//we want the result field which is Base64-encoded PEM
return resolve(new Buffer.from(enrollResponse.result, 'base64').toString());
var enrollResponse = new Object();
// Cert field is Base64-encoded PEM
enrollResponse.enrollmentCert = new Buffer.from(res.result.Cert, 'base64').toString();
enrollResponse.caCertChain = new Buffer.from(res.result.ServerInfo.CAChain, 'base64').toString();
return resolve(enrollResponse);
} else {
return reject(new Error(
util.format('Enrollment failed with errors [%s]', JSON.stringify(enrollResponse.errors))));
Expand Down
10 changes: 6 additions & 4 deletions fabric-ca-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@
"winston": "^2.2.0"
},
"license": "Apache-2.0",
"licenses": [{
"type": "Apache-2.0",
"url": "https://github.com/hyperledger/fabric/blob/master/LICENSE"
}]
"licenses": [
{
"type": "Apache-2.0",
"url": "https://github.com/hyperledger/fabric/blob/master/LICENSE"
}
]
}
27 changes: 14 additions & 13 deletions test/integration/fabric-ca-services-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,12 @@ test('FabricCAServices: Test enroll() With Dynamic CSR', function (t) {

var signingIdentity = new SigningIdentity('testSigningIdentity', eResult.certificate, pubKey, msp, new Signer(msp.cryptoSuite, eResult.key));

return cop._fabricCAClient.register(enrollmentID, 'client', 'org1', [], signingIdentity);
return cop._fabricCAClient.register(enrollmentID, 'client', 'org1', 1, [], signingIdentity);
},(err) => {
t.fail('Failed to import the public key from the enrollment certificate. ' + err.stack ? err.stack : err);
t.end();
}).then((secret) => {
console.log('secret: ' + JSON.stringify(secret));
t.comment(secret);
enrollmentSecret = secret; // to be used in the next test case

Expand All @@ -110,17 +111,16 @@ test('FabricCAServices: Test enroll() With Dynamic CSR', function (t) {
return member.setEnrollment(eResult.key, eResult.certificate);
}).then(() => {
t.comment('Successfully constructed a user object based on the enrollment');

return cop.register({enrollmentID: 'testUserX', group: 'bank_X'}, member);
return cop.register({enrollmentID: 'testUserX', affiliation: 'bank_X'}, member);
}).then((secret) => {
t.fail('Should not have been able to register user of a group "bank_X" because "admin" does not belong to that group');
t.fail('Should not have been able to register user of a affiliation "bank_X" because "admin" does not belong to that affiliation');
t.end();
},(err) => {
t.pass('Successfully rejected registration request "testUserX" in group "bank_X"');
t.pass('Successfully rejected registration request "testUserX" in affiliation "bank_X"');

return cop.register({enrollmentID: 'testUserX', group: 'org1'}, member);
return cop.register({enrollmentID: 'testUserX', affiliation: 'org1'}, member);
}).then((secret) => {
t.pass('Successfully registered "testUserX" in group "org1" with enrollment secret returned: ' + secret);
t.pass('Successfully registered "testUserX" in affiliation "org1" with enrollment secret returned: ' + secret);

return cop.revoke({enrollmentID: 'testUserX'}, member);
},(err) => {
Expand All @@ -129,7 +129,7 @@ test('FabricCAServices: Test enroll() With Dynamic CSR', function (t) {
}).then((response) => {
t.equal(response.success, true, 'Successfully revoked "testUserX"');

return cop.register({enrollmentID: 'testUserY', group: 'org2.department1'}, member);
return cop.register({enrollmentID: 'testUserY', affiliation: 'org2.department1'}, member);
},(err) => {
t.fail('Failed to revoke "testUserX". ' + err.stack ? err.stack : err);
t.end();
Expand All @@ -148,11 +148,12 @@ test('FabricCAServices: Test enroll() With Dynamic CSR', function (t) {
t.comment(util.format('Ready to revoke certificate serial # "%s" with aki "%s"', serial, aki));

return cop.revoke({serial: serial, aki: aki}, member);
//return;
}).then((response) => {
t.equal(response.success, true, 'Successfully revoked "testUserY" using serial number and AKI');

// register a new user 'webAdmin' that can register other users of the role 'client'
return cop.register({enrollmentID: 'webAdmin', group: 'org1.department2', attrs: [{name: 'hf.Registrar.Roles', value: 'client'}]}, member);
return cop.register({enrollmentID: 'webAdmin', affiliation: 'org1.department2', attrs: [{name: 'hf.Registrar.Roles', value: 'client'}]}, member);
}).then((secret) => {
t.pass('Successfully registered "webAdmin" who can register other users of the "client" role');

Expand All @@ -175,7 +176,7 @@ test('FabricCAServices: Test enroll() With Dynamic CSR', function (t) {
},(err) => {
t.pass('Successfully rejected attempt to register a user of invalid role. ' + err);

return cop.register({enrollmentID: 'auditor', role: 'client', group: 'org2.department1'}, webAdmin);
return cop.register({enrollmentID: 'auditor', role: 'client', affiliation: 'org2.department1'}, webAdmin);
}).then(() => {
t.pass('Successfully registered "auditor" of role "client" from "webAdmin"');
t.end();
Expand All @@ -195,12 +196,12 @@ test('FabricCAClient: Test enroll With Static CSR', function (t) {

t.comment(util.format('Sending enroll request for user %s with enrollment secret %s', enrollmentID, enrollmentSecret));
return client.enroll(enrollmentID, enrollmentSecret, csr.toString())
.then(function (pem) {
t.comment(pem);
.then(function (enrollResponse) {
t.comment(enrollResponse.enrollmentCert);
t.pass('Successfully invoked enroll API with enrollmentID \'' + enrollmentID + '\'');
//check that we got back the expected certificate
var cert = new X509();
cert.readCertPEM(pem);
cert.readCertPEM(enrollResponse.enrollmentCert);
t.comment(cert.getSubjectString());
t.equal(cert.getSubjectString(), '/CN=' + enrollmentID, 'Subject should be /CN=' + enrollmentID);
t.end();
Expand Down

0 comments on commit add5598

Please sign in to comment.