环境搭建
适用Fabric版本:1.x及2.x
如果尚未搭建一个可用的SDK测试网络,可参考:
Fabric SDK测试网络搭建(v1.x)
Fabric2.0 SDK测试网络搭建
Peer和Orderer节点启用TLS
官方SDK地址:fabric-sdk-java
废话不说,直接上官方Java SDK代码。
/**
* @methodsName: getEndPointProperties
* @description: 获取Peer和Orderer的tls配置
* @param: type(节点类型:peer或orderer)
* @param: name为节点域名
* @return: Properties
*/
public Properties getEndPointProperties(final String type, final String name) {
Properties ret = new Properties();
final String domainName = getDomainName(name);//获取Peer和Orderer节点域名后缀
File cert = Paths.get(getTestChannelPath(), "crypto-config/ordererOrganizations".replace("orderer", type), domainName, type + "s",
name, "tls/server.crt").toFile(); //getTestChannelPath()为证书文件夹crypto-config所在目录,自行替换
if (!cert.exists()) {
throw new RuntimeException(String.format("Missing cert file for: %s. Could not find at location: %s", name,
cert.getAbsolutePath()));
}
//此处判断是否运行版本为1.0及以后,鉴于目前运用较多为1.x版本,此判断逻辑可去除
if (!isRunningAgainstFabric10()) {
File clientCert;
File clientKey;
if ("orderer".equals(type)) {
clientCert = Paths.get(getTestChannelPath(), "crypto-config/ordererOrganizations/example.com/users/[email protected]/tls/client.crt").toFile();
clientKey = Paths.get(getTestChannelPath(), "crypto-config/ordererOrganizations/example.com/users/[email protected]/tls/client.key").toFile();
} else {
clientCert = Paths.get(getTestChannelPath(), "crypto-config/peerOrganizations/", domainName, "users/User1@" + domainName, "tls/client.crt").toFile();
clientKey = Paths.get(getTestChannelPath(), "crypto-config/peerOrganizations/", domainName, "users/User1@" + domainName, "tls/client.key").toFile();
}
if (!clientCert.exists()) {
throw new RuntimeException(String.format("Missing client cert file for: %s. Could not find at location: %s", name,
clientCert.getAbsolutePath()));
}
if (!clientKey.exists()) {
throw new RuntimeException(String.format("Missing client key file for: %s. Could not find at location: %s", name,
clientKey.getAbsolutePath()));
}
ret.setProperty("clientCertFile", clientCert.getAbsolutePath());
ret.setProperty("clientKeyFile", clientKey.getAbsolutePath());
}
ret.setProperty("pemFile", cert.getAbsolutePath());
ret.setProperty("hostnameOverride", name);
ret.setProperty("sslProvider", "openSSL");
ret.setProperty("negotiationType", "TLS");
return ret;
}
/**
* @methodsName: getDomainName
* @description: 获取Peer和Orderer节点域名后缀(例如org1.example.com)
* @param: name为节点
* @return: String
*/
private String getDomainName(final String name) {
int dot = name.indexOf(".");
if (-1 == dot) {
return null;
} else {
return name.substring(dot + 1);
}
}
Peer节点调用方法:
Properties peerProperties = testConfig.getEndPointProperties("peer", name);//testConfig参考上文
if (peerProperties == null) {
peerProperties = new Properties();
}
peerProperties.put("grpc.NettyChannelBuilderOption.maxInboundMessageSize", 9000000);
Peer peer = client.newPeer(peerName, peerLocation,peerProperties);//client为HFClient对象
Orderer节点调用方法:
Properties ordererProperties = testConfig.getEndPointProperties("orderer", name);
ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTime", new Object[] {5L, TimeUnit.MINUTES});
ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[] {8L, TimeUnit.SECONDS});
ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveWithoutCalls", new Object[] {true});
Orderer orderer = client.newOrderer(orderName, sampleOrg.getOrdererLocation(orderName),
ordererProperties);
CA节点启用TLS
网上大多数博客都是关于Orderer和Peer启用TLS的,对于CA启用TLS的资料较少,作为良心博主,直接上干货。
File cf = new File(cert);
if (!cf.exists() || !cf.isFile()) {
throw new RuntimeException("TEST is missing cert file " + cf.getAbsolutePath());
}
Properties properties = new Properties();
properties.setProperty("pemFile", cf.getAbsolutePath());
properties.setProperty("allowAllHostNames", "true");
CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite();
//创建HFCAClient 实例,caUrl为ca地址,启用tls地址为https开头的,例如https://192.168.1.10:7054
HFCAClient instance = HFCAClient.createNewInstance(caUrl, properties);
instance.setCryptoSuite(cryptoSuite);
需注意的一点是enroll时候,启用tls写法有所不同
final EnrollmentRequest enrollmentRequestTLS = new EnrollmentRequest();
enrollmentRequestTLS.addHost(caUrl);
enrollmentRequestTLS.setProfile("tls");
enrollment = instance.enroll(userName, secret,enrollmentRequestTLS);
附官方源码(不启用tls)
/**
* Enroll the user with member service
*
* @param user Identity name to enroll
* @param secret Secret returned via registration
* @return enrollment
* @throws EnrollmentException
* @throws InvalidArgumentException
*/
public Enrollment enroll(String user, String secret) throws EnrollmentException, InvalidArgumentException {
return enroll(user, secret, new EnrollmentRequest());
}
附官方源码(启用tls)
/**
* Enroll the user with member service
*
* @param user Identity name to enroll
* @param secret Secret returned via registration
* @param req Enrollment request with the following fields: hosts, profile, csr, label, keypair
* @return enrollment
* @throws EnrollmentException
* @throws InvalidArgumentException
*/
public Enrollment enroll(String user, String secret, EnrollmentRequest req) throws EnrollmentException, InvalidArgumentException {
logger.debug(format("url:%s enroll user: %s", url, user));
if (Utils.isNullOrEmpty(user)) {
throw new InvalidArgumentException("enrollment user is not set");
}
if (Utils.isNullOrEmpty(secret)) {
throw new InvalidArgumentException("enrollment secret is not set");
}
if (cryptoSuite == null) {
throw new InvalidArgumentException("Crypto primitives not set.");
}
setUpSSL();
try {
String pem = req.getCsr();
KeyPair keypair = req.getKeyPair();
if (null != pem && keypair == null) {
throw new InvalidArgumentException("If certificate signing request is supplied the key pair needs to be supplied too.");
}
if (keypair == null) {
logger.debug("[HFCAClient.enroll] Generating keys...");
// generate ECDSA keys: signing and encryption keys
keypair = cryptoSuite.keyGen();
logger.debug("[HFCAClient.enroll] Generating keys...done!");
}
if (pem == null) {
String csr = cryptoSuite.generateCertificationRequest(user, keypair);
req.setCSR(csr);
}
if (caName != null && !caName.isEmpty()) {
req.setCAName(caName);
}
String body = req.toJson();
String responseBody = httpPost(getURL(HFCA_ENROLL), body,
new UsernamePasswordCredentials(user, secret));
logger.debug("response:" + responseBody);
JsonReader reader = Json.createReader(new StringReader(responseBody));
JsonObject jsonst = (JsonObject) reader.read();
boolean success = jsonst.getBoolean("success");
logger.debug(format("[HFCAClient] enroll success:[%s]", success));
if (!success) {
throw new EnrollmentException(format("FabricCA failed enrollment for user %s response success is false.", user));
}
JsonObject result = jsonst.getJsonObject("result");
if (result == null) {
throw new EnrollmentException(format("FabricCA failed enrollment for user %s - response did not contain a result", user));
}
Base64.Decoder b64dec = Base64.getDecoder();
String signedPem = new String(b64dec.decode(result.getString("Cert").getBytes(UTF_8)));
logger.debug(format("[HFCAClient] enroll returned pem:[%s]", signedPem));
JsonArray messages = jsonst.getJsonArray("messages");
if (messages != null && !messages.isEmpty()) {
JsonObject jo = messages.getJsonObject(0);
String message = format("Enroll request response message [code %d]: %s", jo.getInt("code"), jo.getString("message"));
logger.info(message);
}
logger.debug("Enrollment done.");
return new X509Enrollment(keypair, signedPem);
} catch (EnrollmentException ee) {
logger.error(format("url:%s, user:%s error:%s", url, user, ee.getMessage()), ee);
throw ee;
} catch (Exception e) {
EnrollmentException ee = new EnrollmentException(format("Url:%s, Failed to enroll user %s ", url, user), e);
logger.error(e.getMessage(), e);
throw ee;
}
}
总结
本篇博客完成了启用TLS(Peer,Orderer,CA)时,Java SDK的写法,有疑问欢迎评论留言。