diff --git a/src/main/java/hlf/java/rest/client/service/impl/ChannelServiceImpl.java b/src/main/java/hlf/java/rest/client/service/impl/ChannelServiceImpl.java index bc38f8e4..ebe5b1b4 100644 --- a/src/main/java/hlf/java/rest/client/service/impl/ChannelServiceImpl.java +++ b/src/main/java/hlf/java/rest/client/service/impl/ChannelServiceImpl.java @@ -25,6 +25,7 @@ import org.hyperledger.fabric.protos.common.Common; import org.hyperledger.fabric.protos.common.Configtx; import org.hyperledger.fabric.protos.common.Configuration; +import org.hyperledger.fabric.protos.common.MspPrincipal; import org.hyperledger.fabric.protos.common.Policies; import org.hyperledger.fabric.protos.msp.MspConfigPackage; import org.hyperledger.fabric.sdk.Channel; @@ -353,15 +354,175 @@ private Configtx.ConfigGroup getMSPConfigGroup(hlf.java.rest.client.model.Peer p Map valueMap = new HashMap<>(); valueMap.put(FabricClientConstants.CHANNEL_CONFIG_GROUP_VALUE_MSP, getOrgMspValue(peer)); + // Organization's role policy defines what role can perform what operation + // For example, there are typically four roles policies defined + // 1. Endorsement + // 2. Admin + // 3. Readers + // 4. Writers + // The policy type used would be signature, so that the role + // binding can be done. return Configtx.ConfigGroup.newBuilder() .setVersion(EMPTY_VERSION) .putAllGroups(new HashMap<>()) .setModPolicy(EMPTY_MOD_POLICY) - .putAllPolicies(new HashMap<>()) + .putAllPolicies(getDefaultRolePolicy(peer.getMspid())) // Organization's role policies .putAllValues(valueMap) .build(); } + // The method returns a default policy for each organization + // that maps the roles. The policy type is signature. Roles + // are identified by their signatures, as those signatures + // represent the certificate. + private HashMap getDefaultRolePolicy(String orgMSPId) { + HashMap defaultOrgRolePolicy = new HashMap<>(); + // add Admins, Readers, Writers and Endorsement policies + defaultOrgRolePolicy.put( + FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_ADMINS, + getDefaultRoleConfigPolicyForMSP( + FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_ADMINS, orgMSPId)); + defaultOrgRolePolicy.put( + FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_READERS, + getDefaultRoleConfigPolicyForMSP( + FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_READERS, orgMSPId)); + defaultOrgRolePolicy.put( + FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_WRITERS, + getDefaultRoleConfigPolicyForMSP( + FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_WRITERS, orgMSPId)); + defaultOrgRolePolicy.put( + FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_ENDORSEMENT, + getDefaultRoleConfigPolicyForMSP( + FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_ENDORSEMENT, orgMSPId)); + return defaultOrgRolePolicy; + } + + // getRolesFor returns the SignaturePolicy that has MSP + // with the logical conditions. + // For example, it is possible to design OR(msp1.member, msp2.client) + // this evaluates to + // identities: { + // ... msp1 + // ... msp2 + // } + // n out of { + // n: 1 + // rules: { + // SignaturePolicy{index: 0} + // SignaturePolicy{index: 1} + // } + // } + private List getRolesFor(String policyFor, String orgMSPId) { + List mspPrincipals = new ArrayList<>(); + MspPrincipal.MSPRole mspRole; + MspPrincipal.MSPPrincipal mspPrincipal; + switch (policyFor) { + case FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_ADMINS: + mspRole = + MspPrincipal.MSPRole.newBuilder() + .setMspIdentifier(orgMSPId) + .setRole(MspPrincipal.MSPRole.MSPRoleType.ADMIN) + .build(); + mspPrincipal = + MspPrincipal.MSPPrincipal.newBuilder() + .setPrincipal(mspRole.toByteString()) + .setPrincipalClassification(MspPrincipal.MSPPrincipal.Classification.ROLE) + .build(); + mspPrincipals.add(mspPrincipal); + break; + case FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_WRITERS: + // any member who is an admin can write + mspRole = + MspPrincipal.MSPRole.newBuilder() + .setMspIdentifier(orgMSPId) + .setRole(MspPrincipal.MSPRole.MSPRoleType.ADMIN) + .build(); + mspPrincipal = + MspPrincipal.MSPPrincipal.newBuilder() + .setPrincipal(mspRole.toByteString()) + .setPrincipalClassification(MspPrincipal.MSPPrincipal.Classification.ROLE) + .build(); + mspPrincipals.add(mspPrincipal); + // any client can also write + mspRole = + MspPrincipal.MSPRole.newBuilder() + .setMspIdentifier(orgMSPId) + .setRole(MspPrincipal.MSPRole.MSPRoleType.CLIENT) + .build(); + mspPrincipal = + MspPrincipal.MSPPrincipal.newBuilder() + .setPrincipal(mspRole.toByteString()) + .setPrincipalClassification(MspPrincipal.MSPPrincipal.Classification.ROLE) + .build(); + mspPrincipals.add(mspPrincipal); + break; + case FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_ENDORSEMENT: + // any member who is peer can only endorse + mspRole = + MspPrincipal.MSPRole.newBuilder() + .setMspIdentifier(orgMSPId) + .setRole(MspPrincipal.MSPRole.MSPRoleType.PEER) + .build(); + mspPrincipal = + MspPrincipal.MSPPrincipal.newBuilder() + .setPrincipal(mspRole.toByteString()) + .setPrincipalClassification(MspPrincipal.MSPPrincipal.Classification.ROLE) + .build(); + mspPrincipals.add(mspPrincipal); + break; + case FabricClientConstants.CHANNEL_CONFIG_POLICY_TYPE_READERS: + // any member can read + mspRole = + MspPrincipal.MSPRole.newBuilder() + .setMspIdentifier(orgMSPId) + .setRole(MspPrincipal.MSPRole.MSPRoleType.MEMBER) + .build(); + mspPrincipal = + MspPrincipal.MSPPrincipal.newBuilder() + .setPrincipal(mspRole.toByteString()) + .setPrincipalClassification(MspPrincipal.MSPPrincipal.Classification.ROLE) + .build(); + mspPrincipals.add(mspPrincipal); + break; + } + return mspPrincipals; + } + + // The method returns a ConfigPolicy of type signature for the + // passed organization's MSP ID. + private Configtx.ConfigPolicy getDefaultRoleConfigPolicyForMSP( + String policyFor, String orgMSPId) { + List mspPrincipals = getRolesFor(policyFor, orgMSPId); + // loop through each entry and apply the n out of policy + // that is always get at least one signature. + // get the signature policy + // set rules + // create those roles + Policies.SignaturePolicyEnvelope.Builder signaturePolicyEnvelopeBuilder = + Policies.SignaturePolicyEnvelope.newBuilder(); + Policies.SignaturePolicy.Builder signaturePolicyBuilder = Policies.SignaturePolicy.newBuilder(); + Policies.SignaturePolicy.NOutOf.Builder signatureNOutOfBuilder = + Policies.SignaturePolicy.NOutOf.newBuilder().setN(1); // expect just one signature always + for (int idx = 0; idx < mspPrincipals.size(); idx++) { + signaturePolicyEnvelopeBuilder.setIdentities(idx, mspPrincipals.get(idx)); + signatureNOutOfBuilder.setRules( + idx, Policies.SignaturePolicy.newBuilder().setSignedBy(idx).build()); + } + signaturePolicyBuilder.setNOutOf(signatureNOutOfBuilder.build()); + signaturePolicyEnvelopeBuilder.setRule(signaturePolicyBuilder.build()); + // get the policy + Policies.Policy policy = + Policies.Policy.newBuilder() + .setType(Policies.Policy.PolicyType.SIGNATURE_VALUE) + .setValue(signaturePolicyEnvelopeBuilder.build().toByteString()) + .build(); + // create config policy and return + return Configtx.ConfigPolicy.newBuilder() + .setPolicy(policy) + .setModPolicy(FabricClientConstants.CHANNEL_CONFIG_MOD_POLICY_ADMINS) + .build(); + } + private Configtx.ConfigValue getOrgMspValue(hlf.java.rest.client.model.Peer peer) { return Configtx.ConfigValue.newBuilder() .setModPolicy(FabricClientConstants.CHANNEL_CONFIG_MOD_POLICY_ADMINS) @@ -492,7 +653,8 @@ private Policies.Policy getImplicitMetaPolicy(String subPolicyName, int rule) { * @param modPolicy * @return */ - private Configtx.ConfigPolicy getConfigPolicy(String subPolicyName, int rule, String modPolicy) { + private Configtx.ConfigPolicy getConfigPolicy( + String subPolicyName, int rule, String modPolicy) { return Configtx.ConfigPolicy.newBuilder() .setPolicy(getImplicitMetaPolicy(subPolicyName, rule)) .setModPolicy(modPolicy)