Skip to content

Commit

Permalink
Lock down the default permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
Flavien committed Aug 19, 2015
1 parent dbdd633 commit 707412d
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 22 deletions.
6 changes: 3 additions & 3 deletions src/OpenChain.Ledger/Validation/Acl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace OpenChain.Ledger.Validation
public class Acl
{
public Acl(
IEnumerable<P2pkhSubject> subjects,
IEnumerable<IPermissionSubject> subjects,
LedgerPath path,
bool recursive,
StringPattern recordName,
Expand All @@ -22,7 +22,7 @@ public Acl(
this.Permissions = permissions;
}

public IReadOnlyList<P2pkhSubject> Subjects { get; }
public IReadOnlyList<IPermissionSubject> Subjects { get; }

public LedgerPath Path { get; }

Expand Down Expand Up @@ -58,7 +58,7 @@ private static Access Parse(JToken value)

public bool IsMatch(IReadOnlyList<SignatureEvidence> authentication, LedgerPath path, bool recursiveOnly, string recordName)
{
return Path.IsParentOf(path)
return Path.FullPath == path.FullPath
&& (Path.Segments.Count == path.Segments.Count || Recursive)
&& (!recursiveOnly || Recursive)
&& RecordName.IsMatch(recordName)
Expand Down
5 changes: 2 additions & 3 deletions src/OpenChain.Ledger/Validation/DefaultPermissionLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public class DefaultPermissionLayout : IPermissionsProvider
private readonly KeyEncoder keyEncoder;
private readonly LedgerPath thirdPartyAssetPath = LedgerPath.Parse("/asset/p2pkh/");
private readonly LedgerPath p2pkhAccountPath = LedgerPath.Parse("/p2pkh/");
private readonly string AclDataRecordName = "acl";

public DefaultPermissionLayout(bool allowThirdPartyAssets, KeyEncoder keyEncoder)
{
Expand Down Expand Up @@ -47,7 +46,7 @@ public Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence> authe
&& path.Segments.Count == p2pkhAccountPath.Segments.Count + 1
&& keyEncoder.IsP2pkh(path.Segments[path.Segments.Count - 1]))
{
Access ownAccount = identities.Contains(path.Segments[path.Segments.Count - 1]) && recordName != AclDataRecordName
Access ownAccount = identities.Contains(path.Segments[path.Segments.Count - 1]) && recordName != DynamicPermissionLayout.AclResourceName
? Access.Permit : Access.Unset;

return Task.FromResult(new PermissionSet(
Expand All @@ -62,7 +61,7 @@ public Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence> authe
&& path.Segments.Count == thirdPartyAssetPath.Segments.Count + 1
&& keyEncoder.IsP2pkh(path.Segments[path.Segments.Count - 1]))
{
Access ownAccount = identities.Contains(path.Segments[path.Segments.Count - 1]) && recordName != AclDataRecordName
Access ownAccount = identities.Contains(path.Segments[path.Segments.Count - 1]) && recordName != DynamicPermissionLayout.AclResourceName
? Access.Permit : Access.Unset;

return Task.FromResult(new PermissionSet(
Expand Down
4 changes: 3 additions & 1 deletion src/OpenChain.Ledger/Validation/DynamicPermissionLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class DynamicPermissionLayout : IPermissionsProvider
private readonly ITransactionStore store;
private readonly KeyEncoder keyEncoder;

public static string AclResourceName { get; } = "acl";

public DynamicPermissionLayout(ITransactionStore store, KeyEncoder keyEncoder)
{
this.store = store;
Expand All @@ -19,7 +21,7 @@ public async Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence>
{
PermissionSet currentPermissions = PermissionSet.DenyAll;

Record record = await this.store.GetRecord(new RecordKey(RecordType.Data, path, "acl"));
Record record = await this.store.GetRecord(new RecordKey(RecordType.Data, path, AclResourceName));

IReadOnlyList<Acl> permissions = Acl.Parse(Encoding.UTF8.GetString(record.Value.ToByteArray()), keyEncoder);

Expand Down
14 changes: 14 additions & 0 deletions src/OpenChain.Ledger/Validation/EveryoneSubject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;

namespace OpenChain.Ledger.Validation
{
public class EveryoneSubject : IPermissionSubject
{
public static EveryoneSubject Instance { get; } = new EveryoneSubject();

public bool IsMatch(IReadOnlyList<SignatureEvidence> authentication)
{
return true;
}
}
}
9 changes: 9 additions & 0 deletions src/OpenChain.Ledger/Validation/IPermissionSubject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace OpenChain.Ledger.Validation
{
public interface IPermissionSubject
{
bool IsMatch(IReadOnlyList<SignatureEvidence> authentication);
}
}
7 changes: 4 additions & 3 deletions src/OpenChain.Ledger/Validation/OpenLoopValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ private async Task<PermissionSet> GetPermissions(IReadOnlyList<SignatureEvidence
{
PermissionSet accumulativePermissions = PermissionSet.DenyAll;

for (int i = 0; i < path.Segments.Count; i++)
for (int i = 0; i <= path.Segments.Count; i++)
{
bool recursiveOnly = i != path.Segments.Count - 1;
PermissionSet[] permissions = await Task.WhenAll(this.permissions.Select(item => item.GetPermissions(signedAddresses, path, recursiveOnly, recordName)));
bool recursiveOnly = i != path.Segments.Count;
LedgerPath currentPath = LedgerPath.FromSegments(path.Segments.Take(i).ToArray());
PermissionSet[] permissions = await Task.WhenAll(this.permissions.Select(item => item.GetPermissions(signedAddresses, currentPath, recursiveOnly, recordName)));

PermissionSet currentLevelPermissions = permissions
.Aggregate(PermissionSet.Unset, (previous, current) => previous.Add(current));
Expand Down
2 changes: 1 addition & 1 deletion src/OpenChain.Ledger/Validation/P2pkhSubject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace OpenChain.Ledger.Validation
{
public class P2pkhSubject
public class P2pkhSubject : IPermissionSubject
{
private readonly KeyEncoder keyEncoder;

Expand Down
19 changes: 17 additions & 2 deletions src/OpenChain.Server/Models/ConfigurationParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,28 @@ public static IMutationValidator CreateRulesValidator(IServiceProvider servicePr
assetPath,
true,
StringPattern.MatchAll,
new PermissionSet(Access.Deny, Access.Permit, Access.Deny, Access.Permit)));
new PermissionSet(accountSpend: Access.Permit, dataModify: Access.Permit)));

pathPermissions.Add(new Acl(
addresses,
assetPath,
true,
new StringPattern(DynamicPermissionLayout.AclResourceName, PatternMatchingStrategy.Exact),
new PermissionSet(dataModify: Access.Deny)));

pathPermissions.Add(new Acl(
new[] { EveryoneSubject.Instance },
assetPath,
true,
new StringPattern(assetPath.FullPath, PatternMatchingStrategy.Prefix),
new PermissionSet(accountModify: Access.Permit)));

pathPermissions.Add(new Acl(
addresses,
LedgerPath.Parse("/"),
true,
new StringPattern(assetPath.FullPath, PatternMatchingStrategy.Prefix),
new PermissionSet(Access.Permit, Access.Deny, Access.Deny, Access.Deny)));
new PermissionSet(accountNegative: Access.Permit)));
}

bool allowThirdPartyAssets = bool.Parse(validator["allow_third_party_assets"]);
Expand Down
6 changes: 6 additions & 0 deletions src/OpenChain.Server/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
"addresses": [
"mtYWSapHLBioZJfXXnQqw45yCuEi37Tkwn"
]
},
{
"path": "/asset/test/",
"addresses": [
"mtPmvh5Vk5CGmezjwVfUtRMALTeykHpBwg"
]
}
],
"version_byte": 111
Expand Down
18 changes: 9 additions & 9 deletions test/OpenChain.Ledger.Tests/OpenLoopValidatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,43 +39,43 @@ public async Task Validate_AccountMutation()
{
// Able to spend existing funds as the issuer
await TestAccountChange(
accountPermissions: new PermissionSet(Access.Permitted, Access.Denied, Access.Permitted, Access.Denied),
accountPermissions: new PermissionSet(Access.Permit, Access.Deny, Access.Permit, Access.Deny),
previousBalance: 150,
newBalance: 100);

// Able to spend non-existing funds as the issuer
await TestAccountChange(
accountPermissions: new PermissionSet(Access.Permitted, Access.Denied, Access.Permitted, Access.Denied),
accountPermissions: new PermissionSet(Access.Permit, Access.Deny, Access.Permit, Access.Deny),
previousBalance: 100,
newBalance: -50);

// Able to spend funds as the owner
await TestAccountChange(
accountPermissions: new PermissionSet(Access.Denied, Access.Permitted, Access.Permitted, Access.Denied),
accountPermissions: new PermissionSet(Access.Deny, Access.Permit, Access.Permit, Access.Deny),
previousBalance: 100,
newBalance: 50);

// Able to receive funds
await TestAccountChange(
accountPermissions: new PermissionSet(Access.Denied, Access.Denied, Access.Permitted, Access.Denied),
accountPermissions: new PermissionSet(Access.Deny, Access.Deny, Access.Permit, Access.Deny),
previousBalance: 50,
newBalance: 100);

// Missing the affect balance permission
await Assert.ThrowsAsync<TransactionInvalidException>(() => TestAccountChange(
accountPermissions: new PermissionSet(Access.Permitted, Access.Permitted, Access.Denied, Access.Permitted),
accountPermissions: new PermissionSet(Access.Permit, Access.Permit, Access.Deny, Access.Permit),
previousBalance: 100,
newBalance: 150));

// Missing the permissions to spend from the account
await Assert.ThrowsAsync<TransactionInvalidException>(() => TestAccountChange(
accountPermissions: new PermissionSet(Access.Denied, Access.Denied, Access.Permitted, Access.Permitted),
accountPermissions: new PermissionSet(Access.Deny, Access.Deny, Access.Permit, Access.Permit),
previousBalance: 150,
newBalance: 100));

// Not able to spend more that the funds on the account
await Assert.ThrowsAsync<TransactionInvalidException>(() => TestAccountChange(
accountPermissions: new PermissionSet(Access.Denied, Access.Permitted, Access.Permitted, Access.Permitted),
accountPermissions: new PermissionSet(Access.Deny, Access.Permit, Access.Permit, Access.Permit),
previousBalance: 100,
newBalance: -50));
}
Expand All @@ -87,7 +87,7 @@ public async Task Validate_DataMutationSuccess()
new string[0],
new Dictionary<string, PermissionSet>()
{
["/a/"] = new PermissionSet(Access.Denied, Access.Denied, Access.Denied, Access.Permitted)
["/a/"] = new PermissionSet(Access.Deny, Access.Deny, Access.Deny, Access.Permit)
});

Dictionary<AccountKey, AccountStatus> accounts = new Dictionary<AccountKey, AccountStatus>();
Expand All @@ -106,7 +106,7 @@ public async Task Validate_DataMutationError()
new string[0],
new Dictionary<string, PermissionSet>()
{
["/a/"] = new PermissionSet(Access.Permitted, Access.Permitted, Access.Permitted, Access.Denied)
["/a/"] = new PermissionSet(Access.Permit, Access.Permit, Access.Permit, Access.Deny)
});

Dictionary<AccountKey, AccountStatus> accounts = new Dictionary<AccountKey, AccountStatus>();
Expand Down

0 comments on commit 707412d

Please sign in to comment.