Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: generalize permissions schema to executor data model #4658

Merged
merged 10 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 24 additions & 19 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ where
You are likely using a version of the client library \
that is incompatible with the version of the peer software",
)
.map_err(Into::into)
.map_err(Into::into)
}
StatusCode::BAD_REQUEST
| StatusCode::UNAUTHORIZED
Expand All @@ -111,22 +111,22 @@ where
| StatusCode::UNPROCESSABLE_ENTITY => Err(ValidationFail::decode_all(
&mut resp.body().as_ref(),
)
.map_or_else(
|_| {
ClientQueryError::Other(
ResponseReport::with_msg("Query failed", resp)
.map_or_else(
|_| eyre!(
.map_or_else(
|_| {
ClientQueryError::Other(
ResponseReport::with_msg("Query failed", resp)
.map_or_else(
|_| eyre!(
"Failed to decode response from Iroha. \
Response is neither a `ValidationFail` encoded value nor a valid utf-8 string error response. \
You are likely using a version of the client library that is incompatible with the version of the peer software",
),
Into::into
),
)
},
ClientQueryError::Validation,
)),
Into::into
),
)
},
ClientQueryError::Validation,
)),
_ => Err(ResponseReport::with_msg("Unexpected query response", resp).unwrap_or_else(core::convert::identity).into()),
}
}
Expand Down Expand Up @@ -328,7 +328,7 @@ impl_query_output! {
crate::data_model::block::BlockHeader,
crate::data_model::metadata::MetadataValueBox,
crate::data_model::query::TransactionQueryOutput,
crate::data_model::permission::PermissionSchema,
crate::data_model::executor::ExecutorDataModel,
crate::data_model::trigger::Trigger,
crate::data_model::prelude::Numeric,
}
Expand Down Expand Up @@ -1517,11 +1517,6 @@ pub mod permission {
//! Module with queries for permission tokens
use super::*;

/// Construct a query to get all registered [`PermissionDefinition`]s
pub const fn permission_schema() -> FindPermissionSchema {
FindPermissionSchema {}
}

/// Construct a query to get all [`Permission`] granted
/// to account with given [`Id`][AccountId]
pub fn by_account_id(account_id: AccountId) -> FindPermissionsByAccountId {
Expand Down Expand Up @@ -1564,6 +1559,16 @@ pub mod parameter {
}
}

pub mod executor {
//! Queries for executor entities
use super::*;

/// Retrieve executor data model
pub const fn data_model() -> FindExecutorDataModel {
FindExecutorDataModel
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down
2 changes: 1 addition & 1 deletion client/tests/integration/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ fn find_rate_and_make_exchange_isi_should_succeed() {
let instruction = Grant::permission(
Permission::new(
"CanTransferUserAsset".parse().unwrap(),
&json!({ "asset_id": asset_id }),
json!({ "asset_id": asset_id }),
),
alice_id.clone(),
);
Expand Down
16 changes: 8 additions & 8 deletions client/tests/integration/domain_owner_permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn domain_owner_domain_permissions() -> Result<()> {
// Granting a respective token also allows "bob@kingdom" to do so
let token = Permission::new(
"CanRegisterAssetDefinitionInDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
json!({ "domain_id": kingdom_id }),
);
test_client.submit_blocking(Grant::permission(token.clone(), bob_id.clone()))?;
let transaction = TransactionBuilder::new(chain_id, bob_id.clone())
Expand All @@ -66,7 +66,7 @@ fn domain_owner_domain_permissions() -> Result<()> {
// check that "alice@wonderland" as owner of domain can grant and revoke domain related permission tokens
let token = Permission::new(
"CanUnregisterDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
json!({ "domain_id": kingdom_id }),
);
test_client.submit_blocking(Grant::permission(token.clone(), bob_id.clone()))?;
test_client.submit_blocking(Revoke::permission(token, bob_id))?;
Expand Down Expand Up @@ -106,7 +106,7 @@ fn domain_owner_account_permissions() -> Result<()> {
let bob_id = BOB_ID.clone();
let token = Permission::new(
"CanUnregisterAccount".parse().unwrap(),
&json!({ "account_id": mad_hatter_id }),
json!({ "account_id": mad_hatter_id }),
);
test_client.submit_blocking(Grant::permission(token.clone(), bob_id.clone()))?;
test_client.submit_blocking(Revoke::permission(token, bob_id))?;
Expand Down Expand Up @@ -141,7 +141,7 @@ fn domain_owner_asset_definition_permissions() -> Result<()> {
// Grant permission to register asset definitions to "bob@kingdom"
let token = Permission::new(
"CanRegisterAssetDefinitionInDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
json!({ "domain_id": kingdom_id }),
);
test_client.submit_blocking(Grant::permission(token, bob_id.clone()))?;

Expand Down Expand Up @@ -172,7 +172,7 @@ fn domain_owner_asset_definition_permissions() -> Result<()> {
// check that "alice@wonderland" as owner of domain can grant and revoke asset definition related permission tokens in her domain
let token = Permission::new(
"CanUnregisterAssetDefinition".parse().unwrap(),
&json!({ "asset_definition_id": coin_id }),
json!({ "asset_definition_id": coin_id }),
);
test_client.submit_blocking(Grant::permission(token.clone(), bob_id.clone()))?;
test_client.submit_blocking(Revoke::permission(token, bob_id))?;
Expand Down Expand Up @@ -206,7 +206,7 @@ fn domain_owner_asset_permissions() -> Result<()> {
// Grant permission to register asset definitions to "bob@kingdom"
let token = Permission::new(
"CanRegisterAssetDefinitionInDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
json!({ "domain_id": kingdom_id }),
);
test_client.submit_blocking(Grant::permission(token, bob_id.clone()))?;

Expand Down Expand Up @@ -242,7 +242,7 @@ fn domain_owner_asset_permissions() -> Result<()> {
// check that "alice@wonderland" as owner of domain can grant and revoke asset related permission tokens in her domain
let token = Permission::new(
"CanUnregisterUserAsset".parse().unwrap(),
&json!({ "asset_id": bob_store_id }),
json!({ "asset_id": bob_store_id }),
);
test_client.submit_blocking(Grant::permission(token.clone(), bob_id.clone()))?;
test_client.submit_blocking(Revoke::permission(token, bob_id))?;
Expand Down Expand Up @@ -293,7 +293,7 @@ fn domain_owner_trigger_permissions() -> Result<()> {
// check that "alice@wonderland" as owner of domain can grant and revoke trigger related permission tokens in her domain
let token = Permission::new(
"CanUnregisterUserTrigger".parse().unwrap(),
&json!({ "account_id": bob_id }),
json!({ "account_id": bob_id }),
);
test_client.submit_blocking(Grant::permission(token.clone(), bob_id.clone()))?;
test_client.submit_blocking(Revoke::permission(token, bob_id))?;
Expand Down
12 changes: 6 additions & 6 deletions client/tests/integration/events/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,11 @@ fn produce_multiple_events() -> Result<()> {
let role_id = RoleId::from_str("TEST_ROLE")?;
let token_1 = Permission::new(
"CanRemoveKeyValueInAccount".parse()?,
&json!({ "account_id": alice_id }),
json!({ "account_id": alice_id }),
);
let token_2 = Permission::new(
"CanSetKeyValueInAccount".parse()?,
&json!({ "account_id": alice_id }),
json!({ "account_id": alice_id }),
);
let role = iroha_client::data_model::role::Role::new(role_id.clone())
.add_permission(token_1.clone())
Expand Down Expand Up @@ -240,13 +240,13 @@ fn produce_multiple_events() -> Result<()> {
DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionAdded(
AccountPermissionChanged {
account_id: bob_id.clone(),
permission_id: token_1.definition_id.clone(),
permission_id: token_1.id.clone(),
},
))),
DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionAdded(
AccountPermissionChanged {
account_id: bob_id.clone(),
permission_id: token_2.definition_id.clone(),
permission_id: token_2.id.clone(),
},
))),
DataEvent::Domain(DomainEvent::Account(AccountEvent::RoleGranted(
Expand All @@ -258,13 +258,13 @@ fn produce_multiple_events() -> Result<()> {
DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionRemoved(
AccountPermissionChanged {
account_id: bob_id.clone(),
permission_id: token_1.definition_id,
permission_id: token_1.id,
},
))),
DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionRemoved(
AccountPermissionChanged {
account_id: bob_id.clone(),
permission_id: token_2.definition_id,
permission_id: token_2.id,
},
))),
DataEvent::Domain(DomainEvent::Account(AccountEvent::RoleRevoked(
Expand Down
34 changes: 19 additions & 15 deletions client/tests/integration/permissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use iroha_client::{
};
use iroha_data_model::{
permission::Permission, role::RoleId, transaction::error::TransactionRejectionReason,
JsonString,
};
use iroha_genesis::GenesisNetwork;
use serde_json::json;
Expand All @@ -22,7 +23,7 @@ fn genesis_transactions_are_validated() {
// Setting up genesis

let genesis = GenesisNetwork::test_with_instructions([Grant::permission(
Permission::new("InvalidToken".parse().unwrap(), &json!(null)),
Permission::new("InvalidToken".parse().unwrap(), json!(null)),
ALICE_ID.clone(),
)
.into()]);
Expand Down Expand Up @@ -232,7 +233,7 @@ fn permissions_differ_not_only_by_names() {
let allow_alice_to_set_key_value_in_hats = Grant::permission(
Permission::new(
"CanSetKeyValueInUserAsset".parse().unwrap(),
&json!({ "asset_id": mouse_hat_id }),
json!({ "asset_id": mouse_hat_id }),
),
alice_id.clone(),
);
Expand Down Expand Up @@ -268,7 +269,7 @@ fn permissions_differ_not_only_by_names() {
let allow_alice_to_set_key_value_in_shoes = Grant::permission(
Permission::new(
"CanSetKeyValueInUserAsset".parse().unwrap(),
&json!({ "asset_id": mouse_shoes_id }),
json!({ "asset_id": mouse_shoes_id }),
),
alice_id,
);
Expand Down Expand Up @@ -315,10 +316,14 @@ fn stored_vs_granted_token_payload() -> Result<()> {
// Allow alice to mint mouse asset and mint initial value
let mouse_asset = AssetId::new(asset_definition_id, mouse_id.clone());
let allow_alice_to_set_key_value_in_mouse_asset = Grant::permission(
Permission::from_str_unchecked(
Permission::new(
"CanSetKeyValueInUserAsset".parse().unwrap(),
// NOTE: Introduced additional whitespaces in the serialized form
&*format!(r###"{{ "asset_id" : "xor#wonderland#{mouse_id}" }}"###),
JsonString::from_string_unchecked(format!(
// Introducing some whitespaces
// This way, if the executor compares just JSON strings, this test would fail
r##"{{ "asset_id" : "xor#wonderland#{}" }}"##,
mouse_id
)),
),
alice_id,
);
Expand Down Expand Up @@ -349,19 +354,18 @@ fn permissions_are_unified() {
let alice_id = ALICE_ID.clone();

let allow_alice_to_transfer_rose_1 = Grant::permission(
Permission::from_str_unchecked(
Permission::new(
"CanTransferUserAsset".parse().unwrap(),
// NOTE: Introduced additional whitespaces in the serialized form
&*format!(r###"{{ "asset_id" : "rose#wonderland#{alice_id}" }}"###),
json!({ "asset_id": format!("rose#wonderland#{alice_id}") }),
),
alice_id.clone(),
);

let allow_alice_to_transfer_rose_2 = Grant::permission(
Permission::from_str_unchecked(
Permission::new(
"CanTransferUserAsset".parse().unwrap(),
// NOTE: Introduced additional whitespaces in the serialized form
&*format!(r###"{{ "asset_id" : "rose##{alice_id}" }}"###),
// different content, but same meaning
json!({ "asset_id": format!("rose##{alice_id}") }),
),
alice_id,
);
Expand All @@ -372,7 +376,7 @@ fn permissions_are_unified() {

let _ = iroha_client
.submit_blocking(allow_alice_to_transfer_rose_2)
.expect_err("permission tokens are not unified");
.expect_err("should reject due to duplication");
}

#[test]
Expand All @@ -388,7 +392,7 @@ fn associated_permissions_removed_on_unregister() {
let register_domain = Register::domain(kingdom);
let bob_to_set_kv_in_domain_token = Permission::new(
"CanSetKeyValueInDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
json!({ "domain_id": kingdom_id }),
);
let allow_bob_to_set_kv_in_domain =
Grant::permission(bob_to_set_kv_in_domain_token.clone(), bob_id.clone());
Expand Down Expand Up @@ -435,7 +439,7 @@ fn associated_permissions_removed_from_role_on_unregister() {
let register_domain = Register::domain(kingdom);
let set_kv_in_domain_token = Permission::new(
"CanSetKeyValueInDomain".parse().unwrap(),
&json!({ "domain_id": kingdom_id }),
json!({ "domain_id": kingdom_id }),
);
let role = Role::new(role_id.clone()).add_permission(set_kv_in_domain_token.clone());
let register_role = Register::role(role);
Expand Down
2 changes: 1 addition & 1 deletion client/tests/integration/queries/role.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ fn find_roles_by_account_id() -> Result<()> {
.map(|role_id| {
Register::role(Role::new(role_id).add_permission(Permission::new(
"CanSetKeyValueInAccount".parse().unwrap(),
&json!({ "account_id": alice_id }),
json!({ "account_id": alice_id }),
)))
})
.collect::<Vec<_>>();
Expand Down
25 changes: 12 additions & 13 deletions client/tests/integration/roles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn register_role_with_empty_token_params() -> Result<()> {
wait_for_genesis_committed(&vec![test_client.clone()], 0);

let role_id = "root".parse().expect("Valid");
let token = Permission::new("token".parse()?, &json!(null));
let token = Permission::new("token".parse()?, json!(null));
let role = Role::new(role_id).add_permission(token);

test_client.submit(Register::role(role))?;
Expand Down Expand Up @@ -64,11 +64,11 @@ fn register_and_grant_role_for_metadata_access() -> Result<()> {
let role = Role::new(role_id.clone())
.add_permission(Permission::new(
"CanSetKeyValueInAccount".parse()?,
&json!({ "account_id": mouse_id }),
json!({ "account_id": mouse_id }),
))
.add_permission(Permission::new(
"CanRemoveKeyValueInAccount".parse()?,
&json!({ "account_id": mouse_id }),
json!({ "account_id": mouse_id }),
));
let register_role = Register::role(role);
test_client.submit_blocking(register_role)?;
Expand Down Expand Up @@ -113,7 +113,7 @@ fn unregistered_role_removed_from_account() -> Result<()> {
// Register root role
let register_role = Register::role(Role::new(role_id.clone()).add_permission(Permission::new(
"CanSetKeyValueInAccount".parse()?,
&json!({ "account_id": alice_id }),
json!({ "account_id": alice_id }),
)));
test_client.submit_blocking(register_role)?;

Expand Down Expand Up @@ -151,7 +151,7 @@ fn role_with_invalid_permissions_is_not_accepted() -> Result<()> {
.expect("should be valid");
let role = Role::new(role_id).add_permission(Permission::new(
"CanSetKeyValueInAccount".parse()?,
&json!({ "account_id": rose_asset_id }),
json!({ "account_id": rose_asset_id }),
));

let err = test_client
Expand All @@ -172,20 +172,19 @@ fn role_with_invalid_permissions_is_not_accepted() -> Result<()> {

#[test]
#[allow(deprecated)]
fn role_permissions_unified() {
fn role_permissions_are_deduplicated() {
let (_rt, _peer, test_client) = <PeerBuilder>::new().with_port(11_235).start_with_runtime();
wait_for_genesis_committed(&vec![test_client.clone()], 0);

let allow_alice_to_transfer_rose_1 = Permission::from_str_unchecked(
let allow_alice_to_transfer_rose_1 = Permission::new(
"CanTransferUserAsset".parse().unwrap(),
// NOTE: Introduced additional whitespaces in the serialized form
"{ \"asset_id\" : \"rose#wonderland#ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland\" }",
json!({ "asset_id": "rose#wonderland#ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland" }),
);

let allow_alice_to_transfer_rose_2 = Permission::from_str_unchecked(
// Different content, but same meaning
let allow_alice_to_transfer_rose_2 = Permission::new(
"CanTransferUserAsset".parse().unwrap(),
// NOTE: Introduced additional whitespaces in the serialized form
"{ \"asset_id\" : \"rose##ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland\" }",
json!({ "asset_id": "rose##ed0120CE7FA46C9DCE7EA4B125E2E36BDB63EA33073E7590AC92816AE1E861B7048B03@wonderland" }),
);

let role_id: RoleId = "role_id".parse().expect("Valid");
Expand Down Expand Up @@ -248,7 +247,7 @@ fn grant_revoke_role_permissions() -> Result<()> {
);
let permission = Permission::new(
"CanSetKeyValueInAccount".parse()?,
&json!({ "account_id": mouse_id }),
json!({ "account_id": mouse_id }),
);
let grant_role_permission = Grant::role_permission(permission.clone(), role_id.clone());
let revoke_role_permission = Revoke::role_permission(permission.clone(), role_id.clone());
Expand Down
Loading
Loading