public void Parse_Defaults() { const string acl = @"[{ ""subjects"": [ ], ""permissions"": { } }]"; IReadOnlyList <Acl> result = Acl.Parse(acl, LedgerPath.Parse("/root/path/"), new KeyEncoder(111)); Assert.Equal(1, result.Count); Assert.Equal("", result[0].RecordName.Pattern); Assert.Equal(PatternMatchingStrategy.Prefix, result[0].RecordName.MatchingStrategy); Assert.Equal(true, result[0].Recursive); Assert.Equal(0, result[0].Subjects.Count); Assert.Equal(Access.Unset, result[0].Permissions.AccountModify); Assert.Equal(Access.Unset, result[0].Permissions.AccountSpend); Assert.Equal(Access.Unset, result[0].Permissions.AccountModify); Assert.Equal(Access.Unset, result[0].Permissions.AccountCreate); Assert.Equal(Access.Unset, result[0].Permissions.DataModify); }
public void Parse_Success() { IReadOnlyList <Acl> result = Acl.Parse(GetValidAcl(), LedgerPath.Parse("/root/path/"), new KeyEncoder(111)); Assert.Equal(1, result.Count); Assert.Equal("/root/path/", result[0].Path.FullPath); Assert.Equal("name", result[0].RecordName.Pattern); Assert.Equal(PatternMatchingStrategy.Exact, result[0].RecordName.MatchingStrategy); Assert.Equal(true, result[0].Recursive); Assert.Equal(1, result[0].Subjects.Count); Assert.Equal(Access.Permit, result[0].Permissions.AccountModify); Assert.Equal(Access.Permit, result[0].Permissions.AccountSpend); Assert.Equal(Access.Permit, result[0].Permissions.AccountModify); Assert.Equal(Access.Permit, result[0].Permissions.AccountCreate); Assert.Equal(Access.Permit, result[0].Permissions.DataModify); }
private ByteString CreateMutation(ByteString @namespace) { Mutation mutation = new Mutation( @namespace, new Record[] { new Record( new AccountKey(LedgerPath.Parse("/account/1/"), LedgerPath.Parse("/a/")).Key.ToBinary(), new ByteString(BitConverter.GetBytes(100L).Reverse()), ByteString.Empty), new Record( new AccountKey(LedgerPath.Parse("/account/2/"), LedgerPath.Parse("/a/")).Key.ToBinary(), new ByteString(BitConverter.GetBytes(100L).Reverse()), ByteString.Empty), }, ByteString.Empty); return(new ByteString(MessageSerializer.SerializeMutation(mutation))); }
public async Task PostTransaction_MaxKeySize() { Dictionary <string, long> accounts = new Dictionary <string, long>(); TransactionValidator validator = CreateValidator(accounts); Mutation mutation = new Mutation( validNamespace, new Record[] { new Record( new AccountKey(LedgerPath.Parse("/"), LedgerPath.Parse($"/{new string('a', 512)}/")).Key.ToBinary(), new ByteString(BitConverter.GetBytes(100L).Reverse()), ByteString.Empty) }, ByteString.Empty); TransactionInvalidException exception = await Assert.ThrowsAsync <TransactionInvalidException>( () => validator.PostTransaction(new ByteString(MessageSerializer.SerializeMutation(mutation)), new SignatureEvidence[0])); Assert.Equal("InvalidMutation", exception.Reason); Assert.Equal(null, store.AddedTransactions); }
public void IsMatch_Success() { // Recursive ACL Acl acl = new Acl(new[] { subject }, path, true, new StringPattern("name", PatternMatchingStrategy.Exact), permissions); // Match (recursiveOnly = true) Assert.True(acl.IsMatch(evidence, path, true, "name")); // Match (recursiveOnly = false) Assert.True(acl.IsMatch(evidence, path, false, "name")); // Non-recursive ACL acl = new Acl(new[] { subject }, path, false, new StringPattern("name", PatternMatchingStrategy.Exact), permissions); // Match (recursiveOnly = false) Assert.True(acl.IsMatch(evidence, path, false, "name")); // Error: record non recursive (recursiveOnly = true) Assert.False(acl.IsMatch(evidence, path, true, "name")); // Error: path mismatch Assert.False(acl.IsMatch(evidence, LedgerPath.Parse("/"), false, "name")); // Error: name mismatch Assert.False(acl.IsMatch(evidence, path, false, "n")); // Error: identity mismatch Assert.False(acl.IsMatch(new[] { new SignatureEvidence(ByteString.Parse("ab"), ByteString.Empty) }, path, false, "name")); }
public async Task Validate_Inheritance() { TestPermissionsProvider firstValidator = new TestPermissionsProvider( new string[0], new Dictionary <string, PermissionSet>() { ["/"] = PermissionSet.AllowAll, ["/a/"] = PermissionSet.AllowAll }); TestPermissionsProvider secondValidator = new TestPermissionsProvider( new string[0], new Dictionary <string, PermissionSet>() { ["/"] = PermissionSet.DenyAll, ["/a/"] = PermissionSet.Unset }); // Level 1: / // Allow + Deny = Deny // Level 2: /a/ // Allow + Unset = Allow // Result: Allow PermissionBasedValidator validator = new PermissionBasedValidator(new[] { firstValidator, secondValidator }); ParsedMutation mutation = new ParsedMutation( new AccountStatus[0], new[] { new KeyValuePair <RecordKey, ByteString>(new RecordKey(RecordType.Data, LedgerPath.Parse("/a/"), "a"), ByteString.Parse("aabb")) }); await validator.Validate(mutation, new SignatureEvidence[0], new Dictionary <AccountKey, AccountStatus>()); }
public async Task Validate_DataMutationError() { PermissionBasedValidator validator = CreateValidator( new string[0], new Dictionary <string, PermissionSet>() { ["/"] = PermissionSet.Unset, ["/a/"] = new PermissionSet(Access.Permit, Access.Permit, Access.Permit, Access.Deny) }); ParsedMutation mutation = new ParsedMutation( new AccountStatus[0], new[] { new KeyValuePair <RecordKey, ByteString>(new RecordKey(RecordType.Data, LedgerPath.Parse("/a/"), "a"), ByteString.Parse("aabb")) }); TransactionInvalidException exception = await Assert.ThrowsAsync <TransactionInvalidException>(() => validator.Validate(mutation, new SignatureEvidence[0], new Dictionary <AccountKey, AccountStatus>())); Assert.Equal("CannotModifyData", exception.Reason); }
public async Task Validate_DataMutationSuccess() { PermissionBasedValidator validator = CreateValidator( new string[0], new Dictionary <string, PermissionSet>() { ["/"] = PermissionSet.Unset, ["/a/"] = new PermissionSet(Access.Deny, Access.Deny, Access.Deny, Access.Deny, Access.Permit) }); Dictionary <AccountKey, AccountStatus> accounts = new Dictionary <AccountKey, AccountStatus>(); ParsedMutation mutation = new ParsedMutation( new AccountStatus[0], new[] { new KeyValuePair <RecordKey, ByteString>(new RecordKey(RecordType.Data, LedgerPath.Parse("/a/"), "a"), ByteString.Parse("aabb")) }); await validator.Validate(mutation, new SignatureEvidence[0], accounts); }
public void AccountKey_ArgumentNullException() { ArgumentNullException exception; exception = Assert.Throws <ArgumentNullException>(() => new AccountKey(null, LedgerPath.Parse("/asset/"))); Assert.Equal("account", exception.ParamName); exception = Assert.Throws <ArgumentNullException>(() => new AccountKey(LedgerPath.Parse("/path/"), null)); Assert.Equal("asset", exception.ParamName); }
public static IMutationValidator CreateRulesValidator(IServiceProvider serviceProvider) { IConfiguration configuration = serviceProvider.GetService <IConfiguration>().GetSection("validator_mode"); ILogger logger = serviceProvider.GetService <ILogger>(); string rootUrl = configuration["root_url"]; if (rootUrl != null) { if (!Uri.IsWellFormedUriString(rootUrl, UriKind.Absolute)) { string errorMessage = $"The server root URL is not a valid URL: '{rootUrl}'. Please make sure it is configured correctly."; throw new InvalidOperationException(errorMessage); } logger.LogInformation("Current mode: Validator mode"); logger.LogInformation($"Namespace: {rootUrl}"); IConfiguration validator = configuration.GetSection("validator"); switch (validator["type"]) { case "PermissionBased": byte versionByte = byte.Parse(validator["version_byte"]); KeyEncoder keyEncoder = new KeyEncoder(versionByte); P2pkhSubject[] adminAddresses = validator .GetSection("admin_addresses") .GetChildren() .Select(key => key.Value) .Select(address => new P2pkhSubject(new[] { address }, 1, keyEncoder)) .ToArray(); List <Acl> pathPermissions = new List <Acl>() { // Admins have full rights new Acl(adminAddresses, LedgerPath.Parse("/"), true, StringPattern.MatchAll, PermissionSet.AllowAll) }; foreach (IConfigurationSection section in validator.GetSection("issuers").GetChildren()) { LedgerPath assetPath = LedgerPath.Parse(section["path"]); P2pkhSubject[] addresses = section .GetSection("addresses") .GetChildren() .Select(child => child.Value) .Select(address => new P2pkhSubject(new[] { address }, 1, keyEncoder)) .ToArray(); pathPermissions.Add(new Acl( addresses, assetPath, true, StringPattern.MatchAll, 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(accountNegative: Access.Permit))); } List <IPermissionsProvider> permissionProviders = new List <IPermissionsProvider>(); if (bool.Parse(validator["allow_third_party_assets"])) { permissionProviders.Add(new P2pkhIssuanceImplicitLayout(keyEncoder)); } if (bool.Parse(validator["allow_p2pkh_accounts"])) { permissionProviders.Add(new P2pkhImplicitLayout(keyEncoder)); } permissionProviders.Add(new StaticPermissionLayout(pathPermissions)); permissionProviders.Add(new DynamicPermissionLayout(serviceProvider.GetRequiredService <IStorageEngine>(), keyEncoder)); return(new PermissionBasedValidator(permissionProviders)); case "Disabled": return(ActivatorUtilities.CreateInstance <NullValidator>(serviceProvider, true)); default: return(null); } } else { logger.LogInformation("Transaction validation mode disabled (Slave mode)"); return(null); } }