Browse Source

Fixed the bug that: when the LedgerPrivilege or TransactionPrivilege property of Privileges is not configured, this property is null after deserialization recover this Privileges instance;

tags/1.1.0
huanghaiquan 5 years ago
parent
commit
1081229733
9 changed files with 223 additions and 63 deletions
  1. +9
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManager.java
  2. +3
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManagerImpl.java
  3. +1
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java
  4. +1
    -1
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java
  5. +81
    -47
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerSecurityManagerTest.java
  6. +1
    -1
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java
  7. +3
    -1
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPermission.java
  8. +32
    -7
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PrivilegeBitset.java
  9. +92
    -0
      source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/PrivilegesTest.java

+ 9
- 2
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManager.java View File

@@ -6,8 +6,15 @@ import com.jd.blockchain.utils.Bytes;

public interface LedgerSecurityManager {

String DEFAULT_ROLE = "_DEFAULT";
String DEFAULT_ROLE = "DEFAULT";

SecurityPolicy getSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes);
/**
* 创建一项与指定的终端用户和节点参与方相关的安全策略;
*
* @param endpoints 终端用户的地址列表;
* @param nodes 节点参与方的地址列表;
* @return 一项安全策略;
*/
SecurityPolicy createSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes);

}

+ 3
- 3
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerSecurityManagerImpl.java View File

