Example #1
0
        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);
        }
Example #2
0
        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"));
        }
Example #6
0
        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>());
        }
Example #7
0
        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);
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
        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);
            }
        }