@@ -36,34 +36,26 @@ 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> | |||
@@ -71,24 +63,27 @@ public enum LedgerPermission { | |||
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()]); | |||
} | |||
} |