diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPermission.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPermission.java index 18d0fdfd..82793392 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPermission.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPermission.java @@ -36,34 +36,26 @@ public enum LedgerPermission { REGISTER_PARTICIPANT((byte) 0x04), /** - * 设置参与方的权限;
+ * 注册用户;
* - * 如果不具备此项权限,则无法设置参与方的“提交交易”、“参与共识”的权限; + * 如果不具备此项权限,则无法注册用户; */ - SET_PARTICIPANT_PERMISSION((byte) 0x05), + REGISTER_USER((byte) 0x05), /** - * 参与方核准交易;
- * - * 如果不具备此项权限,则无法作为节点签署由终端提交的交易; - *

- * 只对交易请求的节点签名列表{@link TransactionRequest#getNodeSignatures()}的用户产生影响; + * 注册数据账户;
*/ - APPROVE_TX((byte) 0x06), + REGISTER_DATA_ACCOUNT((byte) 0x06), /** - * 参与方共识交易;
- * - * 如果不具备此项权限,则无法作为共识节点接入并对交易进行共识; + * 注册合约;
*/ - CONSENSUS_TX((byte) 0x07), + REGISTER_CONTRACT((byte) 0x07), /** - * 注册用户;
- * - * 如果不具备此项权限,则无法注册用户; + * 升级合约 */ - REGISTER_USER((byte) 0x08), + UPGRADE_CONTRACT((byte) 0x08), /** * 设置用户属性;
@@ -71,24 +63,27 @@ public enum LedgerPermission { SET_USER_ATTRIBUTES((byte) 0x09), /** - * 注册数据账户;
- */ - REGISTER_DATA_ACCOUNT((byte) 0x0A), - - /** * 写入数据账户;
*/ - WRITE_DATA_ACCOUNT((byte) 0x0B), + WRITE_DATA_ACCOUNT((byte) 0x0A), /** - * 注册合约;
+ * 参与方核准交易;
+ * + * 如果不具备此项权限,则无法作为节点签署由终端提交的交易; + *

+ * 只对交易请求的节点签名列表{@link TransactionRequest#getNodeSignatures()}的用户产生影响; */ - REGISTER_CONTRACT((byte) 0x0C), + APPROVE_TX((byte) 0x0B), /** - * 升级合约 + * 参与方共识交易;
+ * + * 如果不具备此项权限,则无法作为共识节点接入并对交易进行共识; */ - UPGRADE_CONTRACT((byte) 0x0D); + CONSENSUS_TX((byte) 0x0C); + + @EnumField(type = PrimitiveType.INT8) public final byte CODE; diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/SecurityInitData.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/SecurityInitData.java index 9e4a5d55..9ba2e250 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/SecurityInitData.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/SecurityInitData.java @@ -5,7 +5,7 @@ import java.util.List; public class SecurityInitData implements SecurityInitSettings { - private List roles = new ArrayList(); + private List roles = new ArrayList(); @Override public RoleInitData[] getRoles() { @@ -13,8 +13,8 @@ public class SecurityInitData implements SecurityInitSettings { } public void setRoles(RoleInitData[] roles) { - List list = new ArrayList(); - for (RoleInitSettings r : roles) { + List list = new ArrayList(); + for (RoleInitData r : roles) { list.add(r); } this.roles = list; diff --git a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/SecurityInitDataTest.java b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/SecurityInitDataTest.java index fab4c57a..6bf9d1f5 100644 --- a/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/SecurityInitDataTest.java +++ b/source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/SecurityInitDataTest.java @@ -29,6 +29,18 @@ public class SecurityInitDataTest { assertEquals(LedgerPermission.REGISTER_USER, permissions2[0]); assertEquals(LedgerPermission.REGISTER_DATA_ACCOUNT, permissions2[1]); + LedgerPermission[] allLedgerPermissions = LedgerPermission.values(); + String jsonLedgerPersioms = JSONSerializeUtils.serializeToJSON(allLedgerPermissions); + + TransactionPermission[] allTransactionPermissions = TransactionPermission.values(); + String jsonTransactionPersioms = JSONSerializeUtils.serializeToJSON(allTransactionPermissions); + + System.out.println("----------- Ledger Permissions JSON ------------"); + System.out.println(jsonLedgerPersioms); + System.out.println("-----------------------"); + System.out.println("----------- Transaction Permissions JSON ------------"); + System.out.println(jsonTransactionPersioms); + System.out.println("-----------------------"); } @Test diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/initializer/LedgerInitializeTest.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/initializer/LedgerInitializeTest.java index d01de50f..101c874b 100644 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/initializer/LedgerInitializeTest.java +++ b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/initializer/LedgerInitializeTest.java @@ -13,8 +13,6 @@ import org.junit.Test; import org.springframework.core.io.ClassPathResource; import com.jd.blockchain.binaryproto.DataContractRegistry; -import com.jd.blockchain.consensus.ConsensusProvider; -import com.jd.blockchain.consensus.ConsensusSettings; import com.jd.blockchain.crypto.AddressEncoding; import com.jd.blockchain.crypto.AsymmetricKeypair; import com.jd.blockchain.crypto.Crypto; diff --git a/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java b/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java index 407501e9..ccc97362 100644 --- a/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java +++ b/source/tools/tools-initializer/src/main/java/com/jd/blockchain/tools/initializer/LedgerInitProperties.java @@ -7,15 +7,23 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Properties; +import java.util.TreeMap; import com.jd.blockchain.consts.Global; import com.jd.blockchain.crypto.AddressEncoding; import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.LedgerPermission; import com.jd.blockchain.ledger.ParticipantNode; +import com.jd.blockchain.ledger.RoleInitData; +import com.jd.blockchain.ledger.RoleInitSettings; +import com.jd.blockchain.ledger.RolesPolicy; +import com.jd.blockchain.ledger.TransactionPermission; import com.jd.blockchain.tools.keygen.KeyGenCommand; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.PropertiesUtils; +import com.jd.blockchain.utils.StringUtils; import com.jd.blockchain.utils.codec.HexUtils; import com.jd.blockchain.utils.io.FileUtils; import com.jd.blockchain.utils.net.NetworkAddress; @@ -33,6 +41,13 @@ public class LedgerInitProperties { // 创建时间的格式; public static final String CREATED_TIME_FORMAT = Global.DEFAULT_TIME_FORMAT; + // 角色清单; + public static final String ROLES = "security.roles"; + // 角色的账本权限;用角色名称替代占位符; + public static final String ROLE_LEDGER_PRIVILEGES_PATTERN = "security.role.%s.ledger-privileges"; + // 角色的交易权限;用角色名称替代占位符; + public static final String ROLE_TX_PRIVILEGES_PATTERN = "security.role.%s.tx-privileges"; + // 共识参与方的个数,后续以 part.id 分别标识每一个参与方的配置; public static final String PART_COUNT = "cons_parti.count"; // 共识参与方的名称的模式; @@ -43,6 +58,10 @@ public class LedgerInitProperties { public static final String PART_PUBKEY_PATH = "pubkey-path"; // 参与方的公钥文件路径; public static final String PART_PUBKEY = "pubkey"; + // 参与方的角色清单; + public static final String PART_ROLES = "roles"; + // 参与方的角色权限策略; + public static final String PART_ROLES_POLICY = "roles-policy"; // 共识参与方的账本初始服务的主机; public static final String PART_INITIALIZER_HOST = "initializer.host"; @@ -66,6 +85,8 @@ public class LedgerInitProperties { private String ledgerName; + private RoleInitData[] roles; + private List consensusParticipants = new ArrayList<>(); private String consensusProvider; @@ -143,7 +164,7 @@ public class LedgerInitProperties { consensusParticipants.add(participant); } - private static String getKeyOfCsParti(int partId, String partPropKey) { + private static String getKeyOfParticipant(int partId, String partPropKey) { String partAddrStr = String.format(PART_ID_PATTERN, partId); return String.format("%s.%s", partAddrStr, partPropKey); } @@ -162,12 +183,20 @@ public class LedgerInitProperties { public static LedgerInitProperties resolve(Properties props) { return resolve(null, props); } - - public static LedgerInitProperties resolve(String dir, Properties props) { + + /** + * 从属性表解析账本初始化参数; + * + * @param baseDirectory 基础路径;属性中涉及文件位置的相对路径以此参数指定的目录为父目录; + * @param props 要解析的属性表; + * @return + */ + public static LedgerInitProperties resolve(String baseDirectory, Properties props) { String hexLedgerSeed = PropertiesUtils.getRequiredProperty(props, LEDGER_SEED).replace("-", ""); byte[] ledgerSeed = HexUtils.decode(hexLedgerSeed); LedgerInitProperties initProps = new LedgerInitProperties(ledgerSeed); + // 解析账本信息; // 账本名称 String ledgerName = PropertiesUtils.getRequiredProperty(props, LEDGER_NAME); initProps.ledgerName = ledgerName; @@ -180,11 +209,35 @@ public class LedgerInitProperties { throw new IllegalArgumentException(ex.getMessage(), ex); } + // 解析角色清单; + String strRoleNames = PropertiesUtils.getOptionalProperty(props, ROLES); + String[] roles = StringUtils.splitToArray(strRoleNames, ","); + + Map rolesInitSettingMap = new TreeMap(); + // 解析角色权限表; + for (String role : roles) { + String ledgerPrivilegeKey = getKeyOfRoleLedgerPrivilege(role); + String strLedgerPermissions = PropertiesUtils.getOptionalProperty(props, ledgerPrivilegeKey); + LedgerPermission[] ledgerPermissions = resolveLedgerPermissions(strLedgerPermissions); + + String txPrivilegeKey = getKeyOfRoleTxPrivilege(role); + String strTxPermissions = PropertiesUtils.getOptionalProperty(props, txPrivilegeKey); + TransactionPermission[] txPermissions = resolveTransactionPermissions(strTxPermissions); + + if (ledgerPermissions.length > 0 || txPermissions.length > 0) { + RoleInitData rolesSettings = new RoleInitData(role, ledgerPermissions, txPermissions); + rolesInitSettingMap.put(role, rolesSettings); + } + } + RoleInitData[] rolesInitDatas = rolesInitSettingMap.values() + .toArray(new RoleInitData[rolesInitSettingMap.size()]); + initProps.setRoles(rolesInitDatas); + // 解析共识相关的属性; initProps.consensusProvider = PropertiesUtils.getRequiredProperty(props, CONSENSUS_SERVICE_PROVIDER); String consensusConfigFilePath = PropertiesUtils.getRequiredProperty(props, CONSENSUS_CONFIG); try { - File consensusConfigFile = FileUtils.getFile(dir, consensusConfigFilePath); + File consensusConfigFile = FileUtils.getFile(baseDirectory, consensusConfigFilePath); initProps.consensusConfig = FileUtils.readProperties(consensusConfigFile); } catch (FileNotFoundException e) { throw new IllegalArgumentException( @@ -212,13 +265,13 @@ public class LedgerInitProperties { parti.setId(i); - String nameKey = getKeyOfCsParti(i, PART_NAME); + String nameKey = getKeyOfParticipant(i, PART_NAME); parti.setName(PropertiesUtils.getRequiredProperty(props, nameKey)); - String pubkeyPathKey = getKeyOfCsParti(i, PART_PUBKEY_PATH); + String pubkeyPathKey = getKeyOfParticipant(i, PART_PUBKEY_PATH); String pubkeyPath = PropertiesUtils.getProperty(props, pubkeyPathKey, false); - String pubkeyKey = getKeyOfCsParti(i, PART_PUBKEY); + String pubkeyKey = getKeyOfParticipant(i, PART_PUBKEY); String base58PubKey = PropertiesUtils.getProperty(props, pubkeyKey, false); if (base58PubKey != null) { PubKey pubKey = KeyGenCommand.decodePubKey(base58PubKey); @@ -231,13 +284,27 @@ public class LedgerInitProperties { String.format("Property[%s] and property[%s] are all empty!", pubkeyKey, pubkeyPathKey)); } - String initializerHostKey = getKeyOfCsParti(i, PART_INITIALIZER_HOST); + // 解析参与方的角色权限配置; + String partiRolesKey = getKeyOfParticipant(i, PART_ROLES); + String strPartiRoles = PropertiesUtils.getOptionalProperty(props, partiRolesKey); + String[] partiRoles = StringUtils.splitToArray(strPartiRoles, ","); + parti.setRoles(partiRoles); + + String partiRolePolicyKey = getKeyOfParticipant(i, PART_ROLES_POLICY); + String strPartiPolicy = PropertiesUtils.getOptionalProperty(props, partiRolePolicyKey); + RolesPolicy policy = strPartiPolicy == null ? RolesPolicy.UNION + : RolesPolicy.valueOf(strPartiPolicy.trim()); + policy = policy == null ? RolesPolicy.UNION : policy; + parti.setRolesPolicy(policy); + + // 解析参与方的网络配置参数; + String initializerHostKey = getKeyOfParticipant(i, PART_INITIALIZER_HOST); String initializerHost = PropertiesUtils.getRequiredProperty(props, initializerHostKey); - String initializerPortKey = getKeyOfCsParti(i, PART_INITIALIZER_PORT); + String initializerPortKey = getKeyOfParticipant(i, PART_INITIALIZER_PORT); int initializerPort = getInt(PropertiesUtils.getRequiredProperty(props, initializerPortKey)); - String initializerSecureKey = getKeyOfCsParti(i, PART_INITIALIZER_SECURE); + String initializerSecureKey = getKeyOfParticipant(i, PART_INITIALIZER_SECURE); boolean initializerSecure = Boolean .parseBoolean(PropertiesUtils.getRequiredProperty(props, initializerSecureKey)); NetworkAddress initializerAddress = new NetworkAddress(initializerHost, initializerPort, initializerSecure); @@ -249,10 +316,54 @@ public class LedgerInitProperties { return initProps; } + private static TransactionPermission[] resolveTransactionPermissions(String strTxPermissions) { + String[] strPermissions = StringUtils.splitToArray(strTxPermissions, ","); + List permissions = new ArrayList(); + if (strPermissions != null) { + for (String pm : strPermissions) { + TransactionPermission permission = TransactionPermission.valueOf(pm); + if (permission != null) { + permissions.add(permission); + } + } + } + return permissions.toArray(new TransactionPermission[permissions.size()]); + } + + private static LedgerPermission[] resolveLedgerPermissions(String strLedgerPermissions) { + String[] strPermissions = StringUtils.splitToArray(strLedgerPermissions, ","); + List permissions = new ArrayList(); + if (strPermissions != null) { + for (String pm : strPermissions) { + LedgerPermission permission = LedgerPermission.valueOf(pm); + if (permission != null) { + permissions.add(permission); + } + } + } + return permissions.toArray(new LedgerPermission[permissions.size()]); + } + + private static String getKeyOfRoleLedgerPrivilege(String role) { + return String.format(ROLE_LEDGER_PRIVILEGES_PATTERN, role); + } + + private static String getKeyOfRoleTxPrivilege(String role) { + return String.format(ROLE_TX_PRIVILEGES_PATTERN, role); + } + private static int getInt(String strInt) { return Integer.parseInt(strInt.trim()); } + public RoleInitData[] getRoles() { + return roles; + } + + public void setRoles(RoleInitData[] roles) { + this.roles = roles; + } + /** * 参与方配置信息; * @@ -267,10 +378,12 @@ public class LedgerInitProperties { private String name; -// private String pubKeyPath; - private PubKey pubKey; + private String[] roles; + + private RolesPolicy rolesPolicy; + // private NetworkAddress consensusAddress; private NetworkAddress initializerAddress; @@ -321,6 +434,22 @@ public class LedgerInitProperties { this.address = AddressEncoding.generateAddress(pubKey); } + public String[] getRoles() { + return roles; + } + + public void setRoles(String[] roles) { + this.roles = roles; + } + + public RolesPolicy getRolesPolicy() { + return rolesPolicy; + } + + public void setRolesPolicy(RolesPolicy rolesPolicy) { + this.rolesPolicy = rolesPolicy; + } + } } diff --git a/source/tools/tools-initializer/src/test/java/test/com/jd/blockchain/tools/initializer/LedgerInitPropertiesTest.java b/source/tools/tools-initializer/src/test/java/test/com/jd/blockchain/tools/initializer/LedgerInitPropertiesTest.java index 3e0a004e..6e890a52 100644 --- a/source/tools/tools-initializer/src/test/java/test/com/jd/blockchain/tools/initializer/LedgerInitPropertiesTest.java +++ b/source/tools/tools-initializer/src/test/java/test/com/jd/blockchain/tools/initializer/LedgerInitPropertiesTest.java @@ -1,12 +1,18 @@ package test.com.jd.blockchain.tools.initializer; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; +import java.util.HashMap; +import java.util.Map; import java.util.TimeZone; import org.junit.Test; @@ -14,6 +20,10 @@ import org.springframework.core.io.ClassPathResource; import com.jd.blockchain.crypto.AddressEncoding; import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.ledger.LedgerPermission; +import com.jd.blockchain.ledger.RoleInitData; +import com.jd.blockchain.ledger.RolesPolicy; +import com.jd.blockchain.ledger.TransactionPermission; import com.jd.blockchain.tools.initializer.LedgerInitProperties; import com.jd.blockchain.tools.initializer.LedgerInitProperties.ConsensusParticipantConfig; import com.jd.blockchain.tools.keygen.KeyGenCommand; @@ -22,19 +32,20 @@ import com.jd.blockchain.utils.codec.HexUtils; public class LedgerInitPropertiesTest { private static String expectedCreatedTimeStr = "2019-08-01 14:26:58.069+0800"; - + private static String expectedCreatedTimeStr1 = "2019-08-01 13:26:58.069+0700"; - + @Test public void testTimeFormat() throws ParseException { SimpleDateFormat timeFormat = new SimpleDateFormat(LedgerInitProperties.CREATED_TIME_FORMAT); -// timeFormat.setTimeZone(TimeZone.getTimeZone("GMT+08:00")); - TimeZone.setDefault(TimeZone.getTimeZone("GMT+08:00")); - + timeFormat.setTimeZone(TimeZone.getTimeZone("GMT+08:00")); + // 或者设置全局的默认时区; + // TimeZone.setDefault(TimeZone.getTimeZone("GMT+08:00")); + Date time = timeFormat.parse(expectedCreatedTimeStr); String actualTimeStr = timeFormat.format(time); assertEquals(expectedCreatedTimeStr, actualTimeStr); - + Date time1 = timeFormat.parse(expectedCreatedTimeStr1); String actualTimeStr1 = timeFormat.format(time1); assertEquals(expectedCreatedTimeStr, actualTimeStr1); @@ -42,11 +53,13 @@ public class LedgerInitPropertiesTest { @Test public void testProperties() throws IOException, ParseException { + // 加载用于测试的账本初始化配置; ClassPathResource ledgerInitSettingResource = new ClassPathResource("ledger.init"); InputStream in = ledgerInitSettingResource.getInputStream(); try { LedgerInitProperties initProps = LedgerInitProperties.resolve(in); - assertEquals(4, initProps.getConsensusParticipantCount()); + + // 验证账本信息; String expectedLedgerSeed = "932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe" .replace("-", ""); String actualLedgerSeed = HexUtils.encode(initProps.getLedgerSeed()); @@ -56,10 +69,54 @@ public class LedgerInitPropertiesTest { timeFormat.setTimeZone(TimeZone.getTimeZone("GMT+08:00")); long expectedTs = timeFormat.parse(expectedCreatedTimeStr).getTime(); assertEquals(expectedTs, initProps.getCreatedTime()); - + String createdTimeStr = timeFormat.format(new Date(initProps.getCreatedTime())); assertEquals(expectedCreatedTimeStr, createdTimeStr); + // 验证角色配置; + RoleInitData[] roles = initProps.getRoles(); + assertEquals(4, roles.length); + Map rolesInitDatas = new HashMap(); + for (RoleInitData r : roles) { + rolesInitDatas.put(r.getRoleName(), r); + } + // 初始化配置的角色最终也是有序排列的,按照角色名称的自然顺序; + String[] expectedRolesNames = { "DEFAULT", "ADMIN", "MANAGER", "GUEST" }; + Arrays.sort(expectedRolesNames); + assertEquals(expectedRolesNames[0], roles[0].getRoleName()); + assertEquals(expectedRolesNames[1], roles[1].getRoleName()); + assertEquals(expectedRolesNames[2], roles[2].getRoleName()); + assertEquals(expectedRolesNames[3], roles[3].getRoleName()); + + RoleInitData roleDefault = rolesInitDatas.get("DEFAULT"); + assertArrayEquals( + new LedgerPermission[] { LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT }, + roleDefault.getLedgerPermissions()); + assertArrayEquals(new TransactionPermission[] { TransactionPermission.DIRECT_OPERATION, + TransactionPermission.CONTRACT_OPERATION }, roleDefault.getTransactionPermissions()); + + RoleInitData roleAdmin = rolesInitDatas.get("ADMIN"); + assertArrayEquals(new LedgerPermission[] { LedgerPermission.AUTHORIZE_ROLES, LedgerPermission.SET_CONSENSUS, + LedgerPermission.SET_CRYPTO, LedgerPermission.REGISTER_PARTICIPANT, + LedgerPermission.REGISTER_USER }, roleAdmin.getLedgerPermissions()); + assertArrayEquals(new TransactionPermission[] { TransactionPermission.DIRECT_OPERATION }, + roleAdmin.getTransactionPermissions()); + + RoleInitData roleManager = rolesInitDatas.get("MANAGER"); + assertArrayEquals( + new LedgerPermission[] { LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT, + LedgerPermission.REGISTER_CONTRACT, LedgerPermission.UPGRADE_CONTRACT, + LedgerPermission.SET_USER_ATTRIBUTES, LedgerPermission.WRITE_DATA_ACCOUNT }, + roleManager.getLedgerPermissions()); + assertArrayEquals(new TransactionPermission[] { TransactionPermission.DIRECT_OPERATION, + TransactionPermission.CONTRACT_OPERATION }, roleManager.getTransactionPermissions()); + + RoleInitData roleGuest = rolesInitDatas.get("GUEST"); + assertTrue(roleGuest.getLedgerPermissions() == null || roleGuest.getLedgerPermissions().length == 0); + assertArrayEquals(new TransactionPermission[] { TransactionPermission.CONTRACT_OPERATION }, + roleGuest.getTransactionPermissions()); + + // 验证共识和密码配置; assertEquals("com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider", initProps.getConsensusProvider()); @@ -68,6 +125,9 @@ public class LedgerInitPropertiesTest { assertEquals("com.jd.blockchain.crypto.service.classic.ClassicCryptoService", cryptoProviders[0]); assertEquals("com.jd.blockchain.crypto.service.sm.SMCryptoService", cryptoProviders[1]); + // 验证参与方信息; + assertEquals(4, initProps.getConsensusParticipantCount()); + ConsensusParticipantConfig part0 = initProps.getConsensusParticipant(0); assertEquals("jd.com", part0.getName()); PubKey pubKey0 = KeyGenCommand.decodePubKey("3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9"); @@ -75,14 +135,27 @@ public class LedgerInitPropertiesTest { assertEquals("127.0.0.1", part0.getInitializerAddress().getHost()); assertEquals(8800, part0.getInitializerAddress().getPort()); assertEquals(true, part0.getInitializerAddress().isSecure()); + assertArrayEquals(new String[] {"ADMIN", "MANAGER"}, part0.getRoles()); + assertEquals(RolesPolicy.UNION, part0.getRolesPolicy()); + ConsensusParticipantConfig part1 = initProps.getConsensusParticipant(1); assertEquals(false, part1.getInitializerAddress().isSecure()); PubKey pubKey1 = KeyGenCommand.decodePubKey("3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX"); assertEquals(pubKey1, part1.getPubKey()); + assertArrayEquals(new String[] { "MANAGER"}, part1.getRoles()); + assertEquals(RolesPolicy.UNION, part1.getRolesPolicy()); ConsensusParticipantConfig part2 = initProps.getConsensusParticipant(2); assertEquals("7VeRAr3dSbi1xatq11ZcF7sEPkaMmtZhV9shonGJWk9T4pLe", part2.getPubKey().toBase58()); + assertArrayEquals(new String[] { "MANAGER"}, part2.getRoles()); + assertEquals(RolesPolicy.UNION, part2.getRolesPolicy()); + + ConsensusParticipantConfig part3 = initProps.getConsensusParticipant(3); + PubKey pubKey3 = KeyGenCommand.decodePubKey("3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk"); + assertEquals(pubKey3, part3.getPubKey()); + assertArrayEquals(new String[] { "GUEST"}, part3.getRoles()); + assertEquals(RolesPolicy.INTERSECT, part3.getRolesPolicy()); } finally { in.close(); diff --git a/source/tools/tools-initializer/src/test/resources/ledger.init b/source/tools/tools-initializer/src/test/resources/ledger.init index 2d574f93..275778b7 100644 --- a/source/tools/tools-initializer/src/test/resources/ledger.init +++ b/source/tools/tools-initializer/src/test/resources/ledger.init @@ -5,9 +5,52 @@ ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323 #账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; ledger.name=test -#声明的账本创建时间;格式为 “yyyy-MM-dd HH:mm:ss.SSSZ”,表示”年-月-日 时:分:秒:毫秒时区“;例如:“2019-08-01 14:26:58.069+0800”,其中,+0800 表示时区是东8区 +#声明账本的创建时间;格式为 “yyyy-MM-dd HH:mm:ss.SSSZ”,表示”年-月-日 时:分:秒:毫秒时区“;例如:“2019-08-01 14:26:58.069+0800”,其中,+0800 表示时区是东8区 created-time=2019-08-01 14:26:58.069+0800 + +#----------------------------------------------- +# 初始的角色名称列表;可选项; +# 角色名称不区分大小写,最长不超过20个字符;多个角色名称之间用半角的逗点“,”分隔; +# 系统会预置一个默认角色“DEFAULT”,所有未指定角色的用户都以赋予该角色的权限;若初始化时未配置默认角色的权限,则为默认角色分配所有权限; +# +# 注:如果声明了角色,但未声明角色对应的权限清单,这会忽略该角色的初始化; +# +security.roles=DEFAULT, ADMIN, MANAGER, GUEST + +# 赋予角色的账本权限清单;可选项; +# 可选的权限如下; +# AUTHORIZE_ROLES, SET_CONSENSUS, SET_CRYPTO, REGISTER_PARTICIPANT, +# REGISTER_USER, REGISTER_DATA_ACCOUNT, REGISTER_CONTRACT, UPGRADE_CONTRACT, +# SET_USER_ATTRIBUTES, WRITE_DATA_ACCOUNT, +# APPROVE_TX, CONSENSUS_TX +# 多项权限之间用逗点“,”分隔; +# +security.role.DEFAULT.ledger-privileges=REGISTER_USER, REGISTER_DATA_ACCOUNT + +# 赋予角色的交易权限清单;可选项; +# 可选的权限如下; +# DIRECT_OPERATION, CONTRACT_OPERATION +# 多项权限之间用逗点“,”分隔; +# +security.role.DEFAULT.tx-privileges=DIRECT_OPERATION, CONTRACT_OPERATION + +# 其它角色的配置示例; +# 系统管理员角色:只能操作全局性的参数配置和用户注册,只能执行直接操作指令; +security.role.ADMIN.ledger-privileges=AUTHORIZE_ROLES, SET_CONSENSUS, SET_CRYPTO, REGISTER_PARTICIPANT, REGISTER_USER +security.role.ADMIN.tx-privileges=DIRECT_OPERATION + +# 业务主管角色:只能够执行账本数据相关的操作,包括注册用户、注册数据账户、注册合约、升级合约、写入数据等;能够执行直接操作指令和调用合约; +security.role.MANAGER.ledger-privileges=REGISTER_USER, REGISTER_DATA_ACCOUNT, REGISTER_CONTRACT, UPGRADE_CONTRACT, SET_USER_ATTRIBUTES, WRITE_DATA_ACCOUNT, +security.role.MANAGER.tx-privileges=DIRECT_OPERATION, CONTRACT_OPERATION + +# 访客角色:不具备任何的账本权限,只有数据读取的操作;也只能够通过调用合约来读取数据; +security.role.GUEST.ledger-privileges= +security.role.GUEST.tx-privileges=CONTRACT_OPERATION + + + +#----------------------------------------------- #共识服务提供者;必须; consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider @@ -28,6 +71,10 @@ cons_parti.0.name=jd.com cons_parti.0.pubkey-path=keys/jd-com.pub #第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; cons_parti.0.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 +#第0个参与方的角色清单;可选项; +cons_parti.0.roles=ADMIN, MANAGER +#第0个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; +cons_parti.0.roles-policy=UNION #第0个参与方的共识服务的主机地址; cons_parti.0.consensus.host=127.0.0.1 #第0个参与方的共识服务的端口; @@ -47,6 +94,10 @@ cons_parti.1.name=at.com cons_parti.1.pubkey-path=keys/at-com.pub #第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; cons_parti.1.pubkey=3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX +#第1个参与方的角色清单;可选项; +cons_parti.1.roles=MANAGER +#第1个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; +cons_parti.1.roles-policy=UNION #第1个参与方的共识服务的主机地址; cons_parti.1.consensus.host=127.0.0.1 #第1个参与方的共识服务的端口; @@ -66,6 +117,10 @@ cons_parti.2.name=bt.com cons_parti.2.pubkey-path=classpath:keys/parti2.pub #第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; cons_parti.2.pubkey= +#第2个参与方的角色清单;可选项; +cons_parti.2.roles=MANAGER +#第2个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; +cons_parti.2.roles-policy=UNION #第2个参与方的共识服务的主机地址; cons_parti.2.consensus.host=127.0.0.1 #第2个参与方的共识服务的端口; @@ -85,6 +140,10 @@ cons_parti.3.name=xt.com cons_parti.3.pubkey-path=keys/xt-com.pub #第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; cons_parti.3.pubkey=3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk +#第3个参与方的角色清单;可选项; +cons_parti.3.roles=GUEST +#第3个参与方的角色权限策略,可选值有:UNION(并集),INTERSECT(交集);可选项; +cons_parti.3.roles-policy=INTERSECT #第3个参与方的共识服务的主机地址; cons_parti.3.consensus.host=127.0.0.1 #第3个参与方的共识服务的端口; diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/PropertiesUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/PropertiesUtils.java index 994272b0..f1fba9b1 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/PropertiesUtils.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/PropertiesUtils.java @@ -263,6 +263,10 @@ public abstract class PropertiesUtils { public static String getRequiredProperty(Properties props, String key) { return getProperty(props, key, true); } + + public static String getOptionalProperty(Properties props, String key) { + return getProperty(props, key, false); + } /** * 返回指定的属性;
diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/StringUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/StringUtils.java index 5ae1a856..fea16ace 100644 --- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/StringUtils.java +++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/StringUtils.java @@ -1,24 +1,75 @@ package com.jd.blockchain.utils; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; import java.util.regex.Pattern; /** - * @Author zhaogw - * date 2018/11/26 20:46 + * @Author zhaogw date 2018/11/26 20:46 */ public class StringUtils { - public static boolean isEmpty(Object str) { - return str == null || "".equals(str); - } - - /* - * 判断是否为整数 - * @param str 传入的字符串 - * @return 是整数返回true,否则返回false - */ - - public static boolean isNumber(String str) { - Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$"); - return pattern.matcher(str).matches(); - } + + public static final String[] EMPTY_ARRAY = {}; + + public static boolean isEmpty(Object str) { + return str == null || "".equals(str); + } + + /* + * 判断是否为整数 + * + * @param str 传入的字符串 + * + * @return 是整数返回true,否则返回false + */ + + public static boolean isNumber(String str) { + Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$"); + return pattern.matcher(str).matches(); + } + + /** + * 按照指定的分隔符把字符串分解为字符数组,同时截掉每一个元素两端的空白字符,并忽略掉空字符元素; + * + * @param str 要被截断的字符串; + * @param delimiter 分隔符; + * @return + */ + public static String[] splitToArray(String str, String delimiter) { + return splitToArray(str, delimiter, true, true); + } + + /** + * 按照指定的分隔符把字符串分解为字符数组 + * + * @param str 要被截断的字符串; + * @param delimiter 分隔符; + * @param trimElement 是否截断元素两端的空白字符; + * @param ignoreEmptyElement 是否忽略空字符元素; + * @return + */ + public static String[] splitToArray(String str, String delimiter, boolean trimElement, boolean ignoreEmptyElement) { + if (str == null) { + return null; + } + if (trimElement) { + str = str.trim(); + } + if (str.length() == 0) { + return EMPTY_ARRAY; + } + StringTokenizer tokenizer = new StringTokenizer(str, delimiter); + List tokens = new ArrayList<>(); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if (trimElement) { + token = token.trim(); + } + if ((!ignoreEmptyElement) || token.length() > 0) { + tokens.add(token); + } + } + return tokens.toArray(new String[tokens.size()]); + } } \ No newline at end of file