/* * * Copyright (c) 2021 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { using namespace chip; using namespace chip::Access; using namespace chip::Test; const MockNodeConfig & TestMockNodeConfig() { using namespace chip::app; using namespace chip::app::Clusters::Globals::Attributes; // clang-format off static const MockNodeConfig config({ MockEndpointConfig(kTestEndpointId, { MockClusterConfig(kTestClusterId, { ClusterRevision::Id, FeatureMap::Id, 1, 2 }), }), }); // clang-format on return config; } class TestAccessControlDelegate : public AccessControl::Delegate { public: CHIP_ERROR Check(const SubjectDescriptor & subjectDescriptor, const chip::Access::RequestPath & requestPath, Privilege requestPrivilege) override { if (requestPath.cluster == chip::Test::kTestDeniedClusterId2) { return CHIP_ERROR_ACCESS_DENIED; } return CHIP_NO_ERROR; } }; AccessControl::Delegate * GetTestAccessControlDelegate() { static TestAccessControlDelegate accessControlDelegate; return &accessControlDelegate; } class TestDeviceTypeResolver : public AccessControl::DeviceTypeResolver { public: bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) override { return false; } } gDeviceTypeResolver; class MockInteractionModelApp : public chip::app::ReadClient::Callback { public: void OnAttributeData(const chip::app::ConcreteDataAttributePath & aPath, chip::TLV::TLVReader * apData, const chip::app::StatusIB & status) override { mGotReport = true; mLastStatusReceived = status; } void OnError(CHIP_ERROR aError) override { mError = aError; } void OnDone(chip::app::ReadClient *) override {} void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) override { if (aReadPrepareParams.mpAttributePathParamsList != nullptr) { delete[] aReadPrepareParams.mpAttributePathParamsList; } if (aReadPrepareParams.mpDataVersionFilterList != nullptr) { delete[] aReadPrepareParams.mpDataVersionFilterList; } } bool mGotReport = false; chip::app::StatusIB mLastStatusReceived; CHIP_ERROR mError = CHIP_NO_ERROR; }; } // namespace namespace chip { namespace app { class TestAclAttribute : public Test::AppContext { public: void SetUp() override { AppContext::SetUp(); Access::GetAccessControl().Finish(); Access::GetAccessControl().Init(GetTestAccessControlDelegate(), gDeviceTypeResolver); mOldProvider = InteractionModelEngine::GetInstance()->SetDataModelProvider(&TestImCustomDataModel::Instance()); chip::Test::SetMockNodeConfig(TestMockNodeConfig()); } void TearDown() override { chip::Test::ResetMockNodeConfig(); AppContext::TearDown(); InteractionModelEngine::GetInstance()->SetDataModelProvider(mOldProvider); } private: chip::app::DataModel::Provider * mOldProvider = nullptr; }; // Read Client sends a malformed subscribe request, interaction model engine fails to parse the request and generates a status // report to client, and client is closed. TEST_F(TestAclAttribute, TestACLDeniedAttribute) { Messaging::ReliableMessageMgr * rm = GetExchangeManager().GetReliableMessageMgr(); EXPECT_EQ(rm->TestGetCountRetransTable(), 0); MockInteractionModelApp delegate; auto * engine = chip::app::InteractionModelEngine::GetInstance(); EXPECT_EQ(engine->Init(&GetExchangeManager(), &GetFabricTable(), app::reporting::GetDefaultReportScheduler()), CHIP_NO_ERROR); { app::ReadClient readClient(chip::app::InteractionModelEngine::GetInstance(), &GetExchangeManager(), delegate, chip::app::ReadClient::InteractionType::Subscribe); chip::app::AttributePathParams attributePathParams[2]; attributePathParams[0].mEndpointId = chip::Test::kTestEndpointId; attributePathParams[0].mClusterId = chip::Test::kTestDeniedClusterId1; attributePathParams[0].mAttributeId = 1; attributePathParams[1].mEndpointId = chip::Test::kTestEndpointId; attributePathParams[1].mClusterId = chip::Test::kTestDeniedClusterId1; attributePathParams[1].mAttributeId = 2; ReadPrepareParams readPrepareParams(GetSessionBobToAlice()); readPrepareParams.mpAttributePathParamsList = attributePathParams; readPrepareParams.mAttributePathParamsListSize = 2; EXPECT_EQ(readClient.SendRequest(readPrepareParams), CHIP_NO_ERROR); DrainAndServiceIO(); EXPECT_EQ(delegate.mError, CHIP_IM_GLOBAL_STATUS(InvalidAction)); EXPECT_FALSE(delegate.mGotReport); delegate.mError = CHIP_NO_ERROR; delegate.mGotReport = false; } { app::ReadClient readClient(chip::app::InteractionModelEngine::GetInstance(), &GetExchangeManager(), delegate, chip::app::ReadClient::InteractionType::Subscribe); chip::app::AttributePathParams attributePathParams[2]; attributePathParams[0].mClusterId = chip::Test::kTestDeniedClusterId2; attributePathParams[0].mAttributeId = 1; attributePathParams[1].mClusterId = chip::Test::kTestDeniedClusterId2; attributePathParams[1].mAttributeId = 2; ReadPrepareParams readPrepareParams(GetSessionBobToAlice()); readPrepareParams.mpAttributePathParamsList = attributePathParams; readPrepareParams.mAttributePathParamsListSize = 2; EXPECT_EQ(readClient.SendRequest(readPrepareParams), CHIP_NO_ERROR); DrainAndServiceIO(); EXPECT_EQ(delegate.mError, CHIP_IM_GLOBAL_STATUS(InvalidAction)); EXPECT_FALSE(delegate.mGotReport); delegate.mError = CHIP_NO_ERROR; delegate.mGotReport = false; } { app::ReadClient readClient(chip::app::InteractionModelEngine::GetInstance(), &GetExchangeManager(), delegate, chip::app::ReadClient::InteractionType::Subscribe); chip::app::AttributePathParams attributePathParams[2]; attributePathParams[0].mEndpointId = chip::Test::kTestEndpointId; attributePathParams[0].mClusterId = chip::Test::kTestDeniedClusterId1; attributePathParams[0].mAttributeId = 1; attributePathParams[1].mEndpointId = chip::Test::kTestEndpointId; attributePathParams[1].mClusterId = chip::Test::kTestClusterId; attributePathParams[1].mAttributeId = 2; ReadPrepareParams readPrepareParams(GetSessionBobToAlice()); readPrepareParams.mpAttributePathParamsList = attributePathParams; readPrepareParams.mAttributePathParamsListSize = 2; EXPECT_EQ(readClient.SendRequest(readPrepareParams), CHIP_NO_ERROR); DrainAndServiceIO(); EXPECT_EQ(delegate.mError, CHIP_NO_ERROR); EXPECT_TRUE(delegate.mGotReport); EXPECT_EQ(engine->GetNumActiveReadHandlers(ReadHandler::InteractionType::Subscribe), 1u); delegate.mError = CHIP_NO_ERROR; delegate.mGotReport = false; } EXPECT_EQ(engine->GetNumActiveReadClients(), 0u); engine->Shutdown(); EXPECT_EQ(GetExchangeManager().GetNumActiveExchanges(), 0u); } } // namespace app } // namespace chip