Skip to content

Commit

Permalink
OOB Query Permission Checks
Browse files Browse the repository at this point in the history
Signed-off-by: Egor Ivkov <e.o.ivkov@gmail.com>
  • Loading branch information
e-ivkov committed Jul 23, 2021
1 parent 89574e6 commit ce1edaf
Show file tree
Hide file tree
Showing 9 changed files with 462 additions and 89 deletions.
19 changes: 0 additions & 19 deletions iroha/src/smartcontracts/isi/asset.rs
Expand Up @@ -334,25 +334,6 @@ pub mod query {
}
}

impl<W: WorldTrait> Query<W> for FindAssetsByAccountIdAndAssetDefinitionId {
#[log]
fn execute(&self, wsv: &WorldStateView<W>) -> Result<Self::Output> {
let id = self
.account_id
.evaluate(wsv, &Context::default())
.wrap_err("Failed to get account id")?;
let asset_id = self
.asset_definition_id
.evaluate(wsv, &Context::default())
.wrap_err("Failed to get asset id")?;
Ok(wsv
.account_assets(&id)?
.into_iter()
.filter(|asset| asset.id.definition_id == asset_id)
.collect())
}
}

impl<W: WorldTrait> Query<W> for FindAssetsByDomainNameAndAssetDefinitionId {
#[log]
fn execute(&self, wsv: &WorldStateView<W>) -> Result<Self::Output> {
Expand Down
1 change: 0 additions & 1 deletion iroha/src/smartcontracts/isi/query.rs
Expand Up @@ -176,7 +176,6 @@ impl<W: WorldTrait> Query<W> for QueryBox {
FindAssetsByAccountId(query) => query.execute_into_value(wsv),
FindAssetsByAssetDefinitionId(query) => query.execute_into_value(wsv),
FindAssetsByDomainName(query) => query.execute_into_value(wsv),
FindAssetsByAccountIdAndAssetDefinitionId(query) => query.execute_into_value(wsv),
FindAssetsByDomainNameAndAssetDefinitionId(query) => query.execute_into_value(wsv),
FindAssetQuantityById(query) => query.execute_into_value(wsv),
FindAllDomains(query) => query.execute_into_value(wsv),
Expand Down
24 changes: 15 additions & 9 deletions iroha/test_network/src/lib.rs
Expand Up @@ -21,7 +21,7 @@ use iroha::{
kura::{Kura, KuraTrait},
prelude::*,
queue::{Queue, QueueTrait},
smartcontracts::permissions::IsInstructionAllowedBoxed,
smartcontracts::permissions::{IsInstructionAllowedBoxed, IsQueryAllowedBoxed},
sumeragi::{config::SumeragiConfiguration, Sumeragi, SumeragiTrait},
torii::config::ToriiConfiguration,
wsv::{World, WorldTrait},
Expand Down Expand Up @@ -396,7 +396,8 @@ where
pub async fn start_with_config_permissions(
&mut self,
configuration: Configuration,
permissions: impl Into<IsInstructionAllowedBoxed<W>> + Send + 'static,
instruction_validator: impl Into<IsInstructionAllowedBoxed<W>> + Send + 'static,
query_validator: impl Into<IsQueryAllowedBoxed<W>> + Send + 'static,
) {
let temp_dir = TempDir::new().expect("Failed to create temp dir.");
let mut configuration = self.get_config(configuration);
Expand All @@ -417,8 +418,8 @@ where
let _temp_dir = temp_dir;
let mut iroha = <Iroha<W, G, Q, S, K, B>>::with_broker(
&configuration,
permissions.into(),
AllowAll.into(),
instruction_validator.into(),
query_validator.into(),
broker,
)
.await
Expand All @@ -437,7 +438,7 @@ where

/// Starts peer with config
pub async fn start_with_config(&mut self, configuration: Configuration) {
self.start_with_config_permissions(configuration, AllowAll)
self.start_with_config_permissions(configuration, AllowAll, AllowAll)
.await;
}

Expand Down Expand Up @@ -484,21 +485,26 @@ where
/// Starts peer with default configuration.
/// Returns its info and client for connecting to it.
pub async fn start_test() -> (Self, Client) {
Self::start_test_with_permissions(AllowAll.into()).await
Self::start_test_with_permissions(AllowAll.into(), AllowAll.into()).await
}

/// Starts peer with default configuration and specified permissions.
/// Returns its info and client for connecting to it.
pub async fn start_test_with_permissions(
permissions: IsInstructionAllowedBoxed<W>,
instruction_validator: IsInstructionAllowedBoxed<W>,
query_validator: IsQueryAllowedBoxed<W>,
) -> (Self, Client) {
let mut configuration = Configuration::test();
let mut peer = Self::new().expect("Failed to create peer.");
configuration.sumeragi_configuration.trusted_peers.peers =
std::iter::once(peer.id.clone()).collect();
configuration.genesis_configuration.genesis_block_path = Some(GENESIS_PATH.to_owned());
peer.start_with_config_permissions(configuration.clone(), permissions)
.await;
peer.start_with_config_permissions(
configuration.clone(),
instruction_validator,
query_validator,
)
.await;
let client = Client::test(&peer.api_address);
time::sleep(Duration::from_millis(
configuration.sumeragi_configuration.pipeline_time_ms(),
Expand Down
9 changes: 3 additions & 6 deletions iroha_client/src/client.rs
Expand Up @@ -498,12 +498,9 @@ pub mod asset {
FindAssetsByAccountId::new(account_id)
}

/// Get query to get all assets by account id and definition id
pub fn by_account_id_and_definition_id(
account_id: impl Into<EvaluatesTo<AccountId>>,
asset_definition_id: impl Into<EvaluatesTo<AssetDefinitionId>>,
) -> FindAssetsByAccountIdAndAssetDefinitionId {
FindAssetsByAccountIdAndAssetDefinitionId::new(account_id, asset_definition_id)
/// Get query to get all assets by account id
pub fn by_id(asset_id: impl Into<EvaluatesTo<<Asset as Identifiable>::Id>>) -> FindAssetById {
FindAssetById::new(asset_id)
}
}

Expand Down
39 changes: 37 additions & 2 deletions iroha_client/tests/permissions.rs
Expand Up @@ -2,10 +2,10 @@

use std::thread;

use iroha::config::Configuration;
use iroha::{config::Configuration, prelude::AllowAll};
use iroha_client::client::{self, Client};
use iroha_data_model::prelude::*;
use iroha_permissions_validators::public_blockchain;
use iroha_permissions_validators::{private_blockchain, public_blockchain};
use test_network::{Peer as TestPeer, *};
use tokio::runtime::Runtime;

Expand All @@ -30,6 +30,7 @@ fn permissions_disallow_asset_transfer() {
let rt = Runtime::test();
let (_peer, mut iroha_client) = rt.block_on(<TestPeer>::start_test_with_permissions(
public_blockchain::default_permissions(),
AllowAll.into(),
));
let pipeline_time = Configuration::pipeline_time();

Expand Down Expand Up @@ -88,6 +89,7 @@ fn permissions_disallow_asset_burn() {
let rt = Runtime::test();
let (_not_drop, mut iroha_client) = rt.block_on(<TestPeer>::start_test_with_permissions(
public_blockchain::default_permissions(),
AllowAll.into(),
));
let pipeline_time = Configuration::pipeline_time();

Expand Down Expand Up @@ -145,3 +147,36 @@ fn permissions_disallow_asset_burn() {
let alice_assets = get_assets(&mut iroha_client, &alice_id);
assert_eq!(alice_assets, alice_start_assets);
}

#[test]
fn account_can_query_only_its_own_domain() {
let rt = Runtime::test();
let (_not_drop, mut iroha_client) = rt.block_on(<TestPeer>::start_test_with_permissions(
AllowAll.into(),
private_blockchain::query::OnlyAccountsDomain.into(),
));
let pipeline_time = Configuration::pipeline_time();

// Given
thread::sleep(pipeline_time * 2);

let domain_name = "wonderland";
let new_domain_name = "wonderland2";
let register_domain = RegisterBox::new(IdentifiableBox::from(Domain::new(new_domain_name)));

iroha_client
.submit(register_domain)
.expect("Failed to prepare state.");

thread::sleep(pipeline_time * 2);

// Alice can query the domain in which her account exists.
assert!(iroha_client
.request(client::domain::by_name(domain_name.to_owned()))
.is_ok());

// Alice can not query other domains.
assert!(iroha_client
.request(client::domain::by_name(new_domain_name.to_owned()))
.is_err());
}
3 changes: 2 additions & 1 deletion iroha_client_cli/src/main.rs
Expand Up @@ -521,8 +521,9 @@ mod asset {
fn run(self, cfg: &ClientConfiguration) -> Result<()> {
let Self { account, asset } = self;
let mut iroha_client = Client::new(cfg);
let asset_id = AssetId::new(asset, account);
let value = iroha_client
.request(asset::by_account_id_and_definition_id(account, asset))
.request(asset::by_id(asset_id))
.wrap_err("Failed to get asset.")?;
println!("Get Asset result: {:?}", value);
Ok(())
Expand Down
49 changes: 1 addition & 48 deletions iroha_data_model/src/query.rs
Expand Up @@ -61,8 +61,6 @@ pub enum QueryBox {
FindAssetsByAssetDefinitionId(FindAssetsByAssetDefinitionId),
/// `FindAssetsByDomainName` variant.
FindAssetsByDomainName(FindAssetsByDomainName),
/// `FindAssetsByAccountIdAndAssetDefinitionId` variant.
FindAssetsByAccountIdAndAssetDefinitionId(FindAssetsByAccountIdAndAssetDefinitionId),
/// `FindAssetsByDomainNameAndAssetDefinitionId` variant.
FindAssetsByDomainNameAndAssetDefinitionId(FindAssetsByDomainNameAndAssetDefinitionId),
/// `FindAssetQuantityById` variant.
Expand Down Expand Up @@ -681,35 +679,6 @@ pub mod asset {
type Output = Vec<Asset>;
}

// TODO: remove as it is the same as `FindAssetById`
/// `FindAssetsByAccountIdAndAssetDefinitionId` Iroha Query will get `AccountId` and
/// `AssetDefinitionId` as inputs and find all `Asset`s owned by the `Account`
/// with this `AssetDefinition` in Iroha Peer.
#[derive(
Clone,
Debug,
Io,
Serialize,
Deserialize,
Encode,
Decode,
PartialEq,
Eq,
PartialOrd,
Ord,
IntoSchema,
)]
pub struct FindAssetsByAccountIdAndAssetDefinitionId {
/// `AccountId` under which assets should be found.
pub account_id: EvaluatesTo<AccountId>,
/// `AssetDefinitionId` which assets should be found.
pub asset_definition_id: EvaluatesTo<AssetDefinitionId>,
}

impl QueryOutput for FindAssetsByAccountIdAndAssetDefinitionId {
type Output = Vec<Asset>;
}

/// `FindAssetsByDomainNameAndAssetDefinitionId` Iroha Query will get `Domain`'s name and
/// `AssetDefinitionId` as inputs and find all `Asset`s under the `Domain`
/// with this `AssetDefinition` in Iroha `Peer`.
Expand Down Expand Up @@ -846,21 +815,6 @@ pub mod asset {
}
}

impl FindAssetsByAccountIdAndAssetDefinitionId {
/// Default `FindAssetsByAccountIdAndAssetDefinitionId` constructor.
pub fn new(
account_id: impl Into<EvaluatesTo<AccountId>>,
asset_definition_id: impl Into<EvaluatesTo<AssetDefinitionId>>,
) -> Self {
let account_id = account_id.into();
let asset_definition_id = asset_definition_id.into();
FindAssetsByAccountIdAndAssetDefinitionId {
account_id,
asset_definition_id,
}
}
}

impl FindAssetsByDomainNameAndAssetDefinitionId {
/// Default `FindAssetsByDomainNameAndAssetDefinitionId` constructor
pub fn new(
Expand Down Expand Up @@ -897,8 +851,7 @@ pub mod asset {
pub mod prelude {
pub use super::{
FindAllAssets, FindAllAssetsDefinitions, FindAssetById, FindAssetKeyValueByIdAndKey,
FindAssetQuantityById, FindAssetsByAccountId,
FindAssetsByAccountIdAndAssetDefinitionId, FindAssetsByAssetDefinitionId,
FindAssetQuantityById, FindAssetsByAccountId, FindAssetsByAssetDefinitionId,
FindAssetsByDomainName, FindAssetsByDomainNameAndAssetDefinitionId, FindAssetsByName,
};
}
Expand Down
3 changes: 3 additions & 0 deletions iroha_permissions_validators/Cargo.toml
Expand Up @@ -6,6 +6,9 @@ edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
roles = ["iroha_data_model/roles"]

[dependencies]
iroha = { path = "../iroha"}
iroha_data_model = { path = "../iroha_data_model" }
Expand Down

0 comments on commit ce1edaf

Please sign in to comment.