diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminDataset.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminDataset.java index cbc0af77..b85873a2 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminDataset.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerAdminDataset.java @@ -290,6 +290,10 @@ public class LedgerAdminDataset implements Transactional, LedgerAdminInfo { return participants.getParticipants(); } + ParticipantDataset getParticipantDataset() { + return participants; + } + /** * 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常; * diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerRepositoryImpl.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerRepositoryImpl.java index 66405cf4..45da206c 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerRepositoryImpl.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerRepositoryImpl.java @@ -30,7 +30,7 @@ import com.jd.blockchain.utils.codec.Base58Utils; * @author huanghaiquan * */ -public class LedgerRepositoryImpl implements LedgerRepository { +class LedgerRepositoryImpl implements LedgerRepository { private static final Bytes LEDGER_PREFIX = Bytes.fromString("IDX" + LedgerConsts.KEY_SEPERATOR); @@ -422,7 +422,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { private LedgerDataset innerGetLedgerDataset(LedgerBlock block) { LedgerAdminDataset adminDataset = createAdminDataset(block); CryptoSetting cryptoSetting = adminDataset.getSettings().getCryptoSetting(); - + UserAccountSet userAccountSet = createUserAccountSet(block, cryptoSetting); DataAccountSet dataAccountSet = createDataAccountSet(block, cryptoSetting); ContractAccountSet contractAccountSet = createContractAccountSet(block, cryptoSetting); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManager.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManager.java index aa0692a2..1ee72045 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManager.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManager.java @@ -2,37 +2,12 @@ package com.jd.blockchain.ledger.core; import java.util.Set; -import com.jd.blockchain.ledger.LedgerPrivilege; -import com.jd.blockchain.ledger.RolePrivileges; +import com.jd.blockchain.utils.Bytes; -/** - * - * {@link LedgerSecurityManager} implements the functions of security - * management, including authentication, authorization, data confidentiality, - * etc. - * - * @author huanghaiquan - * - */ -public class LedgerSecurityManager { - - public static final String ANONYMOUS_ROLE = "_ANONYMOUS"; - - public static final String DEFAULT_ROLE = "_DEFAULT"; - - - public Set getRoleNames(){ - throw new IllegalStateException("Not implemented!"); - } - - public RolePrivileges setRole(String role, LedgerPrivilege privilege) { - throw new IllegalStateException("Not implemented!"); - } +public interface LedgerSecurityManager { - public RolePrivileges getRole(String role) { - throw new IllegalStateException("Not implemented!"); - } - - - -} + String DEFAULT_ROLE = "_DEFAULT"; + + SecurityPolicy getSecurityPolicy(Set endpoints, Set nodes); + +} \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManagerImpl.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManagerImpl.java new file mode 100644 index 00000000..adfc33d8 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManagerImpl.java @@ -0,0 +1,287 @@ +package com.jd.blockchain.ledger.core; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.LedgerSecurityException; +import com.jd.blockchain.ledger.RolePrivilegeSettings; +import com.jd.blockchain.ledger.RolePrivileges; +import com.jd.blockchain.ledger.RolesPolicy; +import com.jd.blockchain.ledger.TransactionPermission; +import com.jd.blockchain.ledger.UserRoleSettings; +import com.jd.blockchain.ledger.UserRoles; +import com.jd.blockchain.utils.Bytes; + +/** + * 账本安全管理器; + * + * @author huanghaiquan + * + */ +public class LedgerSecurityManagerImpl implements LedgerSecurityManager { + + private RolePrivilegeSettings rolePrivilegeSettings; + + private UserRoleSettings userRolesSettings; + + private Map userPrivilegesCache = new ConcurrentHashMap<>(); + + private Map userRolesCache = new ConcurrentHashMap<>(); + private Map rolesPrivilegeCache = new ConcurrentHashMap<>(); + + public LedgerSecurityManagerImpl(RolePrivilegeSettings rolePrivilegeSettings, UserRoleSettings userRolesSettings) { + this.rolePrivilegeSettings = rolePrivilegeSettings; + this.userRolesSettings = userRolesSettings; + } + + @Override + public SecurityPolicy getSecurityPolicy(Set endpoints, Set nodes) { + + Map endpointPrivilegeMap = new HashMap<>(); + Map nodePrivilegeMap = new HashMap<>(); + + for (Bytes userAddress : endpoints) { + UserRolesPrivileges userPrivileges = getUserRolesPrivilegs(userAddress); + endpointPrivilegeMap.put(userAddress, userPrivileges); + } + + for (Bytes userAddress : nodes) { + UserRolesPrivileges userPrivileges = getUserRolesPrivilegs(userAddress); + nodePrivilegeMap.put(userAddress, userPrivileges); + } + + return new UserRolesSecurityPolicy(endpointPrivilegeMap, nodePrivilegeMap); + } + + private UserRolesPrivileges getUserRolesPrivilegs(Bytes userAddress) { + UserRolesPrivileges userPrivileges = userPrivilegesCache.get(userAddress); + if (userPrivileges != null) { + return userPrivileges; + } + + UserRoles userRoles = null; + + List privilegesList = new ArrayList<>(); + + // 加载用户的角色列表; + userRoles = userRolesCache.get(userAddress); + if (userRoles == null) { + userRoles = userRolesSettings.getUserRoles(userAddress); + if (userRoles != null) { + userRolesCache.put(userAddress, userRoles); + } + } + + // 计算用户的综合权限; + if (userRoles != null) { + String[] roles = userRoles.getRoles(); + RolePrivileges privilege = null; + for (String role : roles) { + // 先从缓存读取,如果没有再从原始数据源进行加载; + privilege = rolesPrivilegeCache.get(role); + if (privilege == null) { + privilege = rolePrivilegeSettings.getRolePrivilege(role); + if (privilege == null) { + // 略过不存在的无效角色; + continue; + } + rolesPrivilegeCache.put(role, privilege); + } + privilegesList.add(privilege); + } + } + // 如果用户未被授权任何角色,则采用默认角色的权限; + if (privilegesList.size() == 0) { + RolePrivileges privilege = getDefaultRolePrivilege(); + privilegesList.add(privilege); + } + + if (userRoles == null) { + userPrivileges = new UserRolesPrivileges(userAddress, RolesPolicy.UNION, privilegesList); + } else { + userPrivileges = new UserRolesPrivileges(userAddress, userRoles.getPolicy(), privilegesList); + } + + userPrivilegesCache.put(userAddress, userPrivileges); + return userPrivileges; + } + + private RolePrivileges getDefaultRolePrivilege() { + RolePrivileges privileges = rolesPrivilegeCache.get(DEFAULT_ROLE); + if (privileges == null) { + privileges = rolePrivilegeSettings.getRolePrivilege(DEFAULT_ROLE); + if (privileges == null) { + throw new LedgerSecurityException( + "This ledger is missing the default role-privilege settings for the users who don't have a role!"); + } + } + return privileges; + } + + private class UserRolesSecurityPolicy implements SecurityPolicy { + + /** + * 终端用户的权限表; + */ + private Map endpointPrivilegeMap = new HashMap<>(); + + /** + * 节点参与方的权限表; + */ + private Map nodePrivilegeMap = new HashMap<>(); + + public UserRolesSecurityPolicy(Map endpointPrivilegeMap, + Map nodePrivilegeMap) { + this.endpointPrivilegeMap = endpointPrivilegeMap; + this.nodePrivilegeMap = nodePrivilegeMap; + } + + @Override + public boolean isEnableToEndpoints(LedgerPermission permission, MultiIdsPolicy midPolicy) { + if (MultiIdsPolicy.AT_LEAST_ONE == midPolicy) { + // 至少一个; + for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { + if (p.getLedgerPrivileges().isEnable(permission)) { + return true; + } + } + return false; + } else if (MultiIdsPolicy.ALL == midPolicy) { + // 全部; + for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { + if (!p.getLedgerPrivileges().isEnable(permission)) { + return false; + } + } + return true; + } else { + throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); + } + } + + @Override + public boolean isEnableToEndpoints(TransactionPermission permission, MultiIdsPolicy midPolicy) { + if (MultiIdsPolicy.AT_LEAST_ONE == midPolicy) { + // 至少一个; + for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { + if (p.getTransactionPrivileges().isEnable(permission)) { + return true; + } + } + return false; + } else if (MultiIdsPolicy.ALL == midPolicy) { + // 全部; + for (UserRolesPrivileges p : endpointPrivilegeMap.values()) { + if (!p.getTransactionPrivileges().isEnable(permission)) { + return false; + } + } + return true; + } else { + throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); + } + } + + @Override + public boolean isEnableToNodes(LedgerPermission permission, MultiIdsPolicy midPolicy) { + if (MultiIdsPolicy.AT_LEAST_ONE == midPolicy) { + // 至少一个; + for (UserRolesPrivileges p : nodePrivilegeMap.values()) { + if (p.getLedgerPrivileges().isEnable(permission)) { + return true; + } + } + return false; + } else if (MultiIdsPolicy.ALL == midPolicy) { + // 全部; + for (UserRolesPrivileges p : nodePrivilegeMap.values()) { + if (!p.getLedgerPrivileges().isEnable(permission)) { + return false; + } + } + return true; + } else { + throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); + } + } + + @Override + public boolean isEnableToNodes(TransactionPermission permission, MultiIdsPolicy midPolicy) { + if (MultiIdsPolicy.AT_LEAST_ONE == midPolicy) { + // 至少一个; + for (UserRolesPrivileges p : nodePrivilegeMap.values()) { + if (p.getTransactionPrivileges().isEnable(permission)) { + return true; + } + } + return false; + } else if (MultiIdsPolicy.ALL == midPolicy) { + // 全部; + for (UserRolesPrivileges p : nodePrivilegeMap.values()) { + if (!p.getTransactionPrivileges().isEnable(permission)) { + return false; + } + } + return true; + } else { + throw new IllegalArgumentException("Unsupported MultiIdsPolicy[" + midPolicy + "]!"); + } + } + + @Override + public void checkEndpoints(LedgerPermission permission, MultiIdsPolicy midPolicy) + throws LedgerSecurityException { + if (!isEnableToEndpoints(permission, midPolicy)) { + throw new LedgerSecurityException(String.format( + "The security policy [Permission=%s, Policy=%s] for endpoints rejected the current operation!", + permission, midPolicy)); + } + } + + @Override + public void checkEndpoints(TransactionPermission permission, MultiIdsPolicy midPolicy) + throws LedgerSecurityException { + if (!isEnableToEndpoints(permission, midPolicy)) { + throw new LedgerSecurityException(String.format( + "The security policy [Permission=%s, Policy=%s] for endpoints rejected the current operation!", + permission, midPolicy)); + } + } + + @Override + public void checkNodes(LedgerPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException { + if (!isEnableToNodes(permission, midPolicy)) { + throw new LedgerSecurityException(String.format( + "The security policy [Permission=%s, Policy=%s] for nodes rejected the current operation!", + permission, midPolicy)); + } + } + + @Override + public void checkNodes(TransactionPermission permission, MultiIdsPolicy midPolicy) + throws LedgerSecurityException { + if (!isEnableToNodes(permission, midPolicy)) { + throw new LedgerSecurityException(String.format( + "The security policy [Permission=%s, Policy=%s] for nodes rejected the current operation!", + permission, midPolicy)); + } + } + + @Override + public Set getEndpoints() { + return endpointPrivilegeMap.keySet(); + } + + @Override + public Set getNodes() { + return nodePrivilegeMap.keySet(); + } + + } + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionalEditor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionalEditor.java index 4b9f33b5..a6395d92 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionalEditor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionalEditor.java @@ -214,32 +214,9 @@ public class LedgerTransactionalEditor implements LedgerEditor { return ledgerHash.equals(reqLedgerHash); } - private boolean verifyTxContent(TransactionRequest request) { - TransactionContent txContent = request.getTransactionContent(); - if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { - return false; - } - DigitalSignature[] endpointSignatures = request.getEndpointSignatures(); - if (endpointSignatures != null) { - for (DigitalSignature signature : endpointSignatures) { - if (!SignatureUtils.verifyHashSignature(txContent.getHash(), signature.getDigest(), - signature.getPubKey())) { - return false; - } - } - } - DigitalSignature[] nodeSignatures = request.getNodeSignatures(); - if (nodeSignatures != null) { - for (DigitalSignature signature : nodeSignatures) { - if (!SignatureUtils.verifyHashSignature(txContent.getHash(), signature.getDigest(), - signature.getPubKey())) { - return false; - } - } - } - return true; - } - + /** + * 注:此方法不验证交易完整性和签名有效性,仅仅设计为进行交易记录的管理;调用者应在此方法之外进行数据完整性和签名有效性的检查; + */ @Override public synchronized LedgerTransactionContext newTransaction(TransactionRequest txRequest) { // if (SettingContext.txSettings().verifyLedger() && !isRequestMatched(txRequest)) { @@ -250,15 +227,6 @@ public class LedgerTransactionalEditor implements LedgerEditor { TransactionState.IGNORED_BY_WRONG_LEDGER); } - // TODO: 把验签和创建交易并行化; -// if (SettingContext.txSettings().verifySignature() && !verifyTxContent(txRequest)) { - if (!verifyTxContent(txRequest)) { - // 抛弃哈希和签名校验失败的交易请求; - throw new IllegalTransactionException( - "Wrong transaction signature! --[TxHash=" + txRequest.getTransactionContent().getHash() + "]!", - TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); - } - if (currentTxCtx != null) { throw new IllegalStateException( "Unable to open another new transaction before the current transaction is completed! --[TxHash=" diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MultiIdsPolicy.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MultiIdsPolicy.java new file mode 100644 index 00000000..974eb203 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MultiIdsPolicy.java @@ -0,0 +1,21 @@ +package com.jd.blockchain.ledger.core; + +/** + * 多身份的权限校验策略; + * + * @author huanghaiquan + * + */ +public enum MultiIdsPolicy { + + /** + * 至少有一个都能通过; + */ + AT_LEAST_ONE, + + /** + * 每一个都能通过; + */ + ALL + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java index 02d0f453..94affc27 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandle.java @@ -3,7 +3,6 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.Operation; - public interface OperationHandle { /** @@ -18,36 +17,16 @@ public interface OperationHandle { * 同步解析和执行操作; * * - * @param op - * 操作实例; - * @param newBlockDataset - * 需要修改的新区块的数据集; - * @param requestContext - * 交易请求上下文; - * @param previousBlockDataset - * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; + * @param op 操作实例; + * @param newBlockDataset 需要修改的新区块的数据集; + * @param requestContext 交易请求上下文; + * @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集;注:此数据集是只读的; * - * @return 操作执行结果 + * @param handleContext 操作上下文;` + * @param ledgerService + * @return */ - BytesValue process(Operation op, LedgerDataset newBlockDataset, TransactionRequestContext requestContext, + BytesValue process(Operation op, LedgerDataset newBlockDataset, TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); -// /** -// * 异步解析和执行操作; -// * TODO 未来规划实现 -// * -// * -// * @param op -// * 操作实例; -// * @param newBlockDataset -// * 需要修改的新区块的数据集; -// * @param requestContext -// * 交易请求上下文; -// * @param previousBlockDataset -// * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; -// * -// * @return 操作执行结果 -// */ -// AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, -// LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandleContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandleContext.java index ab169976..1d837f15 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandleContext.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/OperationHandleContext.java @@ -2,8 +2,14 @@ package com.jd.blockchain.ledger.core; import com.jd.blockchain.ledger.Operation; +/** + * 在交易处理过程中,提供对多种交易操作处理器互相调用的机制; + * + * @author huanghaiquan + * + */ public interface OperationHandleContext { - + void handle(Operation operation); - + } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantDataset.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantDataset.java index 05267228..3185ae91 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantDataset.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ParticipantDataset.java @@ -77,6 +77,12 @@ public class ParticipantDataset implements Transactional, MerkleProvable { return address; } + public boolean contains(Bytes address) { + Bytes key = encodeKey(address); + long latestVersion = dataset.getVersion(key); + return latestVersion > -1; + } + /** * 返回指定地址的参与方凭证; * diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java index 56c98bf4..8798ca66 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/RolePrivilegeDataset.java @@ -7,6 +7,7 @@ import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.LedgerPermission; import com.jd.blockchain.ledger.LedgerPrivilege; import com.jd.blockchain.ledger.PrivilegeSet; +import com.jd.blockchain.ledger.Privileges; import com.jd.blockchain.ledger.RolePrivilegeSettings; import com.jd.blockchain.ledger.RolePrivileges; import com.jd.blockchain.ledger.TransactionPermission; @@ -61,9 +62,11 @@ public class RolePrivilegeDataset implements Transactional, MerkleProvable, Role return dataset.getDataCount(); } - /** - * - */ + @Override + public long addRolePrivilege(String roleName, Privileges privileges) { + return addRolePrivilege(roleName, privileges.getLedgerPrivilege(), privileges.getTransactionPrivilege()); + } + @Override public long addRolePrivilege(String roleName, LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { RolePrivileges roleAuth = new RolePrivileges(roleName, -1, ledgerPrivilege, txPrivilege); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityContext.java new file mode 100644 index 00000000..d3ad83ba --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityContext.java @@ -0,0 +1,38 @@ +package com.jd.blockchain.ledger.core; + +import java.util.Set; + +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.LedgerSecurityException; +import com.jd.blockchain.ledger.TransactionPermission; + +public class SecurityContext { + + private static ThreadLocal policyHolder = new ThreadLocal(); + + public static void setContextUsersPolicy(SecurityPolicy policy) { + policyHolder.set(policy); + } + + public static SecurityPolicy removeContextUsersPolicy() { + SecurityPolicy p = policyHolder.get(); + policyHolder.remove(); + return p; + } + + public static SecurityPolicy getContextUsersPolicy() { + return policyHolder.get(); + } + + /** + * 把上下文安全策略切换为指定的策略,并执行参数指定的 {@link Runnable} 操作,当操作完成后恢复原来的上下文策略; + * + * @param contextUsersPolicy + * @param runnable + */ + public static void switchContextUsersPolicy(SecurityPolicy contextUsersPolicy, Runnable runnable) { + + } + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityPolicy.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityPolicy.java new file mode 100644 index 00000000..78b85564 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SecurityPolicy.java @@ -0,0 +1,109 @@ +package com.jd.blockchain.ledger.core; + +import java.util.Set; + +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.LedgerSecurityException; +import com.jd.blockchain.ledger.TransactionPermission; +import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.utils.Bytes; + +/** + * 针对特定交易请求的账本安全策略; + * + * @author huanghaiquan + * + */ +public interface SecurityPolicy { + + /** + * 签署交易的终端用户的地址列表;(来自{@link TransactionRequest#getEndpointSignatures()}) + * + * @return + */ + Set getEndpoints(); + + /** + * 签署交易的节点参与方的地址列表(来自{@link TransactionRequest#getNodeSignatures()}) + * + * @return + */ + Set getNodes(); + + /** + * 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;
+ * + * @param permission 要检查的权限; + * @param midPolicy 针对多个签名用户的权限策略; + * @return 返回 true 表示获得授权; 返回 false 表示未获得授权; + */ + boolean isEnableToEndpoints(LedgerPermission permission, MultiIdsPolicy midPolicy); + + /** + * 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;
+ * + * @param permission 要检查的权限; + * @param midPolicy 针对多个签名用户的权限策略; + * @return 返回 true 表示获得授权; 返回 false 表示未获得授权; + */ + boolean isEnableToEndpoints(TransactionPermission permission, MultiIdsPolicy midPolicy); + + /** + * 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;
+ * + * @param permission 要检查的权限; + * @param midPolicy 针对多个签名用户的权限策略; + * @return 返回 true 表示获得授权; 返回 false 表示未获得授权; + */ + boolean isEnableToNodes(LedgerPermission permission, MultiIdsPolicy midPolicy); + + /** + * 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;
+ * + * @param permission 要检查的权限; + * @param midPolicy 针对多个签名用户的权限策略; + * @return 返回 true 表示获得授权; 返回 false 表示未获得授权; + */ + boolean isEnableToNodes(TransactionPermission permission, MultiIdsPolicy midPolicy); + + /** + * 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;
+ * 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; + * + * @param permission 要检查的权限; + * @param midPolicy 针对多个签名用户的权限策略; + * @throws LedgerSecurityException + */ + void checkEndpoints(LedgerPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException; + + /** + * 检查签署交易的终端用户(来自{@link TransactionRequest#getEndpointSignatures()})是否被授权了参数指定的权限;
+ * 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; + * + * @param permission + * @param midPolicy + * @throws LedgerSecurityException + */ + void checkEndpoints(TransactionPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException; + + /** + * 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;
+ * 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; + * + * @param permission + * @param midPolicy + * @throws LedgerSecurityException + */ + void checkNodes(LedgerPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException; + + /** + * 检查签署交易的节点参与方(来自{@link TransactionRequest#getNodeSignatures()})是否被授权了参数指定的权限;
+ * 如果未获授权,方法将引发 {@link LedgerSecurityException} 异常; + * + * @param permission + * @param midPolicy + * @throws LedgerSecurityException + */ + void checkNodes(TransactionPermission permission, MultiIdsPolicy midPolicy) throws LedgerSecurityException; + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java index 599041d0..96ebb5c4 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java @@ -1,6 +1,7 @@ package com.jd.blockchain.ledger.core; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -15,24 +16,32 @@ import com.jd.blockchain.ledger.DataAccountDoesNotExistException; import com.jd.blockchain.ledger.IllegalTransactionException; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerException; +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.LedgerSecurityException; import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.OperationResultData; +import com.jd.blockchain.ledger.ParticipantDoesNotExistException; +import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionRollbackException; import com.jd.blockchain.ledger.TransactionState; import com.jd.blockchain.ledger.UserDoesNotExistException; +import com.jd.blockchain.ledger.core.TransactionRequestExtension.Credential; import com.jd.blockchain.service.TransactionBatchProcess; import com.jd.blockchain.service.TransactionBatchResult; import com.jd.blockchain.service.TransactionBatchResultHandle; +import com.jd.blockchain.transaction.SignatureUtils; +import com.jd.blockchain.transaction.TxBuilder; import com.jd.blockchain.transaction.TxResponseMessage; -import com.jd.blockchain.utils.Bytes; public class TransactionBatchProcessor implements TransactionBatchProcess { private static final Logger LOGGER = LoggerFactory.getLogger(TransactionBatchProcessor.class); + private LedgerSecurityManager securityManager; + private LedgerService ledgerService; private LedgerEditor newBlockEditor; @@ -55,8 +64,9 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { * @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; * @param opHandles 操作处理对象注册表; */ - public TransactionBatchProcessor(LedgerEditor newBlockEditor, LedgerDataset previousBlockDataset, - OperationHandleRegisteration opHandles, LedgerService ledgerService) { + public TransactionBatchProcessor(LedgerSecurityManager securityManager, LedgerEditor newBlockEditor, + LedgerDataset previousBlockDataset, OperationHandleRegisteration opHandles, LedgerService ledgerService) { + this.securityManager = securityManager; this.newBlockEditor = newBlockEditor; this.previousBlockDataset = previousBlockDataset; this.opHandles = opHandles; @@ -76,12 +86,26 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { try { LOGGER.debug("Start handling transaction... --[BlockHeight={}][RequestHash={}][TxHash={}]", newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); + + TransactionRequestExtension reqExt = new TransactionRequestExtensionImpl(request); + + // 初始化交易的用户安全策略; + SecurityPolicy securityPolicy = securityManager.getSecurityPolicy(reqExt.getEndpointAddresses(), + reqExt.getNodeAddresses()); + SecurityContext.setContextUsersPolicy(securityPolicy); + + // 安全校验; + checkSecurity(); + + // 验证交易请求; + checkRequest(reqExt); + // 创建交易上下文; // 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上; LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request); // 处理交易; - resp = handleTx(request, txCtx); + resp = handleTx(reqExt, txCtx); LOGGER.debug("Complete handling transaction. --[BlockHeight={}][RequestHash={}][TxHash={}]", newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); @@ -93,10 +117,9 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { "Ignore transaction caused by IllegalTransactionException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), e.getMessage()), e); - + } catch (BlockRollbackException e) { - // 抛弃发生处理异常的交易请求; -// resp = discard(request, TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK); + // 发生区块级别的处理异常,向上重新抛出异常进行处理,整个区块可能被丢弃; LOGGER.error(String.format( "Ignore transaction caused by BlockRollbackException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), @@ -110,12 +133,86 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), e.getMessage()), e); + } finally { + // 清空交易的用户安全策略; + SecurityContext.removeContextUsersPolicy(); } responseList.add(resp); return resp; } + /** + * 验证交易的参与方的权限; + */ + private void checkSecurity() { + SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); + + // 验证当前交易请求的节点参与方是否具有权限; + securityPolicy.checkNodes(LedgerPermission.APPROVE_TX, MultiIdsPolicy.AT_LEAST_ONE); + } + + private void checkRequest(TransactionRequestExtension reqExt) { + // TODO: 把验签和创建交易并行化; + checkTxContent(reqExt); + checkEndpointSignatures(reqExt); + checkNodeSignatures(reqExt); + } + + private void checkTxContent(TransactionRequestExtension requestExt) { + TransactionContent txContent = requestExt.getTransactionContent(); + if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { + // 由于哈希校验失败,引发IllegalTransactionException,使外部调用抛弃此交易请求; + throw new IllegalTransactionException( + "Wrong transaction content hash! --[TxHash=" + requestExt.getTransactionContent().getHash() + "]!", + TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); + } + } + + private void checkEndpointSignatures(TransactionRequestExtension request) { + TransactionContent txContent = request.getTransactionContent(); + Collection endpoints = request.getEndpoints(); + if (endpoints != null) { + for (Credential endpoint : endpoints) { + if (!previousBlockDataset.getUserAccountSet().contains(endpoint.getAddress())) { + throw new UserDoesNotExistException( + "The endpoint signer[" + endpoint.getAddress() + "] was not registered!"); + } + + if (!SignatureUtils.verifyHashSignature(txContent.getHash(), endpoint.getSignature().getDigest(), + endpoint.getPubKey())) { + // 由于签名校验失败,引发IllegalTransactionException,使外部调用抛弃此交易请求; + throw new IllegalTransactionException( + String.format("Wrong transaction endpoint signature! --[Tx Hash=%s][Endpoint Signer=%s]!", + request.getTransactionContent().getHash(), endpoint.getAddress()), + TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); + } + } + } + } + + private void checkNodeSignatures(TransactionRequestExtension request) { + TransactionContent txContent = request.getTransactionContent(); + Collection nodes = request.getNodes(); + if (nodes != null) { + for (Credential node : nodes) { + if (!previousBlockDataset.getAdminDataset().getParticipantDataset().contains(node.getAddress())) { + throw new ParticipantDoesNotExistException( + "The node signer[" + node.getAddress() + "] was not registered to the participant set!"); + } + + if (!SignatureUtils.verifyHashSignature(txContent.getHash(), node.getSignature().getDigest(), + node.getPubKey())) { + // 由于签名校验失败,引发IllegalTransactionException,使外部调用抛弃此交易请求; + throw new IllegalTransactionException( + String.format("Wrong transaction node signature! --[Tx Hash=%s][Node Signer=%s]!", + request.getTransactionContent().getHash(), node.getAddress()), + TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); + } + } + } + } + /** * 处理交易;
* @@ -125,23 +222,11 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { * @param txCtx * @return */ - private TransactionResponse handleTx(TransactionRequest request, LedgerTransactionContext txCtx) { + private TransactionResponse handleTx(TransactionRequestExtension request, LedgerTransactionContext txCtx) { TransactionState result; List operationResults = new ArrayList<>(); try { LedgerDataset dataset = txCtx.getDataset(); - TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request); - // TODO: 验证签名者的有效性; - for (Bytes edpAddr : reqCtx.getEndpoints()) { - if (!previousBlockDataset.getUserAccountSet().contains(edpAddr)) { - throw new LedgerException("The endpoint signer[" + edpAddr + "] was not registered!"); - } - } - for (Bytes edpAddr : reqCtx.getNodes()) { - if (!previousBlockDataset.getUserAccountSet().contains(edpAddr)) { - throw new LedgerException("The node signer[" + edpAddr + "] was not registered!"); - } - } // 执行操作; Operation[] ops = request.getTransactionContent().getOperations(); @@ -151,14 +236,14 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { // assert; Instance of operation are one of User related operations or // DataAccount related operations; OperationHandle hdl = opHandles.getHandle(operation.getClass()); - hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService); + hdl.process(operation, dataset, request, previousBlockDataset, this, ledgerService); } }; OperationHandle opHandle; int opIndex = 0; for (Operation op : ops) { opHandle = opHandles.getHandle(op.getClass()); - BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, + BytesValue opResult = opHandle.process(op, dataset, request, previousBlockDataset, handleContext, ledgerService); if (opResult != null) { operationResults.add(new OperationResultData(opIndex, opResult)); @@ -177,6 +262,7 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), e.getMessage()), e); } catch (BlockRollbackException e) { + // 回滚整个区块; result = TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK; txCtx.rollback(); LOGGER.error( @@ -195,17 +281,27 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { result = TransactionState.USER_DOES_NOT_EXIST; } else if (e instanceof ContractDoesNotExistException) { result = TransactionState.CONTRACT_DOES_NOT_EXIST; + } else if (e instanceof ParticipantDoesNotExistException) { + result = TransactionState.PARTICIPANT_DOES_NOT_EXIST; } txCtx.discardAndCommit(result, operationResults); LOGGER.error(String.format( - "Due to ledger exception, the data changes resulting from the transaction will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + "Due to ledger exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), + e.getMessage()), e); + } catch (LedgerSecurityException e) { + // TODO: 识别更详细的异常类型以及执行对应的处理; + result = TransactionState.REJECTED_BY_SECURITY_POLICY; + txCtx.discardAndCommit(result, operationResults); + LOGGER.error(String.format( + "Due to ledger security exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), e.getMessage()), e); } catch (Exception e) { result = TransactionState.SYSTEM_ERROR; txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); LOGGER.error(String.format( - "Due to system exception, the data changes resulting from the transaction will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + "Due to system exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), e.getMessage()), e); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionEngineImpl.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionEngineImpl.java index c81cb1f9..d9d47840 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionEngineImpl.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionEngineImpl.java @@ -41,8 +41,12 @@ public class TransactionEngineImpl implements TransactionEngine { LedgerBlock ledgerBlock = ledgerRepo.getLatestBlock(); LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(ledgerBlock); - batch = new InnerTransactionBatchProcessor(ledgerHash, newBlockEditor, previousBlockDataset, opHdlRegs, - ledgerService, ledgerBlock.getHeight()); + + LedgerAdminDataset previousAdminDataset = previousBlockDataset.getAdminDataset(); + LedgerSecurityManager securityManager = new LedgerSecurityManagerImpl(previousAdminDataset.getRolePrivileges(), + previousAdminDataset.getUserRoles()); + batch = new InnerTransactionBatchProcessor(ledgerHash, securityManager, newBlockEditor, previousBlockDataset, + opHdlRegs, ledgerService, ledgerBlock.getHeight()); batchs.put(ledgerHash, batch); return batch; } @@ -65,19 +69,15 @@ public class TransactionEngineImpl implements TransactionEngine { /** * 创建交易批处理器; * - * @param ledgerHash - * 账本哈希; - * @param newBlockEditor - * 新区块的数据编辑器; - * @param previousBlockDataset - * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; - * @param opHandles - * 操作处理对象注册表; + * @param ledgerHash 账本哈希; + * @param newBlockEditor 新区块的数据编辑器; + * @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; + * @param opHandles 操作处理对象注册表; */ - public InnerTransactionBatchProcessor(HashDigest ledgerHash, LedgerEditor newBlockEditor, - LedgerDataset previousBlockDataset, OperationHandleRegisteration opHandles, + public InnerTransactionBatchProcessor(HashDigest ledgerHash, LedgerSecurityManager securityManager, + LedgerEditor newBlockEditor, LedgerDataset previousBlockDataset, OperationHandleRegisteration opHandles, LedgerService ledgerService, long blockHeight) { - super(newBlockEditor, previousBlockDataset, opHandles, ledgerService); + super(securityManager, newBlockEditor, previousBlockDataset, opHandles, ledgerService); this.ledgerHash = ledgerHash; this.blockHeight = blockHeight; } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestContext.java deleted file mode 100644 index 324c4e0e..00000000 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestContext.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.jd.blockchain.ledger.core; - -import java.util.Set; - -import com.jd.blockchain.ledger.DigitalSignature; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.utils.Bytes; - -/** - * 交易请求上下文; - * - * @author huanghaiquan - * - */ -public interface TransactionRequestContext { - - /** - * 交易请求; - * - * @return - */ - TransactionRequest getRequest(); - - /** - * 签名发起请求的终端用户的地址列表; - * - * @return - */ - Set getEndpoints(); - - /** - * 签名发起请求的节点的地址列表; - * - * @return - */ - Set getNodes(); - - /** - * 请求的终端发起人列表中是否包含指定地址的终端用户; - * - * @param address - * @return - */ - boolean containsEndpoint(Bytes address); - - /** - * 请求的经手节点列表中是否包含指定地址的节点; - * - * @param address - * @return - */ - boolean containsNode(Bytes address); - - /** - * 获取交易请求中指定地址的终端的签名; - * - * @param address - * @return - */ - DigitalSignature getEndpointSignature(Bytes address); - - /** - * 获取交易请求中指定地址的节点的签名; - * - * @param address - * @return - */ - DigitalSignature getNodeSignature(Bytes address); - -} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestContextImpl.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestContextImpl.java deleted file mode 100644 index 3348a342..00000000 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestContextImpl.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.jd.blockchain.ledger.core; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.jd.blockchain.crypto.AddressEncoding; -import com.jd.blockchain.ledger.DigitalSignature; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.utils.Bytes; - -/** - * @Author zhaogw - * @Date 2018/9/5 14:52 - */ -public class TransactionRequestContextImpl implements TransactionRequestContext { - - private TransactionRequest request; - - private Map endpointSignatures = new HashMap<>(); - - private Map nodeSignatures = new HashMap<>(); - - public TransactionRequestContextImpl(TransactionRequest request) { - this.request = request; - resolveSigners(); - } - - private void resolveSigners() { - if (request.getEndpointSignatures() != null) { - for (DigitalSignature signature : request.getEndpointSignatures()) { - Bytes address = AddressEncoding.generateAddress(signature.getPubKey()); - endpointSignatures.put(address, signature); - } - } - if (request.getEndpointSignatures() != null) { - for (DigitalSignature signature : request.getNodeSignatures()) { - Bytes address = AddressEncoding.generateAddress(signature.getPubKey()); - nodeSignatures.put(address, signature); - } - } - } - - @Override - public TransactionRequest getRequest() { - return request; - } - - @Override - public Set getEndpoints() { - return endpointSignatures.keySet(); - } - - @Override - public Set getNodes() { - return nodeSignatures.keySet(); - } - - @Override - public boolean containsEndpoint(Bytes address) { - return endpointSignatures.containsKey(address); - } - - @Override - public boolean containsNode(Bytes address) { - return nodeSignatures.containsKey(address); - } - - @Override - public DigitalSignature getEndpointSignature(Bytes address) { - return endpointSignatures.get(address); - } - - @Override - public DigitalSignature getNodeSignature(Bytes address) { - return nodeSignatures.get(address); - } - -} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestExtension.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestExtension.java new file mode 100644 index 00000000..ec6b1122 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestExtension.java @@ -0,0 +1,115 @@ +package com.jd.blockchain.ledger.core; + +import java.util.Collection; +import java.util.Set; + +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.BlockchainIdentity; +import com.jd.blockchain.ledger.BlockchainIdentityData; +import com.jd.blockchain.ledger.DigitalSignature; +import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.utils.Bytes; + +/** + * 交易请求上下文; + * + * @author huanghaiquan + * + */ +public interface TransactionRequestExtension extends TransactionRequest { + +// /** +// * 交易请求; +// * +// * @return +// */ +// TransactionRequest getRequest(); + + /** + * 签名发起请求的终端用户的地址列表; + * + * @return + */ + Set getEndpointAddresses(); + + /** + * 签名发起请求的终端用户列表; + * + * @return + */ + Collection getEndpoints(); + + /** + * 签名发起请求的节点的地址列表; + * + * @return + */ + Set getNodeAddresses(); + + /** + * 签名发起请求的节点列表; + * + * @return + */ + Collection getNodes(); + + /** + * 请求的终端发起人列表中是否包含指定地址的终端用户; + * + * @param address + * @return + */ + boolean containsEndpoint(Bytes address); + + /** + * 请求的经手节点列表中是否包含指定地址的节点; + * + * @param address + * @return + */ + boolean containsNode(Bytes address); + + /** + * 获取交易请求中指定地址的终端的签名; + * + * @param address + * @return + */ + DigitalSignature getEndpointSignature(Bytes address); + + /** + * 获取交易请求中指定地址的节点的签名; + * + * @param address + * @return + */ + DigitalSignature getNodeSignature(Bytes address); + + public static class Credential { + + private final BlockchainIdentity identity; + + private final DigitalSignature signature; + + Credential(DigitalSignature signature) { + this.identity = new BlockchainIdentityData(signature.getPubKey()); + this.signature = signature; + } + + public Bytes getAddress() { + return identity.getAddress(); + } + + public PubKey getPubKey() { + return identity.getPubKey(); + } + + public BlockchainIdentity getIdentity() { + return identity; + } + + public DigitalSignature getSignature() { + return signature; + } + } +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestExtensionImpl.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestExtensionImpl.java new file mode 100644 index 00000000..1d93fbbe --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionRequestExtensionImpl.java @@ -0,0 +1,108 @@ +package com.jd.blockchain.ledger.core; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.DigitalSignature; +import com.jd.blockchain.ledger.TransactionContent; +import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.utils.Bytes; + +/** + * 交易请求的扩展信息; + * + * @author huanghaiquan + * + */ +public class TransactionRequestExtensionImpl implements TransactionRequestExtension { + + private TransactionRequest request; + + private Map endpointSignatures = new HashMap<>(); + + private Map nodeSignatures = new HashMap<>(); + + public TransactionRequestExtensionImpl(TransactionRequest request) { + this.request = request; + resolveSigners(); + } + + private void resolveSigners() { + if (request.getEndpointSignatures() != null) { + for (DigitalSignature signature : request.getEndpointSignatures()) { + Credential cred = new Credential(signature); + endpointSignatures.put(cred.getIdentity().getAddress(), cred); + } + } + if (request.getEndpointSignatures() != null) { + for (DigitalSignature signature : request.getNodeSignatures()) { + Credential cred = new Credential(signature); + nodeSignatures.put(cred.getIdentity().getAddress(), cred); + } + } + } + + @Override + public Set getEndpointAddresses() { + return endpointSignatures.keySet(); + } + + @Override + public Set getNodeAddresses() { + return nodeSignatures.keySet(); + } + + @Override + public Collection getEndpoints() { + return endpointSignatures.values(); + } + + @Override + public Collection getNodes() { + return nodeSignatures.values(); + } + + @Override + public boolean containsEndpoint(Bytes address) { + return endpointSignatures.containsKey(address); + } + + @Override + public boolean containsNode(Bytes address) { + return nodeSignatures.containsKey(address); + } + + @Override + public DigitalSignature getEndpointSignature(Bytes address) { + return endpointSignatures.get(address).getSignature(); + } + + @Override + public DigitalSignature getNodeSignature(Bytes address) { + return nodeSignatures.get(address).getSignature(); + } + + @Override + public HashDigest getHash() { + return request.getHash(); + } + + @Override + public DigitalSignature[] getNodeSignatures() { + return request.getNodeSignatures(); + } + + @Override + public DigitalSignature[] getEndpointSignatures() { + return request.getEndpointSignatures(); + } + + @Override + public TransactionContent getTransactionContent() { + return request.getTransactionContent(); + } + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserRolesPrivileges.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserRolesPrivileges.java new file mode 100644 index 00000000..4a626c70 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/UserRolesPrivileges.java @@ -0,0 +1,63 @@ +package com.jd.blockchain.ledger.core; + +import java.util.Collection; + +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.LedgerPrivilege; +import com.jd.blockchain.ledger.PrivilegeBitset; +import com.jd.blockchain.ledger.RolePrivileges; +import com.jd.blockchain.ledger.RolesPolicy; +import com.jd.blockchain.ledger.TransactionPermission; +import com.jd.blockchain.ledger.TransactionPrivilege; +import com.jd.blockchain.utils.Bytes; + +/** + * {@link UserRolesPrivileges} 表示多角色用户的综合权限; + * + * @author huanghaiquan + * + */ +class UserRolesPrivileges { + + private Bytes userAddress; + + private PrivilegeBitset ledgerPrivileges; + + private PrivilegeBitset transactionPrivileges; + + public UserRolesPrivileges(Bytes userAddress, RolesPolicy policy, Collection privilegesList) { + this.userAddress = userAddress; + LedgerPrivilege[] ledgerPrivileges = privilegesList.stream().map(p -> p.getLedgerPrivilege()) + .toArray(LedgerPrivilege[]::new); + TransactionPrivilege[] transactionPrivileges = privilegesList.stream().map(p -> p.getTransactionPrivilege()) + .toArray(TransactionPrivilege[]::new); + + this.ledgerPrivileges = ledgerPrivileges[0].clone(); + this.transactionPrivileges = transactionPrivileges[0].clone(); + + if (policy == RolesPolicy.UNION) { + this.ledgerPrivileges.union(ledgerPrivileges, 1, ledgerPrivileges.length - 1); + this.transactionPrivileges.union(transactionPrivileges, 1, transactionPrivileges.length - 1); + + } else if (policy == RolesPolicy.INTERSECT) { + this.ledgerPrivileges.intersect(ledgerPrivileges, 1, ledgerPrivileges.length - 1); + this.transactionPrivileges.intersect(transactionPrivileges, 1, transactionPrivileges.length - 1); + } else { + throw new IllegalStateException("Unsupported roles policy[" + policy.toString() + "]!"); + } + + } + + public Bytes getUserAddress() { + return userAddress; + } + + public PrivilegeBitset getLedgerPrivileges() { + return ledgerPrivileges; + } + + public PrivilegeBitset getTransactionPrivileges() { + return transactionPrivileges; + } + +} \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/AbstractLedgerOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/AbstractLedgerOperationHandle.java new file mode 100644 index 00000000..311dc9d5 --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/AbstractLedgerOperationHandle.java @@ -0,0 +1,67 @@ +package com.jd.blockchain.ledger.core.handles; + +import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.Operation; +import com.jd.blockchain.ledger.TransactionPermission; +import com.jd.blockchain.ledger.core.LedgerDataset; +import com.jd.blockchain.ledger.core.LedgerService; +import com.jd.blockchain.ledger.core.MultiIdsPolicy; +import com.jd.blockchain.ledger.core.OperationHandle; +import com.jd.blockchain.ledger.core.OperationHandleContext; +import com.jd.blockchain.ledger.core.SecurityContext; +import com.jd.blockchain.ledger.core.SecurityPolicy; +import com.jd.blockchain.ledger.core.TransactionRequestExtension; + +/** + * 执行直接账本操作的处理类; + * + * @author huanghaiquan + * + * @param + */ +public abstract class AbstractLedgerOperationHandle implements OperationHandle { + + static { + DataContractRegistry.register(BytesValue.class); + } + + private final Class SUPPORTED_OPERATION_TYPE; + + public AbstractLedgerOperationHandle(Class supportedOperationType) { + this.SUPPORTED_OPERATION_TYPE = supportedOperationType; + } + + @Override + public final boolean support(Class operationType) { + return SUPPORTED_OPERATION_TYPE.isAssignableFrom(operationType); + } + + @Override + public final BytesValue process(Operation op, LedgerDataset newBlockDataset, + TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, + OperationHandleContext handleContext, LedgerService ledgerService) { + // 权限校验; + SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); + securityPolicy.checkEndpoints(TransactionPermission.DIRECT_OPERATION, MultiIdsPolicy.AT_LEAST_ONE); + + // 操作账本; + @SuppressWarnings("unchecked") + T concretedOp = (T) op; + doProcess(concretedOp, newBlockDataset, requestContext, previousBlockDataset, handleContext, ledgerService); + + // 账本操作没有返回值; + return null; + } + + /** + * @param op + * @param newBlockDataset + * @param requestContext + * @param previousBlockDataset + * @param handleContext + * @param ledgerService + */ + protected abstract void doProcess(T op, LedgerDataset newBlockDataset, TransactionRequestExtension requestContext, + LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService); +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/AbtractContractEventHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/AbtractContractEventHandle.java index 09b25e28..8a410f1a 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/AbtractContractEventHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/AbtractContractEventHandle.java @@ -8,14 +8,18 @@ import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractEventSendOperation; import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.Operation; +import com.jd.blockchain.ledger.TransactionPermission; import com.jd.blockchain.ledger.core.ContractAccount; import com.jd.blockchain.ledger.core.ContractAccountSet; import com.jd.blockchain.ledger.core.LedgerDataset; import com.jd.blockchain.ledger.core.LedgerQueryService; import com.jd.blockchain.ledger.core.LedgerService; +import com.jd.blockchain.ledger.core.MultiIdsPolicy; import com.jd.blockchain.ledger.core.OperationHandle; import com.jd.blockchain.ledger.core.OperationHandleContext; -import com.jd.blockchain.ledger.core.TransactionRequestContext; +import com.jd.blockchain.ledger.core.SecurityContext; +import com.jd.blockchain.ledger.core.SecurityPolicy; +import com.jd.blockchain.ledger.core.TransactionRequestExtension; @Service public abstract class AbtractContractEventHandle implements OperationHandle { @@ -26,9 +30,22 @@ public abstract class AbtractContractEventHandle implements OperationHandle { } @Override - public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataset newBlockDataset, TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { + // 权限校验; + SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); + securityPolicy.checkEndpoints(TransactionPermission.CONTRACT_OPERATION, MultiIdsPolicy.AT_LEAST_ONE); + + // 操作账本; ContractEventSendOperation contractOP = (ContractEventSendOperation) op; + + return doProcess(requestContext, contractOP, newBlockDataset, previousBlockDataset, opHandleContext, + ledgerService); + } + + private BytesValue doProcess(TransactionRequestExtension request, ContractEventSendOperation contractOP, + LedgerDataset newBlockDataset, LedgerDataset previousBlockDataset, OperationHandleContext opHandleContext, + LedgerService ledgerService) { // 先从账本校验合约的有效性; // 注意:必须在前一个区块的数据集中进行校验,因为那是经过共识的数据;从当前新区块链数据集校验则会带来攻击风险:未经共识的合约得到执行; ContractAccountSet contractSet = previousBlockDataset.getContractAccountset(); @@ -50,19 +67,17 @@ public abstract class AbtractContractEventHandle implements OperationHandle { // 创建合约上下文; LocalContractEventContext localContractEventContext = new LocalContractEventContext( - requestContext.getRequest().getTransactionContent().getLedgerHash(), contractOP.getEvent()); - localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(requestContext.getRequest()) + request.getTransactionContent().getLedgerHash(), contractOP.getEvent()); + localContractEventContext.setArgs(contractOP.getArgs()).setTransactionRequest(request) .setLedgerContext(ledgerContext); - // 装载合约; ContractCode contractCode = loadContractCode(contract); // 处理合约事件; return contractCode.processEvent(localContractEventContext); } - - protected abstract ContractCode loadContractCode(ContractAccount contract); + protected abstract ContractCode loadContractCode(ContractAccount contract); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractCodeDeployOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractCodeDeployOperationHandle.java index c4ae6ce7..6e0d68b8 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractCodeDeployOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/ContractCodeDeployOperationHandle.java @@ -1,41 +1,36 @@ package com.jd.blockchain.ledger.core.handles; -import org.springframework.stereotype.Service; - -import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.ContractCodeDeployOperation; -import com.jd.blockchain.ledger.Operation; +import com.jd.blockchain.ledger.LedgerPermission; import com.jd.blockchain.ledger.core.LedgerDataset; import com.jd.blockchain.ledger.core.LedgerService; -import com.jd.blockchain.ledger.core.OperationHandle; +import com.jd.blockchain.ledger.core.MultiIdsPolicy; import com.jd.blockchain.ledger.core.OperationHandleContext; -import com.jd.blockchain.ledger.core.TransactionRequestContext; +import com.jd.blockchain.ledger.core.SecurityContext; +import com.jd.blockchain.ledger.core.SecurityPolicy; +import com.jd.blockchain.ledger.core.TransactionRequestExtension; -@Service -public class ContractCodeDeployOperationHandle implements OperationHandle { +public class ContractCodeDeployOperationHandle extends AbstractLedgerOperationHandle { + public ContractCodeDeployOperationHandle() { + super(ContractCodeDeployOperation.class); + } @Override - public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, - LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { - ContractCodeDeployOperation contractOP = (ContractCodeDeployOperation) op; + protected void doProcess(ContractCodeDeployOperation op, LedgerDataset newBlockDataset, + TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, + OperationHandleContext handleContext, LedgerService ledgerService) { // TODO: 校验合约代码的正确性; - - // TODO: 请求者应该提供合约账户的公钥签名,已确定注册的地址的唯一性; - dataset.getContractAccountset().deploy(contractOP.getContractID().getAddress(), - contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), contractOP.getChainCode()); + // TODO: 请求者应该提供合约账户的公钥签名,以确保注册人对注册的地址和公钥具有合法的使用权; - return null; - } + // 权限校验; + SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); + securityPolicy.checkEndpoints(LedgerPermission.UPGRADE_CONTRACT, MultiIdsPolicy.AT_LEAST_ONE); -// @Override -// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { -// return null; -// } - - @Override - public boolean support(Class operationType) { - return ContractCodeDeployOperation.class.isAssignableFrom(operationType); + // 操作账本; + ContractCodeDeployOperation contractOP = (ContractCodeDeployOperation) op; + newBlockDataset.getContractAccountset().deploy(contractOP.getContractID().getAddress(), + contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), contractOP.getChainCode()); } } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountKVSetOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountKVSetOperationHandle.java index c3bc832d..52801883 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountKVSetOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountKVSetOperationHandle.java @@ -1,32 +1,34 @@ package com.jd.blockchain.ledger.core.handles; -import org.springframework.stereotype.Service; - -import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataAccountDoesNotExistException; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.ledger.DataAccountKVSetOperation.KVWriteEntry; -import com.jd.blockchain.ledger.Operation; +import com.jd.blockchain.ledger.LedgerPermission; import com.jd.blockchain.ledger.core.DataAccount; import com.jd.blockchain.ledger.core.LedgerDataset; import com.jd.blockchain.ledger.core.LedgerService; -import com.jd.blockchain.ledger.core.OperationHandle; +import com.jd.blockchain.ledger.core.MultiIdsPolicy; import com.jd.blockchain.ledger.core.OperationHandleContext; -import com.jd.blockchain.ledger.core.TransactionRequestContext; +import com.jd.blockchain.ledger.core.SecurityContext; +import com.jd.blockchain.ledger.core.SecurityPolicy; +import com.jd.blockchain.ledger.core.TransactionRequestExtension; import com.jd.blockchain.utils.Bytes; -@Service -public class DataAccountKVSetOperationHandle implements OperationHandle { - static { - DataContractRegistry.register(BytesValue.class); +public class DataAccountKVSetOperationHandle extends AbstractLedgerOperationHandle { + public DataAccountKVSetOperationHandle() { + super(DataAccountKVSetOperation.class); } @Override - public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, - LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { - DataAccountKVSetOperation kvWriteOp = (DataAccountKVSetOperation) op; - DataAccount account = dataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress()); + protected void doProcess(DataAccountKVSetOperation kvWriteOp, LedgerDataset newBlockDataset, + TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, + OperationHandleContext handleContext, LedgerService ledgerService) { + // 权限校验; + SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); + securityPolicy.checkEndpoints(LedgerPermission.WRITE_DATA_ACCOUNT, MultiIdsPolicy.AT_LEAST_ONE); + + // 操作账本; + DataAccount account = newBlockDataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress()); if (account == null) { throw new DataAccountDoesNotExistException("DataAccount doesn't exist!"); } @@ -34,17 +36,7 @@ public class DataAccountKVSetOperationHandle implements OperationHandle { for (KVWriteEntry kvw : writeSet) { account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion()); } - return null; } -// @Override -// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { -// return null; -// } - - @Override - public boolean support(Class operationType) { - return DataAccountKVSetOperation.class.isAssignableFrom(operationType); - } } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountRegisterOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountRegisterOperationHandle.java index 4b4c87b0..06fe0746 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountRegisterOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/DataAccountRegisterOperationHandle.java @@ -1,42 +1,35 @@ package com.jd.blockchain.ledger.core.handles; -import org.springframework.stereotype.Service; - import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataAccountRegisterOperation; -import com.jd.blockchain.ledger.Operation; +import com.jd.blockchain.ledger.LedgerPermission; import com.jd.blockchain.ledger.core.LedgerDataset; import com.jd.blockchain.ledger.core.LedgerService; -import com.jd.blockchain.ledger.core.OperationHandle; +import com.jd.blockchain.ledger.core.MultiIdsPolicy; import com.jd.blockchain.ledger.core.OperationHandleContext; -import com.jd.blockchain.ledger.core.TransactionRequestContext; - -@Service -public class DataAccountRegisterOperationHandle implements OperationHandle { - - @Override - public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, - LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { - DataAccountRegisterOperation dataAccountRegOp = (DataAccountRegisterOperation) op; - BlockchainIdentity bid = dataAccountRegOp.getAccountID(); +import com.jd.blockchain.ledger.core.SecurityContext; +import com.jd.blockchain.ledger.core.SecurityPolicy; +import com.jd.blockchain.ledger.core.TransactionRequestExtension; - //TODO: 校验用户身份; - - //TODO: 请求者应该提供数据账户的公钥签名,已确定注册的地址的唯一性; - dataset.getDataAccountSet().register(bid.getAddress(), bid.getPubKey(), null); - - return null; +public class DataAccountRegisterOperationHandle extends AbstractLedgerOperationHandle { + public DataAccountRegisterOperationHandle() { + super(DataAccountRegisterOperation.class); } + + @Override + protected void doProcess(DataAccountRegisterOperation op, LedgerDataset newBlockDataset, + TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, + OperationHandleContext handleContext, LedgerService ledgerService) { + // TODO: 请求者应该提供数据账户的公钥签名,以更好地确保注册人对该地址和公钥具有合法使用权; -// @Override -// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { -// return null; -// } + // 权限校验; + SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); + securityPolicy.checkEndpoints(LedgerPermission.REGISTER_DATA_ACCOUNT, MultiIdsPolicy.AT_LEAST_ONE); - @Override - public boolean support(Class operationType) { - return DataAccountRegisterOperation.class.isAssignableFrom(operationType); + // 操作账本; + DataAccountRegisterOperation dataAccountRegOp = (DataAccountRegisterOperation) op; + BlockchainIdentity bid = dataAccountRegOp.getAccountID(); + newBlockDataset.getDataAccountSet().register(bid.getAddress(), bid.getPubKey(), null); } } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/JVMContractEventSendOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/JVMContractEventSendOperationHandle.java index 5107ffd5..018c4d8a 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/JVMContractEventSendOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/JVMContractEventSendOperationHandle.java @@ -26,12 +26,4 @@ public class JVMContractEventSendOperationHandle extends AbtractContractEventHan return contractCode; } -// @Override -// public AsyncFuture asyncProcess(Operation op, LedgerDataSet newBlockDataset, -// TransactionRequestContext requestContext, LedgerDataSet previousBlockDataset, -// OperationHandleContext handleContext, LedgerService ledgerService) { -// // TODO Auto-generated method stub -// return null; -// } - } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/UserRegisterOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/UserRegisterOperationHandle.java index bceaaa2a..6a399e71 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/UserRegisterOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/handles/UserRegisterOperationHandle.java @@ -1,37 +1,37 @@ package com.jd.blockchain.ledger.core.handles; import com.jd.blockchain.ledger.BlockchainIdentity; -import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.Operation; +import com.jd.blockchain.ledger.LedgerPermission; import com.jd.blockchain.ledger.UserRegisterOperation; import com.jd.blockchain.ledger.core.LedgerDataset; import com.jd.blockchain.ledger.core.LedgerService; -import com.jd.blockchain.ledger.core.OperationHandle; +import com.jd.blockchain.ledger.core.MultiIdsPolicy; import com.jd.blockchain.ledger.core.OperationHandleContext; -import com.jd.blockchain.ledger.core.TransactionRequestContext; +import com.jd.blockchain.ledger.core.SecurityContext; +import com.jd.blockchain.ledger.core.SecurityPolicy; +import com.jd.blockchain.ledger.core.TransactionRequestExtension; import com.jd.blockchain.utils.Bytes; - -public class UserRegisterOperationHandle implements OperationHandle { +public class UserRegisterOperationHandle extends AbstractLedgerOperationHandle { + public UserRegisterOperationHandle() { + super(UserRegisterOperation.class); + } @Override - public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, - LedgerDataset previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { - - + protected void doProcess(UserRegisterOperation op, LedgerDataset newBlockDataset, + TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, + OperationHandleContext handleContext, LedgerService ledgerService) { + // 权限校验; + SecurityPolicy securityPolicy = SecurityContext.getContextUsersPolicy(); + securityPolicy.checkEndpoints(LedgerPermission.REGISTER_USER, MultiIdsPolicy.AT_LEAST_ONE); + + // 操作账本; UserRegisterOperation userRegOp = (UserRegisterOperation) op; BlockchainIdentity bid = userRegOp.getUserID(); Bytes userAddress = bid.getAddress(); - dataset.getUserAccountSet().register(userAddress, bid.getPubKey()); - - return null; - } - - @Override - public boolean support(Class operationType) { - return UserRegisterOperation.class.isAssignableFrom(operationType); + newBlockDataset.getUserAccountSet().register(userAddress, bid.getPubKey()); } } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java index e7e59409..f7821564 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java @@ -15,6 +15,7 @@ import org.mockito.Mockito; import java.util.Random; import static org.junit.Assert.*; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.*; @@ -65,15 +66,15 @@ public class ContractInvokingTest { // 发布指定地址合约 deploy(ledgerRepo, ledgerManager, opReg, ledgerHash, contractKey); - // 创建新区块的交易处理器; LedgerBlock preBlock = ledgerRepo.getLatestBlock(); LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(preBlock); // 加载合约 LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); - TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, - opReg, ledgerManager); + LedgerSecurityManager securityManager = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, + previousBlockDataset, opReg, ledgerManager); // 构建基于接口调用合约的交易请求,用于测试合约调用; TxBuilder txBuilder = new TxBuilder(ledgerHash); @@ -119,16 +120,16 @@ public class ContractInvokingTest { } private void deploy(LedgerRepository ledgerRepo, LedgerManager ledgerManager, - DefaultOperationHandleRegisteration opReg, HashDigest ledgerHash, - BlockchainKeypair contractKey) { + DefaultOperationHandleRegisteration opReg, HashDigest ledgerHash, BlockchainKeypair contractKey) { // 创建新区块的交易处理器; LedgerBlock preBlock = ledgerRepo.getLatestBlock(); LedgerDataset previousBlockDataset = ledgerRepo.getDataSet(preBlock); // 加载合约 LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); - TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, - opReg, ledgerManager); + LedgerSecurityManager securityManager = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, + previousBlockDataset, opReg, ledgerManager); // 构建基于接口调用合约的交易请求,用于测试合约调用; TxBuilder txBuilder = new TxBuilder(ledgerHash); @@ -189,4 +190,18 @@ public class ContractInvokingTest { new Random().nextBytes(chainCode); return chainCode; } + + private static LedgerSecurityManager getSecurityManager() { + LedgerSecurityManager securityManager = Mockito.mock(LedgerSecurityManager.class); + + SecurityPolicy securityPolicy = Mockito.mock(SecurityPolicy.class); + when(securityPolicy.isEnableToEndpoints(any(LedgerPermission.class), any())).thenReturn(true); + when(securityPolicy.isEnableToEndpoints(any(TransactionPermission.class), any())).thenReturn(true); + when(securityPolicy.isEnableToNodes(any(LedgerPermission.class), any())).thenReturn(true); + when(securityPolicy.isEnableToNodes(any(TransactionPermission.class), any())).thenReturn(true); + + when(securityManager.getSecurityPolicy(any(), any())).thenReturn(securityPolicy); + + return securityManager; + } } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerSecurityManagerTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerSecurityManagerTest.java new file mode 100644 index 00000000..1ea099c0 --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerSecurityManagerTest.java @@ -0,0 +1,141 @@ +package test.com.jd.blockchain.ledger.core; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +import com.jd.blockchain.crypto.Crypto; +import com.jd.blockchain.crypto.CryptoAlgorithm; +import com.jd.blockchain.crypto.CryptoProvider; +import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; +import com.jd.blockchain.crypto.service.sm.SMCryptoService; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; +import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.CryptoSetting; +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.Privileges; +import com.jd.blockchain.ledger.RolePrivilegeSettings; +import com.jd.blockchain.ledger.RolesPolicy; +import com.jd.blockchain.ledger.TransactionPermission; +import com.jd.blockchain.ledger.UserRoleSettings; +import com.jd.blockchain.ledger.core.CryptoConfig; +import com.jd.blockchain.ledger.core.LedgerSecurityManager; +import com.jd.blockchain.ledger.core.LedgerSecurityManagerImpl; +import com.jd.blockchain.ledger.core.MultiIdsPolicy; +import com.jd.blockchain.ledger.core.RolePrivilegeDataset; +import com.jd.blockchain.ledger.core.SecurityPolicy; +import com.jd.blockchain.ledger.core.UserRoleDataset; +import com.jd.blockchain.storage.service.utils.MemoryKVStorage; +import com.jd.blockchain.utils.Bytes; + +public class LedgerSecurityManagerTest { + + private static final String[] SUPPORTED_PROVIDER_NAMES = { ClassicCryptoService.class.getName(), + SMCryptoService.class.getName() }; + + private static final CryptoAlgorithm HASH_ALGORITHM = Crypto.getAlgorithm("SHA256"); + + private static final CryptoProvider[] SUPPORTED_PROVIDERS = new CryptoProvider[SUPPORTED_PROVIDER_NAMES.length]; + + private static final CryptoSetting CRYPTO_SETTINGS; + + static { + for (int i = 0; i < SUPPORTED_PROVIDER_NAMES.length; i++) { + SUPPORTED_PROVIDERS[i] = Crypto.getProvider(SUPPORTED_PROVIDER_NAMES[i]); + } + + CryptoConfig cryptoConfig = new CryptoConfig(); + cryptoConfig.setAutoVerifyHash(true); + cryptoConfig.setSupportedProviders(SUPPORTED_PROVIDERS); + cryptoConfig.setHashAlgorithm(HASH_ALGORITHM); + + CRYPTO_SETTINGS = cryptoConfig; + } + + private RolePrivilegeSettings initRoles(MemoryKVStorage testStorage, String[] roles, Privileges[] privilege) { + String prefix = "role-privilege/"; + RolePrivilegeDataset rolePrivilegeDataset = new RolePrivilegeDataset(CRYPTO_SETTINGS, prefix, testStorage, + testStorage); + for (int i = 0; i < roles.length; i++) { + rolePrivilegeDataset.addRolePrivilege(roles[i], privilege[i]); + } + + rolePrivilegeDataset.commit(); + + return rolePrivilegeDataset; + } + + private UserRoleSettings initUserRoless(MemoryKVStorage testStorage, Bytes[] userAddresses, RolesPolicy[] policies, + String[][] roles) { + String prefix = "user-roles/"; + UserRoleDataset userRolesDataset = new UserRoleDataset(CRYPTO_SETTINGS, prefix, testStorage, testStorage); + + for (int i = 0; i < userAddresses.length; i++) { + userRolesDataset.addUserRoles(userAddresses[i], policies[i], roles[i]); + } + + userRolesDataset.commit(); + + return userRolesDataset; + } + + @Test + public void testGetSecurityPolicy() { + MemoryKVStorage testStorage = new MemoryKVStorage(); + + final BlockchainKeypair kpManager = BlockchainKeyGenerator.getInstance().generate(); + final BlockchainKeypair kpEmployee = BlockchainKeyGenerator.getInstance().generate(); + final BlockchainKeypair kpDevoice = BlockchainKeyGenerator.getInstance().generate(); + + final Map endpoints = new HashMap<>(); + endpoints.put(kpManager.getAddress(), kpManager); + endpoints.put(kpEmployee.getAddress(), kpEmployee); + + final Map nodes = new HashMap<>(); + nodes.put(kpDevoice.getAddress(), kpDevoice); + + + final String ROLE_ADMIN = "ID_ADMIN"; + final String ROLE_OPERATOR = "OPERATOR"; + final String ROLE_DATA_COLLECTOR = "DATA_COLLECTOR"; + + final Privileges PRIVILEGES_ADMIN = Privileges.configure() + .enable(LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT) + .enable(TransactionPermission.DIRECT_OPERATION, TransactionPermission.CONTRACT_OPERATION); + + final Privileges PRIVILEGES_OPERATOR = Privileges.configure() + .enable(LedgerPermission.WRITE_DATA_ACCOUNT, LedgerPermission.APPROVE_TX) + .enable(TransactionPermission.CONTRACT_OPERATION); + + final Privileges PRIVILEGES_DATA_COLLECTOR = Privileges.configure().enable(LedgerPermission.WRITE_DATA_ACCOUNT) + .enable(TransactionPermission.CONTRACT_OPERATION); + + RolePrivilegeSettings rolePrivilegeSettings = initRoles(testStorage, + new String[] { ROLE_ADMIN, ROLE_OPERATOR, ROLE_DATA_COLLECTOR }, + new Privileges[] { PRIVILEGES_ADMIN, PRIVILEGES_OPERATOR, PRIVILEGES_DATA_COLLECTOR }); + + String[] managerRoles = new String[] { ROLE_ADMIN, ROLE_OPERATOR }; + String[] employeeRoles = new String[] { ROLE_OPERATOR }; + String[] devoiceRoles = new String[] { ROLE_DATA_COLLECTOR }; + UserRoleSettings userRolesSettings = initUserRoless(testStorage, + new Bytes[] { kpManager.getAddress(), kpEmployee.getAddress(), kpDevoice.getAddress() }, + new RolesPolicy[] { RolesPolicy.UNION, RolesPolicy.UNION, RolesPolicy.UNION }, + new String[][] { managerRoles, employeeRoles, devoiceRoles }); + + LedgerSecurityManager securityManager = new LedgerSecurityManagerImpl(rolePrivilegeSettings, userRolesSettings); + + SecurityPolicy policy = securityManager.getSecurityPolicy(endpoints.keySet(), nodes.keySet()); + + assertTrue(policy.isEnableToEndpoints(LedgerPermission.REGISTER_USER, MultiIdsPolicy.AT_LEAST_ONE)); + assertTrue(policy.isEnableToEndpoints(LedgerPermission.REGISTER_DATA_ACCOUNT, MultiIdsPolicy.AT_LEAST_ONE)); + assertTrue(policy.isEnableToEndpoints(LedgerPermission.WRITE_DATA_ACCOUNT, MultiIdsPolicy.AT_LEAST_ONE)); + assertTrue(policy.isEnableToEndpoints(LedgerPermission.APPROVE_TX, MultiIdsPolicy.AT_LEAST_ONE)); + assertFalse(policy.isEnableToEndpoints(LedgerPermission.REGISTER_USER, MultiIdsPolicy.ALL)); + assertFalse(policy.isEnableToEndpoints(LedgerPermission.AUTHORIZE_ROLES, MultiIdsPolicy.AT_LEAST_ONE)); + } + +} diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java index 9f5ffb3b..20cc013c 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java @@ -5,8 +5,11 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; import org.junit.Test; +import org.mockito.Mockito; import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.crypto.HashDigest; @@ -17,10 +20,12 @@ import com.jd.blockchain.ledger.DataAccountRegisterOperation; import com.jd.blockchain.ledger.EndpointRequest; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInitSetting; +import com.jd.blockchain.ledger.LedgerPermission; import com.jd.blockchain.ledger.LedgerTransaction; import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.TransactionContentBody; +import com.jd.blockchain.ledger.TransactionPermission; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; @@ -31,9 +36,11 @@ import com.jd.blockchain.ledger.core.LedgerDataset; import com.jd.blockchain.ledger.core.LedgerEditor; import com.jd.blockchain.ledger.core.LedgerManager; import com.jd.blockchain.ledger.core.LedgerRepository; +import com.jd.blockchain.ledger.core.LedgerSecurityManager; import com.jd.blockchain.ledger.core.LedgerTransactionContext; import com.jd.blockchain.ledger.core.LedgerTransactionalEditor; import com.jd.blockchain.ledger.core.OperationHandleRegisteration; +import com.jd.blockchain.ledger.core.SecurityPolicy; import com.jd.blockchain.ledger.core.TransactionBatchProcessor; import com.jd.blockchain.ledger.core.UserAccount; import com.jd.blockchain.storage.service.utils.MemoryKVStorage; @@ -85,8 +92,9 @@ public class TransactionBatchProcessorTest { LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); - TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, - opReg, ledgerManager); + LedgerSecurityManager securityManager = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, + previousBlockDataset, opReg, ledgerManager); // 注册新用户; BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate(); @@ -108,6 +116,20 @@ public class TransactionBatchProcessorTest { assertEquals(TransactionState.SUCCESS, txResp.getExecutionState()); } + private static LedgerSecurityManager getSecurityManager() { + LedgerSecurityManager securityManager = Mockito.mock(LedgerSecurityManager.class); + + SecurityPolicy securityPolicy = Mockito.mock(SecurityPolicy.class); + when(securityPolicy.isEnableToEndpoints(any(LedgerPermission.class), any())).thenReturn(true); + when(securityPolicy.isEnableToEndpoints(any(TransactionPermission.class), any())).thenReturn(true); + when(securityPolicy.isEnableToNodes(any(LedgerPermission.class), any())).thenReturn(true); + when(securityPolicy.isEnableToNodes(any(TransactionPermission.class), any())).thenReturn(true); + + when(securityManager.getSecurityPolicy(any(), any())).thenReturn(securityPolicy); + + return securityManager; + } + @Test public void testMultiTxsProcess() { final MemoryKVStorage STORAGE = new MemoryKVStorage(); @@ -130,8 +152,9 @@ public class TransactionBatchProcessorTest { LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); - TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, - opReg, ledgerManager); + LedgerSecurityManager securityManager = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, + previousBlockDataset, opReg, ledgerManager); // 注册新用户; BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); @@ -187,8 +210,9 @@ public class TransactionBatchProcessorTest { LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); - TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, - opReg, ledgerManager); + LedgerSecurityManager securityManager = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, + previousBlockDataset, opReg, ledgerManager); // 注册新用户; BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); @@ -267,8 +291,9 @@ public class TransactionBatchProcessorTest { LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); - TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, - opReg, ledgerManager); + LedgerSecurityManager securityManager = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, + previousBlockDataset, opReg, ledgerManager); BlockchainKeypair dataAccountKeypair = BlockchainKeyGenerator.getInstance().generate(); TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_DataAccountReg(dataAccountKeypair, @@ -293,7 +318,8 @@ public class TransactionBatchProcessorTest { newBlockEditor = ledgerRepo.createNextBlock(); previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); - txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, opReg, ledgerManager); + txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, previousBlockDataset, opReg, + ledgerManager); txbatchProcessor.schedule(txreq1); txbatchProcessor.schedule(txreq2); @@ -316,7 +342,7 @@ public class TransactionBatchProcessorTest { assertNotNull(v1_1); assertNotNull(v2); assertNotNull(v3); - + assertEquals("V-1-1", v1_0.getValue().toUTF8String()); assertEquals("V-1-2", v1_1.getValue().toUTF8String()); assertEquals("V-2-1", v2.getValue().toUTF8String()); @@ -332,7 +358,8 @@ public class TransactionBatchProcessorTest { newBlockEditor = ledgerRepo.createNextBlock(); previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); - txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, opReg, ledgerManager); + txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, previousBlockDataset, opReg, + ledgerManager); txbatchProcessor.schedule(txreq5); txbatchProcessor.schedule(txreq6); @@ -343,11 +370,13 @@ public class TransactionBatchProcessorTest { BytesValue v1 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K1"); v3 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K3"); - long k1_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getDataVersion("K1"); + long k1_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()) + .getDataVersion("K1"); assertEquals(1, k1_version); - long k3_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getDataVersion("K3"); + long k3_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()) + .getDataVersion("K3"); assertEquals(1, k3_version); - + assertNotNull(v1); assertNotNull(v3); assertEquals("V-1-2", v1.getValue().toUTF8String()); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/AbstractPrivilege.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/AbstractPrivilege.java deleted file mode 100644 index df65c93c..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/AbstractPrivilege.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.jd.blockchain.ledger; - -import java.util.BitSet; - -import com.jd.blockchain.utils.io.BytesSerializable; - -/** - * LedgerPrivilege 账本特权是授权给特定角色的权限代码序列; - * - * @author huanghaiquan - * - */ -public abstract class AbstractPrivilege> implements Privilege, BytesSerializable { - - private BitSet permissionBits; - - public AbstractPrivilege() { - permissionBits = new BitSet(); - } - - public AbstractPrivilege(byte[] codeBytes) { - permissionBits = BitSet.valueOf(codeBytes); - } - - public boolean isEnable(E permission) { - return permissionBits.get(getCodeIndex(permission)); - } - - public void enable(E permission) { - permissionBits.set(getCodeIndex(permission)); - } - - public void disable(E permission) { - permissionBits.clear(getCodeIndex(permission)); - } - - @SuppressWarnings("unchecked") - public void enable(E... permissions) { - for (E p : permissions) { - permissionBits.set(getCodeIndex(p)); - } - } - - @SuppressWarnings("unchecked") - public void disable(E... permissions) { - for (E p : permissions) { - permissionBits.clear(getCodeIndex(p)); - } - } - - protected abstract int getCodeIndex(E permission); - - @Override - public byte[] toBytes() { - return permissionBits.toByteArray(); - } - -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPrivilege.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPrivilege.java index 5b5ebf20..dad59a41 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPrivilege.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPrivilege.java @@ -6,18 +6,24 @@ package com.jd.blockchain.ledger; * @author huanghaiquan * */ -public class LedgerPrivilege extends AbstractPrivilege { +public class LedgerPrivilege extends PrivilegeBitset { + + private static final CodeIndexer CODE_INDEXER = new LedgerPermissionCodeIndexer(); public LedgerPrivilege() { + super(CODE_INDEXER); } - + public LedgerPrivilege(byte[] codeBytes) { - super(codeBytes); + super(codeBytes, CODE_INDEXER); } - @Override - protected int getCodeIndex(LedgerPermission permission) { - return permission.CODE & 0xFF; - } + private static class LedgerPermissionCodeIndexer implements CodeIndexer { + @Override + public int getCodeIndex(LedgerPermission permission) { + return permission.CODE & 0xFF; + } + + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerSecurityException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerSecurityException.java new file mode 100644 index 00000000..0b3e98a8 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerSecurityException.java @@ -0,0 +1,17 @@ +package com.jd.blockchain.ledger; + +public class LedgerSecurityException extends RuntimeException { + + private static final long serialVersionUID = -4090881296855827888L; + + + + public LedgerSecurityException(String message) { + super(message); + } + + public LedgerSecurityException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ParticipantDoesNotExistException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ParticipantDoesNotExistException.java new file mode 100644 index 00000000..54994dc7 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ParticipantDoesNotExistException.java @@ -0,0 +1,15 @@ +package com.jd.blockchain.ledger; + +public class ParticipantDoesNotExistException extends LedgerException { + + private static final long serialVersionUID = 397450363050148898L; + + public ParticipantDoesNotExistException(String message) { + super(message); + } + + public ParticipantDoesNotExistException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PrivilegeBitset.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PrivilegeBitset.java new file mode 100644 index 00000000..71b092ce --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PrivilegeBitset.java @@ -0,0 +1,121 @@ +package com.jd.blockchain.ledger; + +import java.util.BitSet; + +import com.jd.blockchain.utils.io.BytesSerializable; + +/** + * PrivilegeBitset 定义了用位表示的权限码; + * + * @author huanghaiquan + * + */ +public class PrivilegeBitset> implements Privilege, BytesSerializable { + + private BitSet permissionBits; + + private CodeIndexer codeIndexer; + + public PrivilegeBitset(CodeIndexer codeIndexer) { + this(new BitSet(), codeIndexer); + } + + public PrivilegeBitset(byte[] codeBytes, CodeIndexer codeIndexer) { + this(BitSet.valueOf(codeBytes), codeIndexer); + } + + private PrivilegeBitset(BitSet bits, CodeIndexer codeIndexer) { + this.permissionBits = bits; + this.codeIndexer = codeIndexer; + } + + public boolean isEnable(E permission) { + return permissionBits.get(codeIndexer.getCodeIndex(permission)); + } + + public void enable(E permission) { + permissionBits.set(codeIndexer.getCodeIndex(permission)); + } + + public void disable(E permission) { + permissionBits.clear(codeIndexer.getCodeIndex(permission)); + } + + @SuppressWarnings("unchecked") + public void enable(E... permissions) { + for (E p : permissions) { + permissionBits.set(codeIndexer.getCodeIndex(p)); + } + } + + @SuppressWarnings("unchecked") + public void disable(E... permissions) { + for (E p : permissions) { + permissionBits.clear(codeIndexer.getCodeIndex(p)); + } + } + + @Override + public byte[] toBytes() { + return permissionBits.toByteArray(); + } + + /** + * 把指定的权限合并到当前的权限中;
+ * + * @param privileges + * @return + */ + public Privilege union(PrivilegeBitset... privileges) { + return union(privileges, 0, privileges.length); + } + + /** + * 把指定的权限合并到当前的权限中;
+ * @param privileges + * @param offset + * @param count + * @return + */ + public Privilege union(PrivilegeBitset[] privileges, int offset, int count) { + BitSet bits = this.permissionBits; + for (int i = 0; i < count; i++) { + bits.or(privileges[i + offset].permissionBits); + } + return this; + } + + /** + * 保留当前的权限与指定权限的共同生效的部分,同时清除其它的权限位;
+ * + * @param privileges + * @return + */ + public Privilege intersect(PrivilegeBitset... privileges) { + return intersect(privileges, 0, privileges.length); + } + + /** + * 保留当前的权限与指定权限的共同生效的部分,同时清除其它的权限位;
+ * + * @param privileges + * @param offset + * @param count + * @return + */ + public Privilege intersect(PrivilegeBitset[] privileges, int offset, int count) { + BitSet bits = this.permissionBits; + for (int i = 0; i < count; i++) { + bits.and(privileges[i + offset].permissionBits); + } + return this; + } + + public PrivilegeBitset clone() { + return new PrivilegeBitset((BitSet) permissionBits.clone(), codeIndexer); + } + + static interface CodeIndexer> { + int getCodeIndex(E permission); + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Privileges.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Privileges.java new file mode 100644 index 00000000..420cbf45 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/Privileges.java @@ -0,0 +1,65 @@ +package com.jd.blockchain.ledger; + +public class Privileges implements PrivilegeSet { + + private LedgerPrivilege ledgerPrivilege; + + private TransactionPrivilege txPrivilege; + + protected Privileges() { + this.ledgerPrivilege = new LedgerPrivilege(); + this.txPrivilege = new TransactionPrivilege(); + } + + protected Privileges(PrivilegeSet privilege) { + this.ledgerPrivilege = privilege.getLedgerPrivilege(); + this.txPrivilege = privilege.getTransactionPrivilege(); + } + + protected Privileges(LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { + this.ledgerPrivilege = ledgerPrivilege; + this.txPrivilege = txPrivilege; + } + + @Override + public LedgerPrivilege getLedgerPrivilege() { + return ledgerPrivilege; + } + + public void setLedgerPrivilege(LedgerPrivilege ledgerPrivilege) { + this.ledgerPrivilege = ledgerPrivilege; + } + + @Override + public TransactionPrivilege getTransactionPrivilege() { + return txPrivilege; + } + + public void setTransactionPrivilege(TransactionPrivilege txPrivilege) { + this.txPrivilege = txPrivilege; + } + + public static Privileges configure() { + return new Privileges(); + } + + public Privileges enable(LedgerPermission...ledgerPermissions) { + this.ledgerPrivilege.enable(ledgerPermissions); + return this; + } + + public Privileges disable(LedgerPermission...ledgerPermissions) { + this.ledgerPrivilege.disable(ledgerPermissions); + return this; + } + + public Privileges enable(TransactionPermission...transactionPermissions) { + this.txPrivilege.enable(transactionPermissions); + return this; + } + + public Privileges disable(TransactionPermission...transactionPermissions) { + this.txPrivilege.disable(transactionPermissions); + return this; + } +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/RolePrivilegeSettings.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/RolePrivilegeSettings.java index 159b6a48..21e394e2 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/RolePrivilegeSettings.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/RolePrivilegeSettings.java @@ -8,6 +8,17 @@ public interface RolePrivilegeSettings { public static final int MAX_ROLE_NAME_LENGTH = 20; long getRoleCount(); + + /** + * 加入新的角色授权;
+ * + * 如果指定的角色已经存在,则引发 {@link LedgerException} 异常; + * + * @param roleName 角色名称;不能超过 {@link #MAX_ROLE_NAME_LENGTH} 个 Unicode 字符; + * @param ledgerPrivilege + * @param txPrivilege + */ + long addRolePrivilege(String roleName, Privileges privileges); /** * 加入新的角色授权;
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/RolePrivileges.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/RolePrivileges.java index 76db4d01..1b0b32ba 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/RolePrivileges.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/RolePrivileges.java @@ -6,35 +6,28 @@ package com.jd.blockchain.ledger; * @author huanghaiquan * */ -public class RolePrivileges implements PrivilegeSet { +public class RolePrivileges extends Privileges { private String roleName; private long version; - private LedgerPrivilege ledgerPrivilege; - - private TransactionPrivilege txPrivilege; - public RolePrivileges(String roleName, long version) { this.roleName = roleName; this.version = version; - this.ledgerPrivilege = new LedgerPrivilege(); - this.txPrivilege = new TransactionPrivilege(); } public RolePrivileges(String roleName, long version, PrivilegeSet privilege) { + super(privilege); this.roleName = roleName; this.version = version; - this.ledgerPrivilege = privilege.getLedgerPrivilege(); - this.txPrivilege = privilege.getTransactionPrivilege(); } - public RolePrivileges(String roleName, long version, LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { + public RolePrivileges(String roleName, long version, LedgerPrivilege ledgerPrivilege, + TransactionPrivilege txPrivilege) { + super(ledgerPrivilege, txPrivilege); this.roleName = roleName; this.version = version; - this.ledgerPrivilege = ledgerPrivilege; - this.txPrivilege = txPrivilege; } public String getRoleName() { @@ -45,22 +38,4 @@ public class RolePrivileges implements PrivilegeSet { return version; } - @Override - public LedgerPrivilege getLedgerPrivilege() { - return ledgerPrivilege; - } - - public void setLedgerPrivilege(LedgerPrivilege ledgerPrivilege) { - this.ledgerPrivilege = ledgerPrivilege; - } - - @Override - public TransactionPrivilege getTransactionPrivilege() { - return txPrivilege; - } - - public void setTransactionPrivilege(TransactionPrivilege txPrivilege) { - this.txPrivilege = txPrivilege; - } - } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionPrivilege.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionPrivilege.java index 08408326..755a75a7 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionPrivilege.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionPrivilege.java @@ -1,17 +1,23 @@ package com.jd.blockchain.ledger; -public class TransactionPrivilege extends AbstractPrivilege { +public class TransactionPrivilege extends PrivilegeBitset { + + private static final CodeIndexer CODE_INDEXER = new TransactionPermissionCodeIndexer(); public TransactionPrivilege() { + super(CODE_INDEXER); } public TransactionPrivilege(byte[] codeBytes) { - super(codeBytes); + super(codeBytes, CODE_INDEXER); } - @Override - protected int getCodeIndex(TransactionPermission permission) { - return permission.CODE & 0xFF; - } + private static class TransactionPermissionCodeIndexer implements CodeIndexer { + @Override + public int getCodeIndex(TransactionPermission permission) { + return permission.CODE & 0xFF; + } + + } } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java index 6955eb94..a93f719e 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java @@ -39,6 +39,16 @@ public enum TransactionState { */ CONTRACT_DOES_NOT_EXIST((byte) 0x04), + /** + * 参与方不存在; + */ + PARTICIPANT_DOES_NOT_EXIST((byte) 0x05), + + /** + * 被安全策略拒绝; + */ + REJECTED_BY_SECURITY_POLICY((byte) 0x10), + /** * 由于在错误的账本上执行交易而被丢弃; */ diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java index 79223ddd..f48e59c0 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java @@ -37,6 +37,7 @@ import com.jd.blockchain.ledger.LedgerAdminInfo; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInfo; import com.jd.blockchain.ledger.LedgerMetadata; +import com.jd.blockchain.ledger.LedgerPermission; import com.jd.blockchain.ledger.LedgerTransaction; import com.jd.blockchain.ledger.NodeRequest; import com.jd.blockchain.ledger.Operation; @@ -44,6 +45,7 @@ import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.ParticipantNode; import com.jd.blockchain.ledger.TransactionContent; import com.jd.blockchain.ledger.TransactionContentBody; +import com.jd.blockchain.ledger.TransactionPermission; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionRequestBuilder; import com.jd.blockchain.ledger.TransactionResponse; @@ -56,6 +58,8 @@ import com.jd.blockchain.ledger.core.LedgerEditor; import com.jd.blockchain.ledger.core.LedgerManager; import com.jd.blockchain.ledger.core.LedgerQueryService; import com.jd.blockchain.ledger.core.LedgerRepository; +import com.jd.blockchain.ledger.core.LedgerSecurityManager; +import com.jd.blockchain.ledger.core.SecurityPolicy; import com.jd.blockchain.ledger.core.TransactionBatchProcessor; import com.jd.blockchain.mocker.config.MockerConstant; import com.jd.blockchain.mocker.config.PresetAnswerPrompter; @@ -121,7 +125,7 @@ public class MockerNodeContext implements BlockchainQueryService { DataContractRegistry.register(ActionResponse.class); DataContractRegistry.register(ClientIdentifications.class); DataContractRegistry.register(ClientIdentification.class); - + // DataContractRegistry.register(LedgerAdminInfo.class); ByteArrayObjectUtil.init(); @@ -273,7 +277,7 @@ public class MockerNodeContext implements BlockchainQueryService { public LedgerInfo getLedger(HashDigest ledgerHash) { return queryService.getLedger(ledgerHash); } - + @Override public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { return queryService.getLedgerAdminInfo(ledgerHash); @@ -410,7 +414,7 @@ public class MockerNodeContext implements BlockchainQueryService { } @Override - public ContractInfo getContract(HashDigest ledgerHash, String address) { + public ContractInfo getContract(HashDigest ledgerHash, String address) { return queryService.getContract(ledgerHash, address); } @@ -443,8 +447,8 @@ public class MockerNodeContext implements BlockchainQueryService { LedgerEditor newEditor = ledgerRepository.createNextBlock(); LedgerBlock latestBlock = ledgerRepository.getLatestBlock(); LedgerDataset previousDataSet = ledgerRepository.getDataSet(latestBlock); - TransactionBatchProcessor txProc = new TransactionBatchProcessor(newEditor, previousDataSet, opHandler, - ledgerManager); + TransactionBatchProcessor txProc = new TransactionBatchProcessor(newEditor, + previousDataSet, opHandler, ledgerManager); TransactionResponse txResp = txProc.schedule(txRequest); TransactionBatchResultHandle handle = txProc.prepare(); handle.commit(); diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java index a57a181a..e4db1c39 100644 --- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java +++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/handler/MockerContractExeHandle.java @@ -16,7 +16,7 @@ import com.jd.blockchain.ledger.core.LedgerQueryService; import com.jd.blockchain.ledger.core.LedgerService; import com.jd.blockchain.ledger.core.OperationHandle; import com.jd.blockchain.ledger.core.OperationHandleContext; -import com.jd.blockchain.ledger.core.TransactionRequestContext; +import com.jd.blockchain.ledger.core.TransactionRequestExtension; import com.jd.blockchain.ledger.core.handles.ContractLedgerContext; import com.jd.blockchain.mocker.proxy.ExecutorProxy; @@ -29,7 +29,7 @@ public class MockerContractExeHandle implements OperationHandle { private HashDigest ledgerHash; @Override - public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestContext requestContext, + public BytesValue process(Operation op, LedgerDataset dataset, TransactionRequestExtension requestContext, LedgerDataset previousBlockDataset, OperationHandleContext opHandleContext, LedgerService ledgerService) { ContractEventSendOperation contractOP = (ContractEventSendOperation) op;