| @@ -36,59 +36,54 @@ public enum LedgerPermission { | |||
| REGISTER_PARTICIPANT((byte) 0x04), | |||
| /** | |||
| * 设置参与方的权限;<br> | |||
| * 注册用户;<br> | |||
| * | |||
| * 如果不具备此项权限,则无法设置参与方的“提交交易”、“参与共识”的权限; | |||
| * 如果不具备此项权限,则无法注册用户; | |||
| */ | |||
| SET_PARTICIPANT_PERMISSION((byte) 0x05), | |||
| REGISTER_USER((byte) 0x05), | |||
| /** | |||
| * 参与方核准交易;<br> | |||
| * | |||
| * 如果不具备此项权限,则无法作为节点签署由终端提交的交易; | |||
| * <p> | |||
| * 只对交易请求的节点签名列表{@link TransactionRequest#getNodeSignatures()}的用户产生影响; | |||
| * 注册数据账户;<br> | |||
| */ | |||
| APPROVE_TX((byte) 0x06), | |||
| REGISTER_DATA_ACCOUNT((byte) 0x06), | |||
| /** | |||
| * 参与方共识交易;<br> | |||
| * | |||
| * 如果不具备此项权限,则无法作为共识节点接入并对交易进行共识; | |||
| * 注册合约;<br> | |||
| */ | |||
| CONSENSUS_TX((byte) 0x07), | |||
| REGISTER_CONTRACT((byte) 0x07), | |||
| /** | |||
| * 注册用户;<br> | |||
| * | |||
| * 如果不具备此项权限,则无法注册用户; | |||
| * 升级合约 | |||
| */ | |||
| REGISTER_USER((byte) 0x08), | |||
| UPGRADE_CONTRACT((byte) 0x08), | |||
| /** | |||
| * 设置用户属性;<br> | |||
| */ | |||
| SET_USER_ATTRIBUTES((byte) 0x09), | |||
| /** | |||
| * 注册数据账户;<br> | |||
| */ | |||
| REGISTER_DATA_ACCOUNT((byte) 0x0A), | |||
| /** | |||
| * 写入数据账户;<br> | |||
| */ | |||
| WRITE_DATA_ACCOUNT((byte) 0x0B), | |||
| WRITE_DATA_ACCOUNT((byte) 0x0A), | |||
| /** | |||
| * 注册合约;<br> | |||
| * 参与方核准交易;<br> | |||
| * | |||
| * 如果不具备此项权限,则无法作为节点签署由终端提交的交易; | |||
| * <p> | |||
| * 只对交易请求的节点签名列表{@link TransactionRequest#getNodeSignatures()}的用户产生影响; | |||
| */ | |||
| REGISTER_CONTRACT((byte) 0x0C), | |||
| APPROVE_TX((byte) 0x0B), | |||
| /** | |||
| * 升级合约 | |||
| * 参与方共识交易;<br> | |||
| * | |||
| * 如果不具备此项权限,则无法作为共识节点接入并对交易进行共识; | |||
| */ | |||
| UPGRADE_CONTRACT((byte) 0x0D); | |||
| CONSENSUS_TX((byte) 0x0C); | |||
| @EnumField(type = PrimitiveType.INT8) | |||
| public final byte CODE; | |||
| @@ -5,7 +5,7 @@ import java.util.List; | |||
| public class SecurityInitData implements SecurityInitSettings { | |||
| private List<RoleInitSettings> roles = new ArrayList<RoleInitSettings>(); | |||
| private List<RoleInitData> roles = new ArrayList<RoleInitData>(); | |||
| @Override | |||
| public RoleInitData[] getRoles() { | |||
| @@ -13,8 +13,8 @@ public class SecurityInitData implements SecurityInitSettings { | |||
| } | |||
| public void setRoles(RoleInitData[] roles) { | |||
| List<RoleInitSettings> list = new ArrayList<RoleInitSettings>(); | |||
| for (RoleInitSettings r : roles) { | |||
| List<RoleInitData> list = new ArrayList<RoleInitData>(); | |||
| for (RoleInitData r : roles) { | |||
| list.add(r); | |||
| } | |||
| this.roles = list; | |||
| @@ -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 | |||
| @@ -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; | |||
| @@ -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<ConsensusParticipantConfig> 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<String, RoleInitData> rolesInitSettingMap = new TreeMap<String, RoleInitData>(); | |||
| // 解析角色权限表; | |||
| 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<TransactionPermission> permissions = new ArrayList<TransactionPermission>(); | |||
| 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<LedgerPermission> permissions = new ArrayList<LedgerPermission>(); | |||
| 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; | |||
| } | |||
| } | |||
| } | |||
| @@ -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<String, RoleInitData> rolesInitDatas = new HashMap<String, RoleInitData>(); | |||
| 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(); | |||
| @@ -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个参与方的共识服务的端口; | |||
| @@ -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); | |||
| } | |||
| /** | |||
| * 返回指定的属性; <br> | |||
| @@ -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<String> 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()]); | |||
| } | |||
| } | |||