@@ -29,8 +29,9 @@ public class LedgerSecurityManagerImpl implements LedgerSecurityManager {

private UserRoleSettings userRolesSettings;

//用户的权限配置
private Map<Bytes, UserRolesPrivileges> userPrivilegesCache = new ConcurrentHashMap<>();
private Map<Bytes, UserRoles> userRolesCache = new ConcurrentHashMap<>();
private Map<String, RolePrivileges> rolesPrivilegeCache = new ConcurrentHashMap<>();

@@ -40,8 +41,7 @@ public class LedgerSecurityManagerImpl implements LedgerSecurityManager {
}

@Override
public SecurityPolicy getSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) {

public SecurityPolicy createSecurityPolicy(Set<Bytes> endpoints, Set<Bytes> nodes) {
Map<Bytes, UserRolesPrivileges> endpointPrivilegeMap = new HashMap<>();
Map<Bytes, UserRolesPrivileges> nodePrivilegeMap = new HashMap<>();



+ 1
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/TransactionBatchProcessor.java View File

@@ -90,7 +90,7 @@ public class TransactionBatchProcessor implements TransactionBatchProcess {
TransactionRequestExtension reqExt = new TransactionRequestExtensionImpl(request);

// 初始化交易的用户安全策略;
SecurityPolicy securityPolicy = securityManager.getSecurityPolicy(reqExt.getEndpointAddresses(),
SecurityPolicy securityPolicy = securityManager.createSecurityPolicy(reqExt.getEndpointAddresses(),
reqExt.getNodeAddresses());
SecurityContext.setContextUsersPolicy(securityPolicy);



+ 1
- 1
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/ContractInvokingTest.java View File

@@ -200,7 +200,7 @@ public class ContractInvokingTest {
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);
when(securityManager.createSecurityPolicy(any(), any())).thenReturn(securityPolicy);

return securityManager;
}


+ 81
- 47
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/LedgerSecurityManagerTest.java View File

@@ -1,5 +1,6 @@
package test.com.jd.blockchain.ledger.core;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

@@ -18,10 +19,8 @@ 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;
@@ -56,30 +55,18 @@ public class LedgerSecurityManagerTest {
CRYPTO_SETTINGS = cryptoConfig;
}

private RolePrivilegeSettings initRoles(MemoryKVStorage testStorage, String[] roles, Privileges[] privilege) {
private RolePrivilegeDataset createRolePrivilegeDataset(MemoryKVStorage testStorage) {
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) {
private UserRoleDataset createUserRoleDataset(MemoryKVStorage testStorage) {
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;
}

@@ -87,55 +74,102 @@ public class LedgerSecurityManagerTest {
public void testGetSecurityPolicy() {
MemoryKVStorage testStorage = new MemoryKVStorage();

// 定义不同角色用户的 keypair;
final BlockchainKeypair kpManager = BlockchainKeyGenerator.getInstance().generate();
final BlockchainKeypair kpEmployee = BlockchainKeyGenerator.getInstance().generate();
final BlockchainKeypair kpDevoice = BlockchainKeyGenerator.getInstance().generate();
final Map<Bytes, BlockchainKeypair> endpoints = new HashMap<>();
endpoints.put(kpManager.getAddress(), kpManager);
endpoints.put(kpEmployee.getAddress(), kpEmployee);
final Map<Bytes, BlockchainKeypair> nodes = new HashMap<>();
nodes.put(kpDevoice.getAddress(), kpDevoice);
final BlockchainKeypair kpPlatform = BlockchainKeyGenerator.getInstance().generate();

// 定义角色和权限;
final String ROLE_ADMIN = "ID_ADMIN";
final String ROLE_OPERATOR = "OPERATOR";
final String ROLE_DATA_COLLECTOR = "DATA_COLLECTOR";
final String ROLE_PLATFORM = "PLATFORM";

// 定义管理员角色的权限:【账本权限只允许:注册用户、注册数据账户】【交易权限只允许:调用账本直接操作】
final Privileges PRIVILEGES_ADMIN = Privileges.configure()
.enable(LedgerPermission.REGISTER_USER, LedgerPermission.REGISTER_DATA_ACCOUNT)
.enable(TransactionPermission.DIRECT_OPERATION, TransactionPermission.CONTRACT_OPERATION);
.enable(TransactionPermission.DIRECT_OPERATION);

final Privileges PRIVILEGES_OPERATOR = Privileges.configure()
.enable(LedgerPermission.WRITE_DATA_ACCOUNT, LedgerPermission.APPROVE_TX)
// 定义操作员角色的权限:【账本权限只允许:写入数据账户】【交易权限只允许:调用合约】
final Privileges PRIVILEGES_OPERATOR = Privileges.configure().enable(LedgerPermission.WRITE_DATA_ACCOUNT)
.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 });
.enable(TransactionPermission.DIRECT_OPERATION);

// 定义平台角色的权限:【账本权限只允许:签署合约】 (只允许作为节点签署交易,不允许作为终端发起交易指令)
final Privileges PRIVILEGES_PLATFORM = Privileges.configure().enable(LedgerPermission.APPROVE_TX);

RolePrivilegeDataset rolePrivilegeDataset = createRolePrivilegeDataset(testStorage);
long v = rolePrivilegeDataset.addRolePrivilege(ROLE_ADMIN, PRIVILEGES_ADMIN);
assertTrue(v > -1);
v = rolePrivilegeDataset.addRolePrivilege(ROLE_OPERATOR, PRIVILEGES_OPERATOR);
assertTrue(v > -1);
v = rolePrivilegeDataset.addRolePrivilege(ROLE_DATA_COLLECTOR, PRIVILEGES_DATA_COLLECTOR);
assertTrue(v > -1);
v = rolePrivilegeDataset.addRolePrivilege(ROLE_PLATFORM, PRIVILEGES_PLATFORM);
assertTrue(v > -1);
rolePrivilegeDataset.commit();

// 为用户分配角色;
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));
String[] platformRoles = new String[] { ROLE_PLATFORM };
UserRoleDataset userRolesDataset = createUserRoleDataset(testStorage);
userRolesDataset.addUserRoles(kpManager.getAddress(), RolesPolicy.UNION, managerRoles);
userRolesDataset.addUserRoles(kpEmployee.getAddress(), RolesPolicy.UNION, employeeRoles);
userRolesDataset.addUserRoles(kpDevoice.getAddress(), RolesPolicy.UNION, devoiceRoles);
userRolesDataset.addUserRoles(kpPlatform.getAddress(), RolesPolicy.UNION, platformRoles);
userRolesDataset.commit();

// 创建安全管理器;
LedgerSecurityManager securityManager = new LedgerSecurityManagerImpl(rolePrivilegeDataset, userRolesDataset);

// 定义终端用户列表;终端用户一起共同具有 ADMIN、OPERATOR 角色;
final Map<Bytes, BlockchainKeypair> endpoints = new HashMap<>();
endpoints.put(kpManager.getAddress(), kpManager);
endpoints.put(kpEmployee.getAddress(), kpEmployee);

// 定义节点参与方列表;
final Map<Bytes, BlockchainKeypair> nodes = new HashMap<>();
nodes.put(kpPlatform.getAddress(), kpPlatform);

// 创建一项与指定的终端用户和节点参与方相关的安全策略;
SecurityPolicy policy = securityManager.createSecurityPolicy(endpoints.keySet(), nodes.keySet());

// 校验安全策略的正确性;
LedgerPermission[] ledgerPermissions = LedgerPermission.values();
for (LedgerPermission p : ledgerPermissions) {
// 终端节点有 ADMIN 和 OPERATOR 两种角色的合并权限;
if (p == LedgerPermission.REGISTER_USER || p == LedgerPermission.REGISTER_DATA_ACCOUNT
|| p == LedgerPermission.WRITE_DATA_ACCOUNT) {
assertTrue(policy.isEnableToEndpoints(p, MultiIdsPolicy.AT_LEAST_ONE));
} else {
assertFalse(policy.isEnableToEndpoints(p, MultiIdsPolicy.AT_LEAST_ONE));
}

if (p == LedgerPermission.APPROVE_TX) {
// 共识参与方只有 PLATFORM 角色的权限:核准交易;
assertTrue(policy.isEnableToNodes(p, MultiIdsPolicy.AT_LEAST_ONE));
} else {
assertFalse(policy.isEnableToNodes(p, MultiIdsPolicy.AT_LEAST_ONE));
}
}

TransactionPermission[] transactionPermissions = TransactionPermission.values();
for (TransactionPermission p : transactionPermissions) {
// 终端节点有 ADMIN 和 OPERATOR 两种角色的合并权限;
if (p == TransactionPermission.DIRECT_OPERATION || p == TransactionPermission.CONTRACT_OPERATION) {
assertTrue(policy.isEnableToEndpoints(p, MultiIdsPolicy.AT_LEAST_ONE));
} else {
assertFalse(policy.isEnableToEndpoints(p, MultiIdsPolicy.AT_LEAST_ONE));
}

assertFalse(policy.isEnableToNodes(p, MultiIdsPolicy.AT_LEAST_ONE));
}
}

}

+ 1
- 1
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/TransactionBatchProcessorTest.java View File

@@ -125,7 +125,7 @@ public class TransactionBatchProcessorTest {
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);
when(securityManager.createSecurityPolicy(any(), any())).thenReturn(securityPolicy);

return securityManager;
}


