Skip to content

Commit

Permalink
[FAB-9373] Add SDK support for Certificate API
Browse files Browse the repository at this point in the history
Added support to be able to query certificates from
the fabric CA server.

Change-Id: I716c58da4eeb8bee7beeeab7ca5f39e786f32493
Signed-off-by: Saad Karim <skarim@us.ibm.com>
  • Loading branch information
Saad Karim committed Jun 29, 2018
1 parent edd54f8 commit f80259c
Show file tree
Hide file tree
Showing 10 changed files with 666 additions and 20 deletions.
3 changes: 3 additions & 0 deletions src/main/java/org/hyperledger/fabric/sdk/helper/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.TimeZone;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package org.hyperledger.fabric_ca.sdk;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.hyperledger.fabric_ca.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric_ca.sdk.helper.Util;

/**
* Request to the Fabric CA server to get certificates
* based on filter parameters
*/
public class HFCACertificateRequest {

private final Map<String, String> queryParms = new HashMap<>();

/**
* Get certificate request from Fabric CA server
*/
HFCACertificateRequest() {
}

/**
* Get certificates for this enrollment ID
*
* @param enrollmentID Enrollment ID associated with the certificate(s)
*/
public void setEnrollmentID(String enrollmentID) {
queryParms.put("id", enrollmentID);
}

/**
* Get certificates for this serial number
*
* @param serial Serial Number of the certificate
*/
public void setSerial(String serial) {
queryParms.put("serial", serial);
}

/**
* Get certificates for this aki
*
* @param aki AKI of the certificate(s)
*/
public void setAki(String aki) {
queryParms.put("aki", aki);
}

/**
* Get certificates that have been revoked after this date
*
* @param revokedStart Revoked after date
* @throws InvalidArgumentException Date can't be null
*/
public void setRevokedStart(Date revokedStart) throws InvalidArgumentException {
if (revokedStart == null) {
throw new InvalidArgumentException("Date can't be null");
}
queryParms.put("revoked_start", Util.dateToString(revokedStart));
}

/**
* Get certificates that have been revoked before this date
*
* @param revokedEnd Revoked before date
* @throws InvalidArgumentException Date can't be null
*/
public void setRevokedEnd(Date revokedEnd) throws InvalidArgumentException {
if (revokedEnd == null) {
throw new InvalidArgumentException("Date can't be null");
}
queryParms.put("revoked_end", Util.dateToString(revokedEnd));
}

/**
* Get certificates that have expired after this date
*
* @param expiredStart Expired after date
* @throws InvalidArgumentException Date can't be null
*/
public void setExpiredStart(Date expiredStart) throws InvalidArgumentException {
if (expiredStart == null) {
throw new InvalidArgumentException("Date can't be null");
}
queryParms.put("expired_start", Util.dateToString(expiredStart));
}

/**
* Get certificates that have expired before this date
*
* @param expiredEnd Expired end date
* @throws InvalidArgumentException Date can't be null
*/
public void setExpiredEnd(Date expiredEnd) throws InvalidArgumentException {
if (expiredEnd == null) {
throw new InvalidArgumentException("Date can't be null");
}
queryParms.put("expired_end", Util.dateToString(expiredEnd));
}

/**
* Get certificates that include/exclude expired certificates
*
* @param expired Boolean indicating if expired certificates should be excluded
*/
public void setExpired(boolean expired) {
if (expired) {
queryParms.put("notexpired", "false");
} else {
queryParms.put("notexpired", "true");
}
}

/**
* Get certificates that include/exclude revoked certificates
*
* @param revoked Boolean indicating if revoked certificates should excluded
*/
public void setRevoked(boolean revoked) {
if (revoked) {
queryParms.put("notrevoked", "false");
} else {
queryParms.put("notrevoked", "true");
}
}

/**
* Get all the filter parameters for this certificate request
*
* @return A map of filters that will be used as query parameters in GET request
*/
public Map<String, String> getQueryParameters() {
return this.queryParms;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.hyperledger.fabric_ca.sdk;

import java.util.Collection;

/**
* The response from a certificate API request, contains the status code of the
* request and certificates that were retrieved
*/
public class HFCACertificateResponse {
private final int statusCode;
private final Collection<HFCACredential> certs;

/**
* Contains the response from the server with status code and credentials requested
*
* @param statusCode Status code of the HTTP request
* @param certs The certificates return from the GET request
*/
HFCACertificateResponse(int statusCode, Collection<HFCACredential> certs) {
this.statusCode = statusCode;
this.certs = certs;
}

/**
* Returns the status code of the request
*
* @return HTTP status code
*/
public int getStatusCode() {
return statusCode;
}

/**
* Returns the certificates that were retrieved from the GET certificate request
*
* @return Certificates
*/
public Collection<HFCACredential> getCerts() {
return certs;
}
}
82 changes: 62 additions & 20 deletions src/main/java/org/hyperledger/fabric_ca/sdk/HFCAClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,13 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.TimeZone;

import javax.json.Json;
import javax.json.JsonArray;
Expand Down Expand Up @@ -104,13 +102,15 @@
import org.hyperledger.fabric_ca.sdk.exception.AffiliationException;
import org.hyperledger.fabric_ca.sdk.exception.EnrollmentException;
import org.hyperledger.fabric_ca.sdk.exception.GenerateCRLException;
import org.hyperledger.fabric_ca.sdk.exception.HFCACertificateException;
import org.hyperledger.fabric_ca.sdk.exception.HTTPException;
import org.hyperledger.fabric_ca.sdk.exception.IdentityException;
import org.hyperledger.fabric_ca.sdk.exception.InfoException;
import org.hyperledger.fabric_ca.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric_ca.sdk.exception.RegistrationException;
import org.hyperledger.fabric_ca.sdk.exception.RevocationException;
import org.hyperledger.fabric_ca.sdk.helper.Config;
import org.hyperledger.fabric_ca.sdk.helper.Util;

import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
Expand Down Expand Up @@ -189,6 +189,7 @@ public class HFCAClient {
private static final String HFCA_REVOKE = HFCA_CONTEXT_ROOT + "revoke";
private static final String HFCA_INFO = HFCA_CONTEXT_ROOT + "cainfo";
private static final String HFCA_GENCRL = HFCA_CONTEXT_ROOT + "gencrl";
private static final String HFCA_CERTIFICATE = HFCAClient.HFCA_CONTEXT_ROOT + "certificates";

private final String url;
private final boolean isSSL;
Expand Down Expand Up @@ -912,16 +913,16 @@ public String generateCRL(User registrar, Date revokedBefore, Date revokedAfter,
//---------------------------------------
JsonObjectBuilder factory = Json.createObjectBuilder();
if (revokedBefore != null) {
factory.add("revokedBefore", toJson(revokedBefore));
factory.add("revokedBefore", Util.dateToString(revokedBefore));
}
if (revokedAfter != null) {
factory.add("revokedAfter", toJson(revokedAfter));
factory.add("revokedAfter", Util.dateToString(revokedAfter));
}
if (expireBefore != null) {
factory.add("expireBefore", toJson(expireBefore));
factory.add("expireBefore", Util.dateToString(expireBefore));
}
if (expireAfter != null) {
factory.add("expireAfter", toJson(expireAfter));
factory.add("expireAfter", Util.dateToString(expireAfter));
}
if (caName != null) {
factory.add(HFCAClient.FABRIC_CA_REQPROP, caName);
Expand Down Expand Up @@ -1055,14 +1056,55 @@ public HFCAAffiliation getHFCAAffiliations(User registrar) throws AffiliationExc

}

private String toJson(Date date) {
final TimeZone utc = TimeZone.getTimeZone("UTC");
/**
* @return HFCACertificateRequest object
*/
public HFCACertificateRequest newHFCACertificateRequest() {
return new HFCACertificateRequest();
}

SimpleDateFormat tformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
tformat.setTimeZone(utc);
return tformat.format(date);
/**
* Gets all certificates that the registrar is allowed to see and based on filter parameters that
* are part of the certificate request.
*
* @param registrar The identity of the registrar (i.e. who is performing the registration).
* @param req The certificate request that contains filter parameters
* @return HFCACertificateResponse object
* @throws HFCACertificateException Failed to process get certificate request
*/
public HFCACertificateResponse getHFCACertificates(User registrar, HFCACertificateRequest req) throws HFCACertificateException {
try {
logger.debug(format("certificate url: %s, registrar: %s", HFCA_CERTIFICATE, registrar.getName()));

JsonObject result = httpGet(HFCA_CERTIFICATE, registrar, req.getQueryParameters());

int statusCode = result.getInt("statusCode");
Collection<HFCACredential> certs = new ArrayList<>();
if (statusCode < 400) {
JsonArray certificates = result.getJsonArray("certs");
if (certificates != null && !certificates.isEmpty()) {
for (int i = 0; i < certificates.size(); i++) {
String certPEM = certificates.getJsonObject(i).getString("PEM");
certs.add(new HFCAX509Certificate(certPEM));
}
}
logger.debug(format("certificate url: %s, registrar: %s done.", HFCA_CERTIFICATE, registrar));
}
return new HFCACertificateResponse(statusCode, certs);
} catch (HTTPException e) {
String msg = format("[Code: %d] - Error while getting certificates from url '%s': %s", e.getStatusCode(), HFCA_CERTIFICATE, e.getMessage());
HFCACertificateException certificateException = new HFCACertificateException(msg, e);
logger.error(msg);
throw certificateException;
} catch (Exception e) {
String msg = format("Error while getting certificates from url '%s': %s", HFCA_CERTIFICATE, e.getMessage());
HFCACertificateException certificateException = new HFCACertificateException(msg, e);
logger.error(msg);
throw certificateException;
}
}


/**
* Http Post Request.
*
Expand Down Expand Up @@ -1167,8 +1209,12 @@ JsonObject httpPost(String url, String body, User registrar) throws Exception {
}

JsonObject httpGet(String url, User registrar) throws Exception {
return httpGet(url, registrar, null);
}

JsonObject httpGet(String url, User registrar, Map<String, String> queryMap) throws Exception {
String authHTTPCert = getHTTPAuthCertificate(registrar.getEnrollment(), "");
url = getURL(url);
url = getURL(url, queryMap);
HttpGet httpGet = new HttpGet(url);
httpGet.setConfig(getRequestConfig());
logger.debug(format("httpGet %s, authHTTPCert: %s", url, authHTTPCert));
Expand Down Expand Up @@ -1438,13 +1484,7 @@ public Socket createSocket() throws IOException {
}

String getURL(String endpoint) throws URISyntaxException, MalformedURLException, InvalidArgumentException {
setUpSSL();
String url = this.url + endpoint;
URIBuilder uri = new URIBuilder(url);
if (caName != null) {
uri.addParameter("ca", caName);
}
return uri.build().toURL().toString();
return getURL(endpoint, null);
}

String getURL(String endpoint, Map<String, String> queryMap) throws URISyntaxException, MalformedURLException, InvalidArgumentException {
Expand All @@ -1456,7 +1496,9 @@ String getURL(String endpoint, Map<String, String> queryMap) throws URISyntaxExc
}
if (queryMap != null) {
for (Map.Entry<String, String> param : queryMap.entrySet()) {
uri.addParameter(param.getKey(), param.getValue());
if (!Utils.isNullOrEmpty(param.getValue())) {
uri.addParameter(param.getKey(), param.getValue());
}
}
}
return uri.build().toURL().toString();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.hyperledger.fabric_ca.sdk;

/**
* Credentials supported by Fabric CA
*/
public abstract class HFCACredential {
}
Loading

0 comments on commit f80259c

Please sign in to comment.