Skip to content

Commit

Permalink
feat!: generalize permissions schema to executor data model (#4658)
Browse files Browse the repository at this point in the history
Signed-off-by: 0x009922 <[email protected]>
  • Loading branch information
0x009922 authored May 29, 2024
1 parent f0edcb7 commit 7a41ae8
Show file tree
Hide file tree
Showing 44 changed files with 947 additions and 929 deletions.
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

0 comments on commit 7a41ae8

Please sign in to comment.