diff --git a/matter/src/data_model/core.rs b/matter/src/data_model/core.rs index 49ca031..7ea9659 100644 --- a/matter/src/data_model/core.rs +++ b/matter/src/data_model/core.rs @@ -220,7 +220,13 @@ impl DataModel { fn sess_to_accessor(&self, sess: &Session) -> Accessor { match sess.get_session_mode() { SessionMode::Case(c) => { - let subject = AccessorSubjects::new(sess.get_peer_node_id().unwrap_or_default()); + let mut subject = + AccessorSubjects::new(sess.get_peer_node_id().unwrap_or_default()); + for i in c.cat_ids { + if i != 0 { + let _ = subject.add(i); + } + } Accessor::new(c.fab_idx, subject, AuthMode::Case, self.acl_mgr.clone()) } SessionMode::Pase => Accessor::new( diff --git a/matter/tests/common/im_engine.rs b/matter/tests/common/im_engine.rs index 29e1c76..f91433c 100644 --- a/matter/tests/common/im_engine.rs +++ b/matter/tests/common/im_engine.rs @@ -37,7 +37,7 @@ use matter::{ network::Address, packet::PacketPool, proto_demux::ProtoCtx, - session::{CloneData, SessionMgr, SessionMode}, + session::{CloneData, NocCatIds, SessionMgr, SessionMode}, }, transport::{proto_demux::HandleProto, session::CaseDetails}, utils::writebuf::WriteBuf, @@ -69,6 +69,7 @@ pub struct ImInput<'a> { action: OpCode, data: &'a dyn ToTLV, peer_id: u64, + cat_ids: NocCatIds, } pub const IM_ENGINE_PEER_ID: u64 = 445566; @@ -78,12 +79,17 @@ impl<'a> ImInput<'a> { action, data, peer_id: IM_ENGINE_PEER_ID, + cat_ids: Default::default(), } } pub fn set_peer_node_id(&mut self, peer: u64) { self.peer_id = peer; } + + pub fn set_cat_ids(&mut self, cat_ids: &NocCatIds) { + self.cat_ids = *cat_ids; + } } impl ImEngine { @@ -146,7 +152,7 @@ impl ImEngine { std::net::IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 5542, )), - SessionMode::Case(CaseDetails::new(1, &Default::default())), + SessionMode::Case(CaseDetails::new(1, &input.cat_ids)), ); let sess_idx = sess_mgr.clone_session(&clone_data).unwrap(); let sess = sess_mgr.get_session_handle(sess_idx); diff --git a/matter/tests/data_model/acl_and_dataver.rs b/matter/tests/data_model/acl_and_dataver.rs index 3dd2f60..d692c6a 100644 --- a/matter/tests/data_model/acl_and_dataver.rs +++ b/matter/tests/data_model/acl_and_dataver.rs @@ -16,7 +16,7 @@ */ use matter::{ - acl::{AclEntry, AuthMode, Target}, + acl::{gen_noc_cat, AclEntry, AuthMode, Target}, data_model::{ objects::{AttrValue, EncodeValue, Privilege}, system_model::access_control, @@ -30,6 +30,7 @@ use matter::{ messages::{msg, GenericPath}, }, tlv::{self, ElementType, FromTLV, TLVArray, TLVElement, TLVWriter, TagType}, + transport::session::NocCatIds, }; use crate::{ @@ -77,6 +78,7 @@ fn gen_read_reqs_output<'a>( fn handle_write_reqs( im: &mut ImEngine, peer_node_id: u64, + peer_cat_ids: Option<&NocCatIds>, input: &[AttrData], expected: &[AttrStatus], ) { @@ -85,6 +87,9 @@ fn handle_write_reqs( let mut input = ImInput::new(OpCode::WriteRequest, &write_req); input.set_peer_node_id(peer_node_id); + if let Some(cat_ids) = peer_cat_ids { + input.set_cat_ids(cat_ids); + } let (_, out_buf) = im.process(&input, &mut out_buf); tlv::print_tlv_list(out_buf); @@ -263,7 +268,7 @@ fn wc_write_attribute() { // Test 1: Wildcard write to an attribute without permission should return // no error - handle_write_reqs(&mut im, peer, input0, &[]); + handle_write_reqs(&mut im, peer, None, input0, &[]); { let node = im.dm.node.read().unwrap(); let echo = node.get_cluster(0, echo_cluster::ID).unwrap(); @@ -287,6 +292,7 @@ fn wc_write_attribute() { handle_write_reqs( &mut im, peer, + None, input0, &[AttrStatus::new(&ep0_att, IMStatusCode::Sucess, 0)], ); @@ -307,6 +313,7 @@ fn wc_write_attribute() { handle_write_reqs( &mut im, peer, + None, input1, &[ AttrStatus::new(&ep0_att, IMStatusCode::Sucess, 0), @@ -350,7 +357,7 @@ fn exact_write_attribute() { // Test 1: Exact write to an attribute without permission should return // Unsupported Access Error - handle_write_reqs(&mut im, peer, input, expected_fail); + handle_write_reqs(&mut im, peer, None, input, expected_fail); assert_eq!( AttrValue::Uint16(ATTR_WRITE_DEFAULT_VALUE), read_cluster_id_write_attr(&im, 0) @@ -363,7 +370,62 @@ fn exact_write_attribute() { // Test 1: Exact write to an attribute with permission should grant // access - handle_write_reqs(&mut im, peer, input, expected_success); + handle_write_reqs(&mut im, peer, None, input, expected_success); + assert_eq!(AttrValue::Uint16(val0), read_cluster_id_write_attr(&im, 0)); +} + +#[test] +/// Ensure that an write attribute without a wildcard returns an error when the +/// ACL disallows the access, and returns success once access is granted to the CAT ID +/// The Accessor CAT version is one more than that in the ACL +fn exact_write_attribute_noc_cat() { + let _ = env_logger::try_init(); + let val0 = 10; + let attr_data0 = |tag, t: &mut TLVWriter| { + let _ = t.u16(tag, val0); + }; + + let ep0_att = GenericPath::new( + Some(0), + Some(echo_cluster::ID), + Some(echo_cluster::Attributes::AttWrite as u32), + ); + + let input = &[AttrData::new( + None, + AttrPath::new(&ep0_att), + EncodeValue::Closure(&attr_data0), + )]; + let expected_fail = &[AttrStatus::new( + &ep0_att, + IMStatusCode::UnsupportedAccess, + 0, + )]; + let expected_success = &[AttrStatus::new(&ep0_att, IMStatusCode::Sucess, 0)]; + + let peer = 98765; + /* CAT in NOC is 1 more, in version, than that in ACL */ + let noc_cat = gen_noc_cat(0xABCD, 2); + let cat_in_acl = gen_noc_cat(0xABCD, 1); + let cat_ids = [noc_cat, 0, 0]; + let mut im = ImEngine::new(); + + // Test 1: Exact write to an attribute without permission should return + // Unsupported Access Error + handle_write_reqs(&mut im, peer, Some(&cat_ids), input, expected_fail); + assert_eq!( + AttrValue::Uint16(ATTR_WRITE_DEFAULT_VALUE), + read_cluster_id_write_attr(&im, 0) + ); + + // Add ACL to allow our peer to access any endpoint + let mut acl = AclEntry::new(1, Privilege::ADMIN, AuthMode::Case); + acl.add_subject(cat_in_acl).unwrap(); + im.acl_mgr.add(acl).unwrap(); + + // Test 1: Exact write to an attribute with permission should grant + // access + handle_write_reqs(&mut im, peer, Some(&cat_ids), input, expected_success); assert_eq!(AttrValue::Uint16(val0), read_cluster_id_write_attr(&im, 0)); } @@ -399,6 +461,7 @@ fn insufficient_perms_write() { handle_write_reqs( &mut im, peer, + None, input0, &[AttrStatus::new( &ep0_att, @@ -466,6 +529,7 @@ fn write_with_runtime_acl_add() { handle_write_reqs( &mut im, peer, + None, // write to echo-cluster attribute, write to acl attribute, write to echo-cluster attribute &[input0, acl_input, input0], &[ @@ -623,6 +687,7 @@ fn test_write_data_ver() { handle_write_reqs( &mut im, peer, + None, input_correct_dataver, &[AttrStatus::new(&ep0_attwrite, IMStatusCode::Sucess, 0)], ); @@ -638,6 +703,7 @@ fn test_write_data_ver() { handle_write_reqs( &mut im, peer, + None, input_correct_dataver, &[AttrStatus::new( &ep0_attwrite, @@ -660,6 +726,7 @@ fn test_write_data_ver() { handle_write_reqs( &mut im, peer, + None, input_correct_dataver, &[AttrStatus::new(&ep0_attwrite, IMStatusCode::Sucess, 0)], );