Skip to content

Commit 3dce1cb

Browse files
committed
* Add support of CredentialPojo creation and verification
1 parent 9f83dbf commit 3dce1cb

File tree

6 files changed

+240
-7
lines changed

6 files changed

+240
-7
lines changed

src/main/java/com/webank/weid/http/constant/WeIdentityFunctionNames.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public final class WeIdentityFunctionNames {
4040
public static final String FUNCNAME_GET_WEID_DOCUMENT_JSON = "getWeIdDocumentJson";
4141
public static final String FUNCNAME_QUERY_AUTHORITY_ISSUER = "queryAuthorityIssuer";
4242
public static final String FUNCNAME_QUERY_CPT = "queryCpt";
43+
public static final String FUNCNAME_CREATE_CREDENTIALPOJO = "createCredentialPojo";
44+
public static final String FUNCNAME_VERIFY_CREDENTIALPOJO = "verifyCredentialPojo";
4345

4446
/**
4547
* Function names to be assembled in SDK Function call. Case sensitive.

src/main/java/com/webank/weid/http/service/InvokerCredentialService.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package com.webank.weid.http.service;
2121

22+
import com.webank.weid.protocol.base.CredentialPojo;
2223
import org.springframework.stereotype.Service;
2324

2425
import com.webank.weid.http.protocol.request.InputArg;
@@ -43,4 +44,20 @@ public interface InvokerCredentialService {
4344
* @return the Boolean response data
4445
*/
4546
HttpResponseData<Object> verifyCredentialInvoke(InputArg verifyCredentialFuncArgs);
47+
48+
/**
49+
* Create Credential Pojo. Need format conversion.
50+
*
51+
* @param createCredentialPojoFuncArgs
52+
* @return credentialpojo
53+
*/
54+
HttpResponseData<Object> createCredentialPojoInvoke(InputArg createCredentialPojoFuncArgs);
55+
56+
/**
57+
* Verify the validity of a Credential Pojo. Need format conversion.
58+
*
59+
* @param verifyCredentialPojoFuncArgs
60+
* @return boolean
61+
*/
62+
HttpResponseData<Boolean> verifyCredentialPojoInvoke(InputArg verifyCredentialPojoFuncArgs);
4663
}

src/main/java/com/webank/weid/http/service/impl/InvokerCredentialServiceImpl.java

Lines changed: 132 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@
2020

2121
package com.webank.weid.http.service.impl;
2222

23+
import com.webank.weid.protocol.base.CredentialPojo;
24+
import com.webank.weid.protocol.base.WeIdAuthentication;
25+
import com.webank.weid.protocol.request.CreateCredentialPojoArgs;
26+
import com.webank.weid.rpc.CredentialPojoService;
27+
import com.webank.weid.service.impl.CredentialPojoServiceImpl;
28+
import com.webank.weid.util.CredentialPojoUtils;
29+
import com.webank.weid.util.DataToolUtils;
2330
import java.io.IOException;
2431
import java.util.HashMap;
2532
import java.util.Map;
@@ -58,14 +65,16 @@ public class InvokerCredentialServiceImpl extends BaseService implements Invoker
5865
private Logger logger = LoggerFactory.getLogger(InvokerCredentialServiceImpl.class);
5966

6067
private CredentialService credentialService = new CredentialServiceImpl();
68+
private CredentialPojoService credentialPojoService = new CredentialPojoServiceImpl();
6169

