Skip to content

Commit

Permalink
Merge pull request #266 from yanggang-JV/feature/add-check-credential…
Browse files Browse the repository at this point in the history
…-with-cpt

* add function for check credential with cpt
  • Loading branch information
junqizhang-dev committed Oct 28, 2020
2 parents 6f41f09 + 901c922 commit 299a845
Show file tree
Hide file tree
Showing 7 changed files with 193 additions and 12 deletions.
10 changes: 10 additions & 0 deletions src/main/java/com/webank/weid/constant/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,16 @@ public enum ErrorCode {
CREDENTIAL_VERIFY_SUCCEEDED_WITH_WRONG_PUBLIC_KEY_ID(100442, "credential"
+ "verify succeeded, but the given public key ID is incorrect."),

/**
* credential is disclosed.
*/
CREDENTIAL_IS_DISCLOSED(100443, "credential is disclosed."),

/**
* credential does not match CPT.
*/
CREDENTIAL_DOES_NOT_MATCHE_THE_CPT(100444, "credential does not match CPT."),

/**
* Authorization WeIDs: from and to must be different.
*/
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/com/webank/weid/protocol/base/CredentialPojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -280,4 +280,25 @@ public String getHash() {
public String getSignatureThumbprint() {
return CredentialPojoUtils.getCredentialThumbprintWithoutSig(this, this.getSalt(), null);
}

/**
* Get the CredentialType.
* @return the CredentialType
*/
public CredentialType getCredentialType() {
if (this.type == null) {
logger.warn("[getCredentialType] the type is null.");
return null;
}
if (this.type.contains(CredentialType.ZKP.getName())) {
return CredentialType.ZKP;
} else if (this.type.contains(CredentialType.LITE1.getName())) {
return CredentialType.LITE1;
} else if (this.type.contains(CredentialType.ORIGINAL.getName())) {
return CredentialType.ORIGINAL;
} else {
logger.warn("[getCredentialType] the type does not contain default CredentialType.");
return null;
}
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/webank/weid/rpc/CredentialPojoService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@

import java.util.List;

import com.github.fge.jsonschema.core.report.ProcessingReport;

import com.webank.weid.protocol.base.Challenge;
import com.webank.weid.protocol.base.ClaimPolicy;
import com.webank.weid.protocol.base.Cpt;
import com.webank.weid.protocol.base.CredentialPojo;
import com.webank.weid.protocol.base.PresentationE;
import com.webank.weid.protocol.base.PresentationPolicyE;
Expand Down Expand Up @@ -213,5 +216,14 @@ ResponseData<CredentialPojo> createDataAuthToken(
Cpt101 authInfo,
WeIdAuthentication weIdAuthentication
);

/**
* Check the credential with CPT.
*
* @param credential the CredentialPojo
* @param cpt the CPT information
* @return return ProcessingReport
*/
ResponseData<ProcessingReport> checkCredentialWithCpt(CredentialPojo credential, Cpt cpt);
}

Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.UUID;
import java.util.stream.Collectors;

import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.webank.wedpr.common.Utils;
import com.webank.wedpr.selectivedisclosure.CredentialTemplateEntity;
import com.webank.wedpr.selectivedisclosure.PredicateType;
Expand Down Expand Up @@ -724,7 +725,9 @@ private static ErrorCode verifyCptFormat(
return ErrorCode.CPT_JSON_SCHEMA_INVALID;
}
if (!isSelectivelyDisclosed) {
if (!DataToolUtils.isValidateJsonVersusSchema(claimStr, cptJsonSchema)) {
ProcessingReport checkRes = DataToolUtils.checkJsonVersusSchema(
claimStr, cptJsonSchema);
if (!checkRes.isSuccess()) {
logger.error(ErrorCode.CREDENTIAL_CLAIM_DATA_ILLEGAL.getCodeDesc());
return ErrorCode.CREDENTIAL_CLAIM_DATA_ILLEGAL;
}
Expand Down Expand Up @@ -2274,4 +2277,139 @@ public ResponseData<CredentialPojo> createDataAuthToken(
}
return resp;
}

@Override
public ResponseData<ProcessingReport> checkCredentialWithCpt(
CredentialPojo credential,
Cpt cpt
) {
try {
if (credential == null || credential.getSalt() == null
|| credential.getClaim() == null || credential.getType() == null) {
String errorMsg = ErrorCode.ILLEGAL_INPUT.getCodeDesc() + ": credential";
logger.error("[checkCredentialWithCpt] {}.", errorMsg);
return new ResponseData<>(null, ErrorCode.ILLEGAL_INPUT.getCode(), errorMsg);
}
if (cpt == null || cpt.getCptJsonSchema() == null) {
String errorMsg = ErrorCode.ILLEGAL_INPUT.getCodeDesc() + ": cpt";
logger.error("[checkCredentialWithCpt] {}.", errorMsg);
return new ResponseData<>(null, ErrorCode.ILLEGAL_INPUT.getCode(), errorMsg);
}
if (credential.getCptId().intValue() != cpt.getCptId().intValue()) {
logger.error("[checkCredentialWithCpt] the cptId does not match.");
return new ResponseData<>(null, ErrorCode.CREDENTIAL_CPTID_NOTMATCH);
}
// zkp不支持检查
if (credential.getCredentialType() == CredentialType.ZKP) {
logger.error("[checkCredentialWithCpt] ZKP Credential DO NOT support.");
return new ResponseData<>(null, ErrorCode.THIS_IS_UNSUPPORTED);
} else if (credential.getCredentialType() == CredentialType.ORIGINAL) {
// 如果不是lite1类型的,则判断是否为选择性披露类型
boolean isSelectivelyDisclosed = CredentialPojoUtils.isSelectivelyDisclosed(
credential.getSalt());
// 如果是选择性披露 则特殊处理
if (isSelectivelyDisclosed) {
// 做特殊处理逻辑: remove不披露的字段 并判断是否为必选字段,如果是必选字段 并且为不披露则检查失败
credential = DataToolUtils.clone(credential);
removeDisclosedFiledMap(
credential.getClaim(),
credential.getSalt(),
cpt.getCptJsonSchema()
);
}
}

String cptJsonSchema = DataToolUtils.serialize(cpt.getCptJsonSchema());
// 验证cp自身的合法性
if (!DataToolUtils.isCptJsonSchemaValid(cptJsonSchema)) {
logger.error("[checkCredentialWithCpt] the cpt invalid.");
return new ResponseData<>(null, ErrorCode.CPT_JSON_SCHEMA_INVALID);
}
String claimStr = DataToolUtils.serialize(credential.getClaim());
// 验证cpt与credential的匹配性
ProcessingReport checkRes = DataToolUtils.checkJsonVersusSchema(
claimStr, cptJsonSchema);
if (!checkRes.isSuccess()) {
logger.error(
"[checkCredentialWithCpt] check fail, ProcessingReport = {}.", checkRes);
ResponseData<ProcessingReport> result = new ResponseData<>(
checkRes,
ErrorCode.CREDENTIAL_DOES_NOT_MATCHE_THE_CPT
);
return result;
}
return new ResponseData<>(checkRes, ErrorCode.SUCCESS);
} catch (WeIdBaseException e) {
logger.error("[checkCredentialWithCpt] check has base exception.", e);
return new ResponseData<>(null, e.getErrorCode().getCode(), e.getMessage());
} catch (Exception e) {
logger.error("[checkCredentialWithCpt] check has unknown exception.", e);
return new ResponseData<>(null, ErrorCode.UNKNOW_ERROR);
}
}

// 移除不披露的字段
private void removeDisclosedFiledMap(
Map<String, Object> claim,
Map<String, Object> salt,
Map<String, Object> properties
) {
ArrayList<String> requireds = (ArrayList<String>)properties.get("required");
Map<String, Object> nextProperties = (Map<String, Object>)properties.get("properties");
// 遍历claim
for (Map.Entry<String, Object> entry : salt.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Map) {
// 说明下一层为map
removeDisclosedFiledMap(
(Map<String, Object>) claim.get(key),
(Map<String, Object>) value,
(Map<String, Object>) nextProperties.get(key)
);
} else if (value instanceof List) {
// 说明下一层是List
removeDisclosedFiledList(
(ArrayList<Object>) claim.get(key),
(ArrayList<Object>) value,
(Map<String, Object>) nextProperties.get(key));
} else {
// 说明当前层为需要处理的层
// 如果当前为不披露的key
// 1. 如果必须的key则报错
// 2. 否则移除此key
if ("0".equals(value.toString())) {
// 说明是选择性披露
if (requireds != null && requireds.contains(key)) {
throw new WeIdBaseException(key + " is required and disclosed.");
} else {
claim.remove(key);
}
}
}
}
}

private void removeDisclosedFiledList(
ArrayList<Object> claims,
ArrayList<Object> salts,
Map<String, Object> properties
) {
for (int i = 0; i < claims.size(); i++) {
Object claim = claims.get(i);
if (claim instanceof Map) {
removeDisclosedFiledMap(
(Map<String, Object>) claim,
(Map<String, Object>) salts.get(i),
(Map<String, Object>) properties.get("items")
);
} else {
removeDisclosedFiledList(
(ArrayList<Object>) claim,
(ArrayList<Object>) salts.get(i),
(Map<String, Object>) properties.get("items")
);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.Map;
import java.util.UUID;

import com.github.fge.jsonschema.core.report.ProcessingReport;
import org.apache.commons.lang3.StringUtils;
import org.bcos.web3j.abi.datatypes.Address;
import org.bcos.web3j.crypto.ECKeyPair;
Expand Down Expand Up @@ -442,7 +443,9 @@ private ErrorCode verifyCptFormat(Integer cptId, Map<String, Object> claim) {
logger.error(ErrorCode.CPT_JSON_SCHEMA_INVALID.getCodeDesc());
return ErrorCode.CPT_JSON_SCHEMA_INVALID;
}
if (!DataToolUtils.isValidateJsonVersusSchema(claimStr, cptJsonSchema)) {
ProcessingReport checkRes = DataToolUtils.checkJsonVersusSchema(
claimStr, cptJsonSchema);
if (!checkRes.isSuccess()) {
logger.error(ErrorCode.CREDENTIAL_CLAIM_DATA_ILLEGAL.getCodeDesc());
return ErrorCode.CREDENTIAL_CLAIM_DATA_ILLEGAL;
}
Expand Down
8 changes: 3 additions & 5 deletions src/main/java/com/webank/weid/util/DataToolUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -421,28 +421,26 @@ public static JsonNode loadJsonObject(String jsonString) throws IOException {
*
* @param jsonData the json data
* @param jsonSchema the json schema
* @return true if yes, false otherwise
* @return empty if yes, not empty otherwise
* @throws Exception the exception
*/
public static boolean isValidateJsonVersusSchema(String jsonData, String jsonSchema)
public static ProcessingReport checkJsonVersusSchema(String jsonData, String jsonSchema)
throws Exception {
JsonNode jsonDataNode = loadJsonObject(jsonData);
JsonNode jsonSchemaNode = loadJsonObject(jsonSchema);
JsonSchema schema = JsonSchemaFactory.byDefault().getJsonSchema(jsonSchemaNode);

ProcessingReport report = schema.validate(jsonDataNode);
if (report.isSuccess()) {
logger.info(report.toString());
return true;
} else {
Iterator<ProcessingMessage> it = report.iterator();
StringBuffer errorMsg = new StringBuffer();
while (it.hasNext()) {
errorMsg.append(it.next().getMessage());
}
logger.error("Json schema validator failed, error: {}", errorMsg.toString());
return false;
}
return report;
}

/**
Expand Down
9 changes: 4 additions & 5 deletions src/test/java/com/webank/weid/util/TestJsonUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@
package com.webank.weid.util;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;

import com.github.fge.jsonschema.core.report.ProcessingReport;
import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import org.junit.Test;
Expand All @@ -34,7 +33,6 @@
import com.webank.weid.constant.JsonSchemaConstant;
import com.webank.weid.protocol.base.Challenge;
import com.webank.weid.protocol.base.Credential;
import com.webank.weid.protocol.cpt.Cpt101;
import com.webank.weid.protocol.cpt.Cpt103;

public class TestJsonUtil {
Expand Down Expand Up @@ -98,8 +96,9 @@ public void testCptGenerator() throws Exception {
cpt103.setChallenge(Challenge.create("did:weid:0x11111", "abcd"));
cpt103.setProof("aaa");
cpt103.setId("did:weid:101:0x12221");
Assert.assertTrue(DataToolUtils
.isValidateJsonVersusSchema(DataToolUtils.objToJsonStrWithNoPretty(cpt103), cptSchema));
ProcessingReport checkRes = DataToolUtils.checkJsonVersusSchema(
DataToolUtils.objToJsonStrWithNoPretty(cpt103), cptSchema);
Assert.assertTrue(checkRes.isSuccess());

cptSchema = DataToolUtils.generateDefaultCptJsonSchema(105);
Assert.assertTrue(DataToolUtils.isCptJsonSchemaValid(cptSchema));
Expand Down

0 comments on commit 299a845

Please sign in to comment.