@@ -56,8 +56,14 @@ public interface DataCodes { | |||||
public static final int TX_OP_RESULT = 0x360; | public static final int TX_OP_RESULT = 0x360; | ||||
// enum types of permissions; | // enum types of permissions; | ||||
public static final int ENUM_TX_PERMISSIONS = 0x401; | |||||
public static final int ENUM_LEDGER_PERMISSIONS = 0x402; | |||||
public static final int ENUM_TX_PERMISSION = 0x401; | |||||
public static final int ENUM_LEDGER_PERMISSION = 0x402; | |||||
public static final int ENUM_MULTI_ROLES_POLICY = 0x403; | |||||
public static final int ROLE_PRIVILEGE = 0x410; | |||||
public static final int ROLE_SET = 0x411; | |||||
// contract types of metadata; | // contract types of metadata; | ||||
public static final int METADATA = 0x600; | public static final int METADATA = 0x600; | ||||
@@ -12,52 +12,47 @@ import com.jd.blockchain.utils.io.BytesSerializable; | |||||
*/ | */ | ||||
public abstract class AbstractPrivilege<E extends Enum<?>> implements Privilege<E>, BytesSerializable { | public abstract class AbstractPrivilege<E extends Enum<?>> implements Privilege<E>, BytesSerializable { | ||||
private BitSet permissions; | |||||
private BitSet permissionBits; | |||||
public AbstractPrivilege() { | |||||
permissionBits = new BitSet(); | |||||
} | |||||
public AbstractPrivilege(byte[] codeBytes) { | public AbstractPrivilege(byte[] codeBytes) { | ||||
permissions = BitSet.valueOf(codeBytes); | |||||
permissionBits = BitSet.valueOf(codeBytes); | |||||
} | } | ||||
public boolean isEnable(E permission) { | public boolean isEnable(E permission) { | ||||
return permissions.get(getCodeIndex(permission)); | |||||
return permissionBits.get(getCodeIndex(permission)); | |||||
} | } | ||||
public void enable(E permission) { | public void enable(E permission) { | ||||
permissions.set(getCodeIndex(permission)); | |||||
permissionBits.set(getCodeIndex(permission)); | |||||
} | } | ||||
public void disable(E permission) { | public void disable(E permission) { | ||||
permissions.clear(getCodeIndex(permission)); | |||||
permissionBits.clear(getCodeIndex(permission)); | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
public void enable(E... permissions) { | |||||
for (E p : permissions) { | |||||
permissionBits.set(getCodeIndex(p)); | |||||
} | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
public void disable(E... permissions) { | |||||
for (E p : permissions) { | |||||
permissionBits.clear(getCodeIndex(p)); | |||||
} | |||||
} | } | ||||
// private int getCodeIndex(E permission) { | |||||
// return permission.CODE & 0xFF; | |||||
// } | |||||
protected abstract int getCodeIndex(E permission); | protected abstract int getCodeIndex(E permission); | ||||
@Override | @Override | ||||
public byte[] toBytes() { | public byte[] toBytes() { | ||||
return permissions.toByteArray(); | |||||
} | |||||
// public boolean[] getPermissionStates() { | |||||
// LedgerPermission[] PMs = LedgerPermission.values(); | |||||
// | |||||
// LedgerPermission maxPermission = Arrays.stream(PMs).max(new Comparator<LedgerPermission>() { | |||||
// @Override | |||||
// public int compare(LedgerPermission o1, LedgerPermission o2) { | |||||
// return getCodeIndex(o1) - getCodeIndex(o2); | |||||
// } | |||||
// }).get(); | |||||
// | |||||
// boolean[] states = new boolean[getCodeIndex(maxPermission) + 1]; | |||||
// int idx = -1; | |||||
// for (LedgerPermission pm : PMs) { | |||||
// idx = getCodeIndex(pm); | |||||
// states[idx] = permissions.get(idx); | |||||
// } | |||||
// | |||||
// return states; | |||||
// } | |||||
return permissionBits.toByteArray(); | |||||
} | |||||
} | } |
@@ -11,7 +11,7 @@ import com.jd.blockchain.consts.DataCodes; | |||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
@EnumContract(code = DataCodes.ENUM_LEDGER_PERMISSIONS) | |||||
@EnumContract(code = DataCodes.ENUM_LEDGER_PERMISSION) | |||||
public enum LedgerPermission { | public enum LedgerPermission { | ||||
/** | /** | ||||
@@ -8,6 +8,9 @@ package com.jd.blockchain.ledger.core; | |||||
*/ | */ | ||||
public class LedgerPrivilege extends AbstractPrivilege<LedgerPermission> { | public class LedgerPrivilege extends AbstractPrivilege<LedgerPermission> { | ||||
public LedgerPrivilege() { | |||||
} | |||||
public LedgerPrivilege(byte[] codeBytes) { | public LedgerPrivilege(byte[] codeBytes) { | ||||
super(codeBytes); | super(codeBytes); | ||||
} | } | ||||
@@ -22,11 +22,11 @@ public class LedgerSecurityManager { | |||||
throw new IllegalStateException("Not implemented!"); | throw new IllegalStateException("Not implemented!"); | ||||
} | } | ||||
public Role setRole(String role, LedgerPrivilege privilege) { | |||||
public RolePrivilegeAuthorization setRole(String role, LedgerPrivilege privilege) { | |||||
throw new IllegalStateException("Not implemented!"); | throw new IllegalStateException("Not implemented!"); | ||||
} | } | ||||
public Role getRole(String role) { | |||||
public RolePrivilegeAuthorization getRole(String role) { | |||||
throw new IllegalStateException("Not implemented!"); | throw new IllegalStateException("Not implemented!"); | ||||
} | } | ||||
@@ -149,6 +149,22 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
} | } | ||||
return values; | return values; | ||||
} | } | ||||
public VersioningKVEntry[] getLatestDataEntries(int fromIndex, int count) { | |||||
if (count > LedgerConsts.MAX_LIST_COUNT) { | |||||
throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | |||||
} | |||||
if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { | |||||
throw new IllegalArgumentException("Index out of bound!"); | |||||
} | |||||
VersioningKVEntry[] values = new VersioningKVEntry[count]; | |||||
for (int i = 0; i < count; i++) { | |||||
MerkleDataNode dataNode = merkleTree.getData(fromIndex + i); | |||||
Bytes dataKey = encodeDataKey(dataNode.getKey()); | |||||
values[i] = valueStorage.getEntry(dataKey, dataNode.getVersion()); | |||||
} | |||||
return values; | |||||
} | |||||
/** | /** | ||||
* get the data at the specific index; | * get the data at the specific index; | ||||
@@ -404,6 +420,11 @@ public class MerkleDataSet implements Transactional, MerkleProvable { | |||||
return getDataEntry(Bytes.fromString(key)); | return getDataEntry(Bytes.fromString(key)); | ||||
} | } | ||||
/** | |||||
* | |||||
* @param key | |||||
* @return Null if the key doesn't exist! | |||||
*/ | |||||
public VersioningKVEntry getDataEntry(Bytes key) { | public VersioningKVEntry getDataEntry(Bytes key) { | ||||
long latestVersion = getMerkleVersion(key); | long latestVersion = getMerkleVersion(key); | ||||
if (latestVersion < 0) { | if (latestVersion < 0) { | ||||
@@ -1,27 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
public class Role { | |||||
private String name; | |||||
private long version; | |||||
private LedgerPrivilege privilege; | |||||
public String getName() { | |||||
return name; | |||||
} | |||||
public long getVersion() { | |||||
return version; | |||||
} | |||||
public LedgerPrivilege getPrivilege() { | |||||
return privilege; | |||||
} | |||||
} |
@@ -0,0 +1,175 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.ledger.LedgerException; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.Transactional; | |||||
public class RoleDataSet implements Transactional, MerkleProvable { | |||||
/** | |||||
* 角色名称的最大 Unicode 字符数; | |||||
*/ | |||||
public static final int MAX_ROLE_NAME_LENGTH = 20; | |||||
private MerkleDataSet dataset; | |||||
public RoleDataSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exPolicyStorage, | |||||
VersioningKVStorage verStorage) { | |||||
dataset = new MerkleDataSet(cryptoSetting, prefix, exPolicyStorage, verStorage); | |||||
} | |||||
public RoleDataSet(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, | |||||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { | |||||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); | |||||
} | |||||
@Override | |||||
public HashDigest getRootHash() { | |||||
return dataset.getRootHash(); | |||||
} | |||||
@Override | |||||
public MerkleProof getProof(Bytes key) { | |||||
return dataset.getProof(key); | |||||
} | |||||
@Override | |||||
public boolean isUpdated() { | |||||
return dataset.isUpdated(); | |||||
} | |||||
@Override | |||||
public void commit() { | |||||
dataset.commit(); | |||||
} | |||||
@Override | |||||
public void cancel() { | |||||
dataset.cancel(); | |||||
} | |||||
public long getRoleCount() { | |||||
return dataset.getDataCount(); | |||||
} | |||||
/** | |||||
* 加入新的角色授权; <br> | |||||
* | |||||
* 如果指定的角色已经存在,则引发 {@link LedgerException} 异常; | |||||
* | |||||
* @param roleName 角色名称;不能超过 {@link #MAX_ROLE_NAME_LENGTH} 个 Unicode 字符; | |||||
* @param ledgerPrivilege | |||||
* @param txPrivilege | |||||
*/ | |||||
public void addRoleAuthorization(String roleName, LedgerPrivilege ledgerPrivilege, | |||||
TransactionPrivilege txPrivilege) { | |||||
RolePrivilegeAuthorization roleAuth = new RolePrivilegeAuthorization(roleName, -1, ledgerPrivilege, txPrivilege); | |||||
long nv = innerSetRoleAuthorization(roleAuth); | |||||
if (nv < 0) { | |||||
throw new LedgerException("Role[" + roleName + "] already exist!"); | |||||
} | |||||
} | |||||
/** | |||||
* 设置角色授权; <br> | |||||
* 如果版本校验不匹配,则返回 -1; | |||||
* | |||||
* @param roleAuth | |||||
* @return | |||||
*/ | |||||
public long innerSetRoleAuthorization(RolePrivilegeAuthorization roleAuth) { | |||||
if (roleAuth.getRoleName().length() > MAX_ROLE_NAME_LENGTH) { | |||||
throw new LedgerException("Too long role name!"); | |||||
} | |||||
Bytes key = encodeKey(roleAuth.getRoleName()); | |||||
byte[] privilegeBytes = BinaryProtocol.encode(roleAuth, RolePrivilege.class); | |||||
return dataset.setValue(key, privilegeBytes, roleAuth.getVersion()); | |||||
} | |||||
/** | |||||
* 更新角色授权; <br> | |||||
* 如果指定的角色不存在,或者版本不匹配,则引发 {@link LedgerException} 异常; | |||||
* | |||||
* @param participant | |||||
*/ | |||||
public void updateRoleAuthorization(RolePrivilegeAuthorization roleAuth) { | |||||
long nv = innerSetRoleAuthorization(roleAuth); | |||||
if (nv < 0) { | |||||
throw new LedgerException("Update to RoleAuthorization[" + roleAuth.getRoleName() | |||||
+ "] failed due to wrong version[" + roleAuth.getVersion() + "] !"); | |||||
} | |||||
} | |||||
/** | |||||
* 授权角色指定的权限; <br> | |||||
* 如果角色不存在,则返回 -1; | |||||
* | |||||
* @param participant | |||||
*/ | |||||
public long authorizePermissions(String roleName, LedgerPermission... permissions) { | |||||
RolePrivilegeAuthorization roleAuth = getRoleAuthorization(roleName); | |||||
if (roleAuth == null) { | |||||
return -1; | |||||
} | |||||
roleAuth.getLedgerPrivilege().enable(permissions); | |||||
return innerSetRoleAuthorization(roleAuth); | |||||
} | |||||
/** | |||||
* 授权角色指定的权限; <br> | |||||
* 如果角色不存在,则返回 -1; | |||||
* | |||||
* @param participant | |||||
*/ | |||||
public long authorizePermissions(String roleName, TransactionPermission... permissions) { | |||||
RolePrivilegeAuthorization roleAuth = getRoleAuthorization(roleName); | |||||
if (roleAuth == null) { | |||||
return -1; | |||||
} | |||||
roleAuth.getTransactionPrivilege().enable(permissions); | |||||
return innerSetRoleAuthorization(roleAuth); | |||||
} | |||||
private Bytes encodeKey(String address) { | |||||
// return id + ""; | |||||
return Bytes.fromString(address); | |||||
} | |||||
/** | |||||
* 查询角色授权; | |||||
* | |||||
* <br> | |||||
* 如果不存在,则返回 null; | |||||
* | |||||
* @param address | |||||
* @return | |||||
*/ | |||||
public RolePrivilegeAuthorization getRoleAuthorization(String roleName) { | |||||
// 只返回最新版本; | |||||
Bytes key = encodeKey(roleName); | |||||
VersioningKVEntry kv = dataset.getDataEntry(key); | |||||
if (kv == null) { | |||||
return null; | |||||
} | |||||
RolePrivilege privilege = BinaryProtocol.decode(kv.getValue()); | |||||
return new RolePrivilegeAuthorization(roleName, kv.getVersion(), privilege); | |||||
} | |||||
public RolePrivilegeAuthorization[] getRoleAuthorizations() { | |||||
VersioningKVEntry[] kvEntries = dataset.getLatestDataEntries(0, (int) dataset.getDataCount()); | |||||
RolePrivilegeAuthorization[] pns = new RolePrivilegeAuthorization[kvEntries.length]; | |||||
RolePrivilege privilege; | |||||
for (int i = 0; i < pns.length; i++) { | |||||
privilege = BinaryProtocol.decode(kvEntries[i].getValue()); | |||||
pns[i] = new RolePrivilegeAuthorization(kvEntries[i].getKey().toUTF8String(), kvEntries[i].getVersion(), privilege); | |||||
} | |||||
return pns; | |||||
} | |||||
} |
@@ -1,10 +1,9 @@ | |||||
package com.jd.blockchain.ledger.core; | package com.jd.blockchain.ledger.core; | ||||
import java.io.ByteArrayInputStream; | |||||
import java.io.ByteArrayOutputStream; | |||||
import com.jd.blockchain.utils.io.BytesEncoding; | |||||
import com.jd.blockchain.utils.io.BytesSerializable; | |||||
import com.jd.blockchain.binaryproto.DataContract; | |||||
import com.jd.blockchain.binaryproto.DataField; | |||||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.consts.DataCodes; | |||||
/** | /** | ||||
* 表示赋予角色的特权码; | * 表示赋予角色的特权码; | ||||
@@ -12,57 +11,13 @@ import com.jd.blockchain.utils.io.BytesSerializable; | |||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
public class RolePrivilege implements BytesSerializable { | |||||
// 权限码的数量;目前有2种:账本权限 + 交易权限; | |||||
private static final int SEGMENT_COUNT = 2; | |||||
private LedgerPrivilege ledgerPrivilege; | |||||
private TxPrivilege txPrivilege; | |||||
public Privilege<TxPermission> getTxPrivilege() { | |||||
return txPrivilege; | |||||
} | |||||
public Privilege<LedgerPermission> getLedgerPrivilege() { | |||||
return ledgerPrivilege; | |||||
} | |||||
public RolePrivilege(byte[] priviledgeCodes) { | |||||
byte[][] bytesSegments = decodeBytes(priviledgeCodes); | |||||
ledgerPrivilege = new LedgerPrivilege(bytesSegments[0]); | |||||
txPrivilege = new TxPrivilege(bytesSegments[1]); | |||||
} | |||||
private byte[] encodeBytes(byte[]... bytes) { | |||||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||||
// write one byte; | |||||
out.write(bytes.length); | |||||
for (int i = 0; i < bytes.length; i++) { | |||||
BytesEncoding.writeInTiny(bytes[i], out); | |||||
} | |||||
return out.toByteArray(); | |||||
} | |||||
@DataContract(code = DataCodes.ROLE_PRIVILEGE, name = "ROLE-PRIVILEGE") | |||||
public interface RolePrivilege { | |||||
private byte[][] decodeBytes(byte[] bytes) { | |||||
ByteArrayInputStream in = new ByteArrayInputStream(bytes); | |||||
// read one byte; | |||||
int len = in.read(); | |||||
if (len < 1 || len > SEGMENT_COUNT) { | |||||
throw new IllegalStateException("Decoded illegal privilege bytes!"); | |||||
} | |||||
byte[][] bytesSegments = new byte[len][]; | |||||
for (int i = 0; i < bytesSegments.length; i++) { | |||||
bytesSegments[i] = BytesEncoding.readInTiny(in); | |||||
} | |||||
return bytesSegments; | |||||
} | |||||
@DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||||
LedgerPrivilege getLedgerPrivilege(); | |||||
@Override | |||||
public byte[] toBytes() { | |||||
// 保持和解码时一致的顺序; | |||||
return encodeBytes(ledgerPrivilege.toBytes(), txPrivilege.toBytes()); | |||||
} | |||||
@DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||||
TransactionPrivilege getTransactionPrivilege(); | |||||
} | } |
@@ -0,0 +1,66 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
/** | |||||
* 对角色的授权; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
public class RolePrivilegeAuthorization implements RolePrivilege { | |||||
private String roleName; | |||||
private long version; | |||||
private LedgerPrivilege ledgerPrivilege; | |||||
private TransactionPrivilege txPrivilege; | |||||
public RolePrivilegeAuthorization(String roleName, long version) { | |||||
this.roleName = roleName; | |||||
this.version = version; | |||||
this.ledgerPrivilege = new LedgerPrivilege(); | |||||
this.txPrivilege = new TransactionPrivilege(); | |||||
} | |||||
public RolePrivilegeAuthorization(String roleName, long version, RolePrivilege privilege) { | |||||
this.roleName = roleName; | |||||
this.version = version; | |||||
this.ledgerPrivilege = privilege.getLedgerPrivilege(); | |||||
this.txPrivilege = privilege.getTransactionPrivilege(); | |||||
} | |||||
public RolePrivilegeAuthorization(String roleName, long version, LedgerPrivilege ledgerPrivilege, TransactionPrivilege txPrivilege) { | |||||
this.roleName = roleName; | |||||
this.version = version; | |||||
this.ledgerPrivilege = ledgerPrivilege; | |||||
this.txPrivilege = txPrivilege; | |||||
} | |||||
public String getRoleName() { | |||||
return roleName; | |||||
} | |||||
public long getVersion() { | |||||
return version; | |||||
} | |||||
@Override | |||||
public LedgerPrivilege getLedgerPrivilege() { | |||||
return ledgerPrivilege; | |||||
} | |||||
public void setLedgerPrivilege(LedgerPrivilege ledgerPrivilege) { | |||||
this.ledgerPrivilege = ledgerPrivilege; | |||||
} | |||||
@Override | |||||
public TransactionPrivilege getTransactionPrivilege() { | |||||
return txPrivilege; | |||||
} | |||||
public void setTransactionPrivilege(TransactionPrivilege txPrivilege) { | |||||
this.txPrivilege = txPrivilege; | |||||
} | |||||
} |
@@ -0,0 +1,23 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.binaryproto.DataContract; | |||||
import com.jd.blockchain.binaryproto.DataField; | |||||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.consts.DataCodes; | |||||
/** | |||||
* 角色集; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
@DataContract(code = DataCodes.ROLE_SET) | |||||
public interface RoleSet { | |||||
@DataField(order = 1, refEnum = true) | |||||
RolesPolicy getPolicy(); | |||||
@DataField(order = 2, primitiveType = PrimitiveType.TEXT, list = true) | |||||
String[] getRoles(); | |||||
} |
@@ -0,0 +1,40 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.binaryproto.EnumContract; | |||||
import com.jd.blockchain.binaryproto.EnumField; | |||||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||||
import com.jd.blockchain.consts.DataCodes; | |||||
/** | |||||
* 多角色策略;<br> | |||||
* | |||||
* 表示如何处理一个对象被赋予多个角色时的综合权限; | |||||
* | |||||
* @author huanghaiquan | |||||
* | |||||
*/ | |||||
@EnumContract(code = DataCodes.ENUM_MULTI_ROLES_POLICY, name = "USER-ROLE-POLICY") | |||||
public enum RolesPolicy { | |||||
/** | |||||
* 合并权限;<br> | |||||
* | |||||
* 综合权限是所有角色权限的并集,即任何一个角色的权限都被继承; | |||||
*/ | |||||
UNION((byte) 0), | |||||
/** | |||||
* 交叉权限;<br> | |||||
* | |||||
* 综合权限是所有角色权限的交集,即只有全部角色共同拥有的权限才会被继承; | |||||
*/ | |||||
INTERSECT((byte) 1); | |||||
@EnumField(type = PrimitiveType.INT8) | |||||
public final byte CODE; | |||||
private RolesPolicy(byte code) { | |||||
this.CODE = code; | |||||
} | |||||
} |
@@ -11,23 +11,23 @@ import com.jd.blockchain.consts.DataCodes; | |||||
* @author huanghaiquan | * @author huanghaiquan | ||||
* | * | ||||
*/ | */ | ||||
@EnumContract(code = DataCodes.ENUM_TX_PERMISSIONS) | |||||
public enum TxPermission { | |||||
@EnumContract(code = DataCodes.ENUM_TX_PERMISSION) | |||||
public enum TransactionPermission { | |||||
/** | /** | ||||
* 交易中包含指令操作; | * 交易中包含指令操作; | ||||
*/ | */ | ||||
COMMAND((byte) 0x01), | |||||
DIRECT_OPERATION((byte) 0x01), | |||||
/** | /** | ||||
* 交易中包含合约操作; | * 交易中包含合约操作; | ||||
*/ | */ | ||||
CONTRACT((byte) 0x02); | |||||
CONTRACT_OPERATION((byte) 0x02); | |||||
@EnumField(type = PrimitiveType.INT8) | @EnumField(type = PrimitiveType.INT8) | ||||
public final byte CODE; | public final byte CODE; | ||||
private TxPermission(byte code) { | |||||
private TransactionPermission(byte code) { | |||||
this.CODE = code; | this.CODE = code; | ||||
} | } | ||||
@@ -0,0 +1,17 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
public class TransactionPrivilege extends AbstractPrivilege<TransactionPermission> { | |||||
public TransactionPrivilege() { | |||||
} | |||||
public TransactionPrivilege(byte[] codeBytes) { | |||||
super(codeBytes); | |||||
} | |||||
@Override | |||||
protected int getCodeIndex(TransactionPermission permission) { | |||||
return permission.CODE & 0xFF; | |||||
} | |||||
} |
@@ -1,14 +0,0 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
public class TxPrivilege extends AbstractPrivilege<TxPermission> { | |||||
public TxPrivilege(byte[] codeBytes) { | |||||
super(codeBytes); | |||||
} | |||||
@Override | |||||
protected int getCodeIndex(TxPermission permission) { | |||||
return permission.CODE & 0xFF; | |||||
} | |||||
} |
@@ -0,0 +1,155 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.ledger.LedgerException; | |||||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||||
import com.jd.blockchain.storage.service.VersioningKVEntry; | |||||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.Transactional; | |||||
public class UserRoleDataSet implements Transactional, MerkleProvable { | |||||
/** | |||||
* 角色名称的最大 Unicode 字符数; | |||||
*/ | |||||
public static final int MAX_ROLE_NAME_LENGTH = 20; | |||||
private MerkleDataSet dataset; | |||||
public UserRoleDataSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exPolicyStorage, | |||||
VersioningKVStorage verStorage) { | |||||
dataset = new MerkleDataSet(cryptoSetting, prefix, exPolicyStorage, verStorage); | |||||
} | |||||
public UserRoleDataSet(HashDigest merkleRootHash, CryptoSetting cryptoSetting, String prefix, | |||||
ExPolicyKVStorage exPolicyStorage, VersioningKVStorage verStorage, boolean readonly) { | |||||
dataset = new MerkleDataSet(merkleRootHash, cryptoSetting, prefix, exPolicyStorage, verStorage, readonly); | |||||
} | |||||
@Override | |||||
public HashDigest getRootHash() { | |||||
return dataset.getRootHash(); | |||||
} | |||||
@Override | |||||
public MerkleProof getProof(Bytes key) { | |||||
return dataset.getProof(key); | |||||
} | |||||
@Override | |||||
public boolean isUpdated() { | |||||
return dataset.isUpdated(); | |||||
} | |||||
@Override | |||||
public void commit() { | |||||
dataset.commit(); | |||||
} | |||||
@Override | |||||
public void cancel() { | |||||
dataset.cancel(); | |||||
} | |||||
public long getRoleCount() { | |||||
return dataset.getDataCount(); | |||||
} | |||||
/** | |||||
* 加入新的用户角色授权; <br> | |||||
* | |||||
* 如果该用户的授权已经存在,则引发 {@link LedgerException} 异常; | |||||
* | |||||
* @param userAddress | |||||
* @param rolesPolicy | |||||
* @param roles | |||||
*/ | |||||
public void addUserRoles(Bytes userAddress, RolesPolicy rolesPolicy, String... roles) { | |||||
UserRolesAuthorization roleAuth = new UserRolesAuthorization(userAddress, -1, rolesPolicy); | |||||
roleAuth.addRoles(roles); | |||||
long nv = innerSetUserRolesAuthorization(roleAuth); | |||||
if (nv < 0) { | |||||
throw new LedgerException("Roles authorization of User[" + userAddress + "] already exists!"); | |||||
} | |||||
} | |||||
/** | |||||
* 设置用户角色授权; <br> | |||||
* 如果版本校验不匹配,则返回 -1; | |||||
* | |||||
* @param userRoles | |||||
* @return | |||||
*/ | |||||
public long innerSetUserRolesAuthorization(UserRolesAuthorization userRoles) { | |||||
byte[] rolesetBytes = BinaryProtocol.encode(userRoles, RoleSet.class); | |||||
return dataset.setValue(userRoles.getUserAddress(), rolesetBytes, userRoles.getVersion()); | |||||
} | |||||
/** | |||||
* 更新用户角色授权; <br> | |||||
* 如果指定用户的授权不存在,或者版本不匹配,则引发 {@link LedgerException} 异常; | |||||
* | |||||
* @param userRoles | |||||
*/ | |||||
public void updateUserRolesAuthorization(UserRolesAuthorization userRoles) { | |||||
long nv = innerSetUserRolesAuthorization(userRoles); | |||||
if (nv < 0) { | |||||
throw new LedgerException("Update to roles of user[" + userRoles.getUserAddress() | |||||
+ "] failed due to wrong version[" + userRoles.getVersion() + "] !"); | |||||
} | |||||
} | |||||
/** | |||||
* 设置用户的角色; <br> | |||||
* 如果用户的角色授权不存在,则创建新的授权; | |||||
* | |||||
* @param userAddress 用户; | |||||
* @param policy 角色策略; | |||||
* @param roles 角色列表; | |||||
* @return | |||||
*/ | |||||
public long setRoles(Bytes userAddress, RolesPolicy policy, String... roles) { | |||||
UserRolesAuthorization userRoles = getUserRolesAuthorization(userAddress); | |||||
if (userRoles == null) { | |||||
userRoles = new UserRolesAuthorization(userAddress, -1, policy); | |||||
} | |||||
userRoles.setPolicy(policy); | |||||
userRoles.setRoles(roles); | |||||
return innerSetUserRolesAuthorization(userRoles); | |||||
} | |||||
/** | |||||
* 查询角色授权; | |||||
* | |||||
* <br> | |||||
* 如果不存在,则返回 null; | |||||
* | |||||
* @param address | |||||
* @return | |||||
*/ | |||||
public UserRolesAuthorization getUserRolesAuthorization(Bytes userAddress) { | |||||
// 只返回最新版本; | |||||
VersioningKVEntry kv = dataset.getDataEntry(userAddress); | |||||
if (kv == null) { | |||||
return null; | |||||
} | |||||
RoleSet roleSet = BinaryProtocol.decode(kv.getValue()); | |||||
return new UserRolesAuthorization(userAddress, kv.getVersion(), roleSet); | |||||
} | |||||
public RolePrivilegeAuthorization[] getRoleAuthorizations() { | |||||
VersioningKVEntry[] kvEntries = dataset.getLatestDataEntries(0, (int) dataset.getDataCount()); | |||||
RolePrivilegeAuthorization[] pns = new RolePrivilegeAuthorization[kvEntries.length]; | |||||
RolePrivilege privilege; | |||||
for (int i = 0; i < pns.length; i++) { | |||||
privilege = BinaryProtocol.decode(kvEntries[i].getValue()); | |||||
pns[i] = new RolePrivilegeAuthorization(kvEntries[i].getKey().toUTF8String(), kvEntries[i].getVersion(), | |||||
privilege); | |||||
} | |||||
return pns; | |||||
} | |||||
} |
@@ -0,0 +1,84 @@ | |||||
package com.jd.blockchain.ledger.core; | |||||
import java.util.Set; | |||||
import java.util.TreeSet; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
public class UserRolesAuthorization implements RoleSet { | |||||
private Bytes userAddress; | |||||
private RolesPolicy policy; | |||||
private Set<String> roles; | |||||
private long version; | |||||
public UserRolesAuthorization(Bytes userAddress, long version, RolesPolicy policy) { | |||||
this.userAddress = userAddress; | |||||
this.version = version; | |||||
this.policy = policy; | |||||
this.roles = new TreeSet<String>(); | |||||
} | |||||
public UserRolesAuthorization(Bytes userAddress, long version, RoleSet roleSet) { | |||||
this.userAddress = userAddress; | |||||
this.version = version; | |||||
this.policy = roleSet.getPolicy(); | |||||
this.roles = initRoles(roleSet.getRoles()); | |||||
} | |||||
private Set<String> initRoles(String[] roles) { | |||||
TreeSet<String> roleset = new TreeSet<String>(); | |||||
if (roles != null) { | |||||
for (String r : roles) { | |||||
roleset.add(r); | |||||
} | |||||
} | |||||
return roleset; | |||||
} | |||||
public Bytes getUserAddress() { | |||||
return userAddress; | |||||
} | |||||
@Override | |||||
public RolesPolicy getPolicy() { | |||||
return policy; | |||||
} | |||||
public void setPolicy(RolesPolicy policy) { | |||||
this.policy = policy; | |||||
} | |||||
public int getRoleCount() { | |||||
return roles.size(); | |||||
} | |||||
@Override | |||||
public String[] getRoles() { | |||||
return roles.toArray(new String[roles.size()]); | |||||
} | |||||
public long getVersion() { | |||||
return version; | |||||
} | |||||
public void addRoles(String... roles) { | |||||
for (String r : roles) { | |||||
this.roles.add(r); | |||||
} | |||||
} | |||||
/** | |||||
* 设置角色集合;<br> | |||||
* 注意,这不是追加;现有的不在参数指定范围的角色将被移除; | |||||
* | |||||
* @param roles | |||||
*/ | |||||
public void setRoles(String[] roles) { | |||||
} | |||||
} |