6270
/**
63-
* Generate a credential for client to sign. The signature field is null, and both full claim
64-
* and claimHash will be returned. The returned json String is an key-ordered compact json.
71+
* Generate a credential for client to sign. The signature field is null, and both full claim and claimHash will be returned. The returned json
72+
* String is an key-ordered compact json.
6573
*
6674
* @param createCredentialFuncArgs the functionArgs
6775
* @return the Map contains Credential content and claimHash.
6876
*/
77+
@Override
6978
public HttpResponseData<Object> createCredentialInvoke(
7079
InputArg createCredentialFuncArgs) {
7180
try {
@@ -150,7 +159,7 @@ public HttpResponseData<Object> createCredentialInvoke(
150159
// this is the server-hosting privkey approach
151160
String privateKey = KeyUtil
152161
.getPrivateKeyByWeId(KeyUtil.SDK_PRIVKEY_PATH, keyIndexNode.textValue());
153-
if (StringUtils.isEmpty(privateKey)) {
162+
if (!KeyUtil.isPrivateKeyLengthValid(privateKey)) {
154163
return new HttpResponseData<>(null, HttpReturnCode.INVOKER_ILLEGAL);
155164
}
156165
Map<String, String> credentialProof = CredentialUtils
@@ -185,6 +194,7 @@ public HttpResponseData<Object> createCredentialInvoke(
185194
* @param verifyCredentialFuncArgs the credential json args
186195
* @return the Boolean response data
187196
*/
197+
@Override
188198
public HttpResponseData<Object> verifyCredentialInvoke(InputArg verifyCredentialFuncArgs) {
189199
Credential credential = null;
190200
try {
@@ -222,4 +232,123 @@ public HttpResponseData<Object> verifyCredentialInvoke(InputArg verifyCredential
222232
HttpReturnCode.WEID_SDK_ERROR.getCodeDesc().concat(e.getMessage()));
223233
}
224234
}
235+
236+
@Override
237+
public HttpResponseData<Object> createCredentialPojoInvoke(InputArg createCredentialPojoFuncArgs) {
238+
JsonNode cptIdNode;
239+
JsonNode issuerNode;
240+
JsonNode expirationDateNode;
241+
JsonNode claimNode;
242+
try {
243+
JsonNode functionArgNode = new ObjectMapper()
244+
.readTree(createCredentialPojoFuncArgs.getFunctionArg());
245+
cptIdNode = functionArgNode.get(ParamKeyConstant.CPT_ID);
246+
issuerNode = functionArgNode.get(ParamKeyConstant.ISSUER);
247+
expirationDateNode = functionArgNode.get(ParamKeyConstant.EXPIRATION_DATE);
248+
claimNode = functionArgNode.get(ParamKeyConstant.CLAIM);
249+
if (cptIdNode == null || StringUtils.isEmpty(cptIdNode.toString())
250+
|| issuerNode == null || StringUtils.isEmpty(issuerNode.textValue())
251+
|| expirationDateNode == null || StringUtils.isEmpty(expirationDateNode.textValue())
252+
|| claimNode == null || StringUtils.isEmpty(claimNode.toString())) {
253+
return new HttpResponseData<>(null, HttpReturnCode.INPUT_NULL);
254+
}
255+
} catch (Exception e) {
256+
logger.error("[createCredentialPojoInvoke]: input args error: {}", createCredentialPojoFuncArgs, e);
257+
return new HttpResponseData<>(null, HttpReturnCode.VALUE_FORMAT_ILLEGAL);
258+
}
259+
260+
Integer cptId;
261+
try {
262+
cptId = Integer.valueOf(JsonUtil.removeDoubleQuotes(cptIdNode.toString()));
263+
} catch (Exception e) {
264+
return new HttpResponseData<>(null, HttpReturnCode.VALUE_FORMAT_ILLEGAL);
265+
}
266+
267+
Long expirationDate;
268+
try {
269+
expirationDate = DateUtils
270+
.convertUtcDateToTimeStamp(expirationDateNode.textValue());
271+
} catch (Exception e) {
272+
return new HttpResponseData<>(null,
273+
ErrorCode.CREDENTIAL_EXPIRE_DATE_ILLEGAL.getCode(),
274+
ErrorCode.CREDENTIAL_EXPIRE_DATE_ILLEGAL.getCodeDesc());
275+
}
276+
277+
CredentialPojo credential = new CredentialPojo();
278+
credential.setId(UUID.randomUUID().toString());
279+
credential.setCptId(cptId);
280+
credential.setIssuer(issuerNode.textValue());
281+
credential.setExpirationDate(expirationDate);
282+
credential.setContext(CredentialConstant.DEFAULT_CREDENTIAL_CONTEXT);
283+
credential.setIssuanceDate(DateUtils.getNoMillisecondTimeStamp());
284+
Map<String, Object> claimMap;
285+
try {
286+
claimMap = (Map<String, Object>) JsonUtil
287+
.jsonStrToObj(new HashMap<String, Object>(), claimNode.toString());
288+
} catch (Exception e) {
289+
return new HttpResponseData<>(null,
290+
ErrorCode.CREDENTIAL_CLAIM_DATA_ILLEGAL.getCode(),
291+
ErrorCode.CREDENTIAL_CLAIM_DATA_ILLEGAL.getCodeDesc());
292+
}
293+
credential.setClaim(claimMap);
294+
295+
WeIdAuthentication weIdAuthentication;
296+
try {
297+
JsonNode txnArgNode = new ObjectMapper().readTree(createCredentialPojoFuncArgs.getTransactionArg());
298+
JsonNode keyIndexNode = txnArgNode.get(WeIdentityParamKeyConstant.KEY_INDEX);
299+
String privateKey = KeyUtil
300+
.getPrivateKeyByWeId(KeyUtil.SDK_PRIVKEY_PATH, keyIndexNode.textValue());
301+
weIdAuthentication = KeyUtil.buildWeIdAuthenticationFromPrivKey(privateKey);
302+
if (weIdAuthentication == null) {
303+
return new HttpResponseData<>(null, HttpReturnCode.INVOKER_ILLEGAL);
304+
}
305+
} catch (Exception e) {
306+
return new HttpResponseData<>(null, ErrorCode.CREDENTIAL_PRIVATE_KEY_NOT_EXISTS.getCode(),
307+
ErrorCode.CREDENTIAL_PRIVATE_KEY_NOT_EXISTS.getCodeDesc());
308+
}
309+
310+
// Client-side check of validity
311+
CreateCredentialPojoArgs createArg = new CreateCredentialPojoArgs();
312+
createArg.setClaim(claimMap);
313+
createArg.setCptId(cptId);
314+
createArg.setIssuer(issuerNode.textValue());
315+
createArg.setIssuanceDate(credential.getIssuanceDate());
316+
createArg.setExpirationDate(expirationDate);
317+
createArg.setContext(credential.getContext());
318+
createArg.setId(credential.getId());
319+
createArg.setWeIdAuthentication(weIdAuthentication);
320+
ErrorCode errorCode = CredentialPojoUtils.isCreateCredentialPojoArgsValid(createArg);
321+
if (errorCode.getCode() != ErrorCode.SUCCESS.getCode()) {
322+
return new HttpResponseData<>(null, errorCode.getCode(),
323+
errorCode.getCodeDesc());
324+
}
325+
ResponseData<CredentialPojo> createResp = credentialPojoService.createCredential(createArg);
326+
// TODO unify with Credential
327+
Map<String, Object> credMap = (Map<String, Object>) JsonUtil.jsonStrToObj(new HashMap<String, Object>(),
328+
DataToolUtils.serialize(createResp.getResult()));
329+
return new HttpResponseData<>(credMap, createResp.getErrorCode(), createResp.getErrorMessage());
330+
}
331+
332+
@Override
333+
public HttpResponseData<Boolean> verifyCredentialPojoInvoke(InputArg verifyCredentialPojoFuncArgs) {
334+
CredentialPojo credential;
335+
try {
336+
credential = DataToolUtils.deserialize(verifyCredentialPojoFuncArgs.getFunctionArg(), CredentialPojo.class);
337+
} catch (Exception e) {
338+
logger.error("Input credential format illegal: {}", verifyCredentialPojoFuncArgs);
339+
return new HttpResponseData<>(null, HttpReturnCode.INPUT_ILLEGAL.getCode(),
340+
HttpReturnCode.INPUT_ILLEGAL.getCodeDesc().concat(e.getMessage()));
341+
}
342+
try {
343+
ResponseData<Boolean> responseData = credentialPojoService.verify(credential.getIssuer(), credential);
344+
return new HttpResponseData<>(responseData.getResult(),
345+
responseData.getErrorCode(), responseData.getErrorMessage());
346+
} catch (Exception e) {
347+
logger.error("[verifyCredentialInvoke]: SDK error. reqCredentialArgs:{}",
348+
verifyCredentialPojoFuncArgs,
349+
e);
350+
return new HttpResponseData<>(null, HttpReturnCode.WEID_SDK_ERROR.getCode(),
351+
HttpReturnCode.WEID_SDK_ERROR.getCodeDesc().concat(e.getMessage()));
352+
}
353+
}
225354
}

src/main/java/com/webank/weid/http/service/impl/TransactionServiceImpl.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright© (2019) WeBank Co., Ltd.
2+
* Copyright© (2019-2020) WeBank Co., Ltd.
33
*
44
* This file is part of weid-http-service.
55
*
@@ -21,6 +21,7 @@
2121

2222
import com.fasterxml.jackson.databind.JsonNode;
2323
import com.fasterxml.jackson.databind.ObjectMapper;
24+
import com.webank.weid.protocol.base.CredentialPojo;
2425
import org.apache.commons.lang3.StringUtils;
2526
import org.bcos.web3j.protocol.core.methods.request.RawTransaction;
2627
import org.slf4j.Logger;
@@ -69,6 +70,7 @@ public class TransactionServiceImpl extends BaseService implements TransactionSe
6970
* params into SDK readable format to send there; apiVersion is for extensibility purpose.
7071
* @return encoded transaction in Base64 format, and the data segment in RawTransaction.
7172
*/
73+
@Override
7274
public HttpResponseData<Object> encodeTransaction(
7375
String encodeTransactionJsonArgs) {
7476
try {
@@ -139,6 +141,7 @@ public HttpResponseData<Object> encodeTransaction(
139141
* (including all business related params), transactionArgs, functionName and apiVersion.
140142
* @return the json string from SDK response.
141143
*/
144+
@Override
142145
public HttpResponseData<Object> sendTransaction(String sendTransactionJsonArgs) {
143146
try {
144147
HttpResponseData<InputArg> resp = TransactionEncoderUtil
@@ -240,6 +243,7 @@ public HttpResponseData<Object> sendTransaction(String sendTransactionJsonArgs)
240243
* (including all business related params), EMPTY transactionArgs, functionName and apiVersion.
241244
* @return the json string from SDK response.
242245
*/
246+
@Override
243247
public HttpResponseData<Object> invokeFunction(String invokeFunctionJsonArgs) {
244248
HttpResponseData<InputArg> resp = TransactionEncoderUtil
245249
.buildInputArg(invokeFunctionJsonArgs);
@@ -253,9 +257,16 @@ public HttpResponseData<Object> invokeFunction(String invokeFunctionJsonArgs) {
253257
if (functionName.equalsIgnoreCase(WeIdentityFunctionNames.FUNCNAME_CREATE_CREDENTIAL)) {
254258
return invokerCredentialService.createCredentialInvoke(inputArg);
255259
}
260+
if (functionName.equalsIgnoreCase(WeIdentityFunctionNames.FUNCNAME_CREATE_CREDENTIALPOJO)) {
261+
return invokerCredentialService.createCredentialPojoInvoke(inputArg);
262+
}
256263
if (functionName.equalsIgnoreCase(WeIdentityFunctionNames.FUNCNAME_VERIFY_CREDENTIAL)) {
257264
return invokerCredentialService.verifyCredentialInvoke(inputArg);
258265
}
266+
if (functionName.equalsIgnoreCase(WeIdentityFunctionNames.FUNCNAME_VERIFY_CREDENTIALPOJO)) {
267+
HttpResponseData<Boolean> respData = invokerCredentialService.verifyCredentialPojoInvoke(inputArg);
268+
return new HttpResponseData<>(respData.getRespBody(), respData.getErrorCode(), respData.getErrorMessage());
269+
}
259270
if (functionName
260271
.equalsIgnoreCase(WeIdentityFunctionNames.FUNCNAME_QUERY_AUTHORITY_ISSUER)) {
261272
return invokerAuthorityIssuerService.queryAuthorityIssuerInfoInvoke(inputArg);

src/main/java/com/webank/weid/http/util/KeyUtil.java

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,22 @@
1919

2020
package com.webank.weid.http.util;
2121

22+
import com.webank.weid.protocol.base.WeIdAuthentication;
23+
import com.webank.weid.protocol.base.WeIdPrivateKey;
24+
import com.webank.weid.util.WeIdUtils;
2225
import java.io.File;
2326
import java.io.FileInputStream;
2427
import java.io.FileNotFoundException;
2528
import java.io.FileOutputStream;
2629
import java.io.IOException;
2730
import java.io.OutputStreamWriter;
31+
import java.math.BigInteger;
2832
import java.nio.charset.StandardCharsets;
2933

3034
import org.apache.commons.lang3.StringUtils;
35+
import org.fisco.bcos.web3j.abi.datatypes.Address;
36+
import org.fisco.bcos.web3j.crypto.ECKeyPair;
37+
import org.fisco.bcos.web3j.crypto.Keys;
3138
import org.slf4j.Logger;
3239
import org.slf4j.LoggerFactory;
3340

@@ -54,8 +61,7 @@ public class KeyUtil {
5461
private static final String SLASH_CHARACTER = "/";
5562

5663
/**
57-
* this method stores weId private key information by file and stores private key information by
58-
* itself in actual scene.
64+
* this method stores weId private key information by file and stores private key information by itself in actual scene.
5965
*
6066
* @param path save path
6167
* @param weId the weId
@@ -211,4 +217,41 @@ public static String saveFile(String filePath, String dataStr) {
211217
}
212218
return StringUtils.EMPTY;
213219
}
220+
221+
/**
222+
* Build a default WeIdAuthentication from passed-in private key.
223+
*
224+
* @param privateKey the private key in String
225+
* @return weIdAuthentication
226+
*/
227+
public static WeIdAuthentication buildWeIdAuthenticationFromPrivKey(String privateKey) {
228+
if (StringUtils.isBlank(privateKey) || !isPrivateKeyLengthValid(privateKey)) {
229+
logger.error("Private key format or size illegal.");
230+
return null;
231+
}
232+
ECKeyPair keyPair = ECKeyPair.create(new BigInteger(privateKey));
233+
String keyWeId = WeIdUtils
234+
.convertAddressToWeId(new Address(Keys.getAddress(keyPair)).toString());
235+
WeIdAuthentication weIdAuthentication = new WeIdAuthentication();
236+
weIdAuthentication.setWeId(keyWeId);
237+
weIdAuthentication.setWeIdPublicKeyId(keyWeId + "#keys-0");
238+
WeIdPrivateKey weIdPrivateKey = new WeIdPrivateKey();
239+
weIdPrivateKey.setPrivateKey(privateKey);
240+
weIdAuthentication.setWeIdPrivateKey(weIdPrivateKey);
241+
return weIdAuthentication;
242+
}
243+
244+
public static boolean isPrivateKeyLengthValid(String privateKey) {
245+
if (StringUtils.isBlank(privateKey)) {
246+
return false;
247+
}
248+
WeIdPrivateKey weIdPrivateKey = new WeIdPrivateKey();
249+
weIdPrivateKey.setPrivateKey(privateKey);
250+
if (WeIdUtils.isPrivateKeyValid(weIdPrivateKey)) {
251+
BigInteger privKeyBig = new BigInteger(privateKey, 10);
252+
BigInteger MAX_PRIVKEY_VALUE = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16);
253+
return (privKeyBig.compareTo(MAX_PRIVKEY_VALUE) <= 0);
254+
}
255+
return false;
256+
}
214257
}

src/test/java/com/webank/weid/http/service/PureInvokerTest.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package com.webank.weid.http.service;
2121

22+
import com.webank.weid.protocol.base.CredentialPojo;
2223
import java.math.BigInteger;
2324
import java.util.LinkedHashMap;
2425
import java.util.Map;
@@ -207,6 +208,36 @@ public void testInvokeIntegration() throws Exception {
207208
HttpResponseData<Object> resp9 =
208209
transactionService.invokeFunction(JsonUtil.objToJsonStr(inputParamMap));
209210
System.out.println(JsonUtil.objToJsonStr(resp9));
210-
Assert.assertNotNull(resp9.getRespBody());
211+
Assert.assertTrue((Boolean) resp9.getRespBody());
212+
213+
// create credentialPojo using the same cpt id
214+
txnArgMap = new LinkedHashMap<>();
215+
txnArgMap.put(WeIdentityParamKeyConstant.KEY_INDEX, weId);
216+
inputParamMap = new LinkedHashMap<>();
217+
inputParamMap.put(WeIdentityParamKeyConstant.FUNCTION_ARG, funcArgMap);
218+
inputParamMap.put(WeIdentityParamKeyConstant.TRANSACTION_ARG, txnArgMap);
219+
inputParamMap.put(WeIdentityParamKeyConstant.API_VERSION,
220+
WeIdentityParamKeyConstant.DEFAULT_API_VERSION);
221+
inputParamMap.put(WeIdentityParamKeyConstant.FUNCTION_NAME,
222+
WeIdentityFunctionNames.FUNCNAME_CREATE_CREDENTIALPOJO);
223+
HttpResponseData<Object> resp10 =
224+
transactionService.invokeFunction(JsonUtil.objToJsonStr(inputParamMap));
225+
System.out.println(JsonUtil.objToJsonStr(resp10));
226+
Assert.assertNotNull(resp10.getRespBody());
227+
228+
// verify credentialPojo
229+
credJsonMap = (Map<String, Object>) resp10.getRespBody();
230+
txnArgMap = new LinkedHashMap<>();
231+
inputParamMap = new LinkedHashMap<>();
232+
inputParamMap.put(WeIdentityParamKeyConstant.FUNCTION_ARG, credJsonMap);
233+
inputParamMap.put(WeIdentityParamKeyConstant.TRANSACTION_ARG, txnArgMap);
234+
inputParamMap.put(WeIdentityParamKeyConstant.API_VERSION,
235+
WeIdentityParamKeyConstant.DEFAULT_API_VERSION);
236+
inputParamMap.put(WeIdentityParamKeyConstant.FUNCTION_NAME,
237+
WeIdentityFunctionNames.FUNCNAME_VERIFY_CREDENTIALPOJO);
238+
HttpResponseData<Object> resp11 =
239+
transactionService.invokeFunction(JsonUtil.objToJsonStr(inputParamMap));
240+
System.out.println(JsonUtil.objToJsonStr(resp11));
241+
Assert.assertTrue((Boolean) resp11.getRespBody());
211242
}
212243
}

0 commit comments

Comments
 (0)