+ 3
- 1
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerPermission.java View File

@@ -45,7 +45,9 @@ public enum LedgerPermission {
/**
* 参与方核准交易;<br>
*
* 如果不具备此项权限,则无法作为网关节点接入并签署由终端提交的交易;
* 如果不具备此项权限,则无法作为节点签署由终端提交的交易;
* <p>
* 只对交易请求的节点签名列表{@link TransactionRequest#getNodeSignatures()}的用户产生影响;
*/
APPROVE_TX((byte) 0x06),



+ 32
- 7
source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/PrivilegeBitset.java View File

@@ -11,17 +11,37 @@ import com.jd.blockchain.utils.io.BytesSerializable;
*
*/
public class PrivilegeBitset<E extends Enum<?>> implements Privilege<E>, BytesSerializable {
// 加入前缀位,可避免序列化时输出空的字节数组;
private static final boolean[] PREFIX = { false, false, false, true, false, false, false, true };
private static final int OFFSET = PREFIX.length;
private static final int MAX_SIZE = 256 - PREFIX.length;

private BitSet permissionBits;

private CodeIndexer<E> codeIndexer;

public PrivilegeBitset(CodeIndexer<E> codeIndexer) {
this(new BitSet(), codeIndexer);
this.permissionBits = new BitSet();
this.codeIndexer = codeIndexer;
// 设置前缀;
for (int i = 0; i < PREFIX.length; i++) {
permissionBits.set(i, PREFIX[i]);
}
}

public PrivilegeBitset(byte[] codeBytes, CodeIndexer<E> codeIndexer) {
this(BitSet.valueOf(codeBytes), codeIndexer);
if (codeBytes.length > MAX_SIZE) {
throw new IllegalArgumentException(
"The size of code bytes specified to PrivilegeBitset exceed the max size[" + MAX_SIZE + "]!");
}
this.permissionBits = BitSet.valueOf(codeBytes);
this.codeIndexer = codeIndexer;
// 校验前缀;
for (int i = 0; i < PREFIX.length; i++) {
if (permissionBits.get(i) != PREFIX[i]) {
throw new IllegalArgumentException("The code bytes is not match the privilege prefix code!");
}
}
}

private PrivilegeBitset(BitSet bits, CodeIndexer<E> codeIndexer) {
@@ -30,28 +50,28 @@ public class PrivilegeBitset<E extends Enum<?>> implements Privilege<E>, BytesSe
}

public boolean isEnable(E permission) {
return permissionBits.get(codeIndexer.getCodeIndex(permission));
return permissionBits.get(index(permission));
}

public void enable(E permission) {
permissionBits.set(codeIndexer.getCodeIndex(permission));
permissionBits.set(index(permission));
}

public void disable(E permission) {
permissionBits.clear(codeIndexer.getCodeIndex(permission));
permissionBits.clear(index(permission));
}

@SuppressWarnings("unchecked")
public void enable(E... permissions) {
for (E p : permissions) {
permissionBits.set(codeIndexer.getCodeIndex(p));
permissionBits.set(index(p));
}
}

@SuppressWarnings("unchecked")
public void disable(E... permissions) {
for (E p : permissions) {
permissionBits.clear(codeIndexer.getCodeIndex(p));
permissionBits.clear(index(p));
}
}

@@ -72,6 +92,7 @@ public class PrivilegeBitset<E extends Enum<?>> implements Privilege<E>, BytesSe

/**
* 把指定的权限合并到当前的权限中; <br>
*
* @param privileges
* @param offset
* @param count
@@ -115,6 +136,10 @@ public class PrivilegeBitset<E extends Enum<?>> implements Privilege<E>, BytesSe
return new PrivilegeBitset<E>((BitSet) permissionBits.clone(), codeIndexer);
}

private int index(E permission) {
return OFFSET + codeIndexer.getCodeIndex(permission);
}

static interface CodeIndexer<E extends Enum<?>> {
int getCodeIndex(E permission);
}


+ 92
- 0
source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/PrivilegesTest.java View File

@@ -0,0 +1,92 @@
package test.com.jd.blockchain.ledger;

import static org.junit.Assert.*;

import org.junit.Test;

import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.ledger.LedgerPermission;
import com.jd.blockchain.ledger.PrivilegeSet;
import com.jd.blockchain.ledger.Privileges;
import com.jd.blockchain.ledger.TransactionPermission;

public class PrivilegesTest {

@Test
public void test() {
// 正常情形;
{
Privileges privileges = Privileges.configure()
.enable(LedgerPermission.REGISTER_USER, LedgerPermission.APPROVE_TX)
.enable(TransactionPermission.DIRECT_OPERATION);

byte[] bytes = BinaryProtocol.encode(privileges, PrivilegeSet.class);

PrivilegeSet decodePrivileges = BinaryProtocol.decode(bytes);

assertNotNull(decodePrivileges.getLedgerPrivilege());
assertNotNull(decodePrivileges.getTransactionPrivilege());

for (LedgerPermission p : LedgerPermission.values()) {
if (p == LedgerPermission.REGISTER_USER || p == LedgerPermission.APPROVE_TX) {
assertTrue(decodePrivileges.getLedgerPrivilege().isEnable(p));
} else {
assertFalse(decodePrivileges.getLedgerPrivilege().isEnable(p));
}
}
for (TransactionPermission p : TransactionPermission.values()) {
if (p == TransactionPermission.DIRECT_OPERATION) {
assertTrue(decodePrivileges.getTransactionPrivilege().isEnable(p));
} else {
assertFalse(decodePrivileges.getTransactionPrivilege().isEnable(p));
}
}
}
// 只定义账本权限的情形;
{
Privileges privileges = Privileges.configure().enable(LedgerPermission.REGISTER_USER,
LedgerPermission.APPROVE_TX);

byte[] bytes = BinaryProtocol.encode(privileges, PrivilegeSet.class);

PrivilegeSet decodePrivileges = BinaryProtocol.decode(bytes);

assertNotNull(decodePrivileges.getLedgerPrivilege());
assertNotNull(decodePrivileges.getTransactionPrivilege());

for (LedgerPermission p : LedgerPermission.values()) {
if (p == LedgerPermission.REGISTER_USER || p == LedgerPermission.APPROVE_TX) {
assertTrue(decodePrivileges.getLedgerPrivilege().isEnable(p));
} else {
assertFalse(decodePrivileges.getLedgerPrivilege().isEnable(p));
}
}
for (TransactionPermission p : TransactionPermission.values()) {
assertFalse(decodePrivileges.getTransactionPrivilege().isEnable(p));
}
}
// 只定义交易权限的情形;
{
Privileges privileges = Privileges.configure().enable(TransactionPermission.CONTRACT_OPERATION);

byte[] bytes = BinaryProtocol.encode(privileges, PrivilegeSet.class);

PrivilegeSet decodePrivileges = BinaryProtocol.decode(bytes);

assertNotNull(decodePrivileges.getLedgerPrivilege());
assertNotNull(decodePrivileges.getTransactionPrivilege());
for (LedgerPermission p : LedgerPermission.values()) {
assertFalse(decodePrivileges.getLedgerPrivilege().isEnable(p));
}
for (TransactionPermission p : TransactionPermission.values()) {
if (p == TransactionPermission.CONTRACT_OPERATION) {
assertTrue(decodePrivileges.getTransactionPrivilege().isEnable(p));
} else {
assertFalse(decodePrivileges.getTransactionPrivilege().isEnable(p));
}
}
}
}

}

Loading…
Cancel
Save