Skip to content

Commit 0ced347

Browse files
andy31415andreilitvinbzbarsky-apple
authored andcommitted
Update usage of Event logic to be routable through DataModel::Provider (#35697)
* updates * Add missing file * Updates into the code, hopefully it works * Restyle * Use eventpathreadable as a name, since this is what the access check is for * Fix some unit tests * Fix flag * Fix linter complaint (which is not valid, but we have to work around it) * Attempt some code reuse with ember coupling * Restyle * Undo change that was unintended * No gn check for the enabled provider use since dependency will not be there ... * Rename and remove simple file and place directly into main * Restyle * Remove extra text that is not needed anymore * Remove unused file * Conditional use fix * Update src/app/data-model-provider/Provider.h Co-authored-by: Boris Zbarsky <bzbarsky@apple.com> * Renamed to ClusterSupportsEvent * updated comment * Typo fix --------- Co-authored-by: Andrei Litvin <andreilitvin@google.com> Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
1 parent c4c81c0 commit 0ced347

13 files changed

+251
-105
lines changed

src/app/BUILD.gn

+5-1
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ static_library("interaction-model") {
257257
"reporting/Read-Ember.cpp",
258258
"reporting/Read-Ember.h",
259259
]
260+
public_deps += [ "${chip_root}/src/app/ember_coupling" ]
260261
} else if (chip_use_data_model_interface == "check") {
261262
sources += [
262263
"reporting/Read-Checked.cpp",
@@ -266,7 +267,10 @@ static_library("interaction-model") {
266267
"reporting/Read-Ember.cpp",
267268
"reporting/Read-Ember.h",
268269
]
269-
public_deps += [ "${chip_root}/src/app/data-model-provider" ]
270+
public_deps += [
271+
"${chip_root}/src/app/data-model-provider",
272+
"${chip_root}/src/app/ember_coupling",
273+
]
270274
} else { # enabled
271275
sources += [
272276
"reporting/Read-DataModel.cpp",

src/app/InteractionModelEngine.cpp

+8-99
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
#include <app/codegen-data-model-provider/Instance.h>
5252
#endif
5353

54+
#if !CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
55+
#include <app/ember_coupling/EventPathValidity.mixin.h> // nogncheck
56+
#endif
57+
5458
namespace chip {
5559
namespace app {
5660

@@ -544,105 +548,6 @@ CHIP_ERROR InteractionModelEngine::ParseAttributePaths(const Access::SubjectDesc
544548
return err;
545549
}
546550

547-
#if !CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
548-
static bool CanAccessEvent(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteClusterPath & aPath,
549-
Access::Privilege aNeededPrivilege)
550-
{
551-
Access::RequestPath requestPath{ .cluster = aPath.mClusterId,
552-
.endpoint = aPath.mEndpointId,
553-
.requestType = Access::RequestType::kEventReadRequest };
554-
// leave requestPath.entityId optional value unset to indicate wildcard
555-
CHIP_ERROR err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, aNeededPrivilege);
556-
return (err == CHIP_NO_ERROR);
557-
}
558-
#endif
559-
560-
static bool CanAccessEvent(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteEventPath & aPath)
561-
{
562-
Access::RequestPath requestPath{ .cluster = aPath.mClusterId,
563-
.endpoint = aPath.mEndpointId,
564-
.requestType = Access::RequestType::kEventReadRequest,
565-
.entityId = aPath.mEventId };
566-
CHIP_ERROR err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, RequiredPrivilege::ForReadEvent(aPath));
567-
return (err == CHIP_NO_ERROR);
568-
}
569-
570-
/**
571-
* Helper to handle wildcard events in the event path.
572-
*/
573-
static bool HasValidEventPathForEndpointAndCluster(EndpointId aEndpoint, const EmberAfCluster * aCluster,
574-
const EventPathParams & aEventPath,
575-
const Access::SubjectDescriptor & aSubjectDescriptor)
576-
{
577-
if (aEventPath.HasWildcardEventId())
578-
{
579-
#if CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
580-
for (decltype(aCluster->eventCount) idx = 0; idx < aCluster->eventCount; ++idx)
581-
{
582-
ConcreteEventPath path(aEndpoint, aCluster->clusterId, aCluster->eventList[idx]);
583-
// If we get here, the path exists. We just have to do an ACL check for it.
584-
bool isValid = CanAccessEvent(aSubjectDescriptor, path);
585-
if (isValid)
586-
{
587-
return true;
588-
}
589-
}
590-
591-
return false;
592-
#else
593-
// We have no way to expand wildcards. Just assume that we would need
594-
// View permissions for whatever events are involved.
595-
ConcreteClusterPath clusterPath(aEndpoint, aCluster->clusterId);
596-
return CanAccessEvent(aSubjectDescriptor, clusterPath, Access::Privilege::kView);
597-
#endif
598-
}
599-
600-
ConcreteEventPath path(aEndpoint, aCluster->clusterId, aEventPath.mEventId);
601-
if (CheckEventSupportStatus(path) != Status::Success)
602-
{
603-
// Not an existing event path.
604-
return false;
605-
}
606-
return CanAccessEvent(aSubjectDescriptor, path);
607-
}
608-
609-
/**
610-
* Helper to handle wildcard clusters in the event path.
611-
*/
612-
static bool HasValidEventPathForEndpoint(EndpointId aEndpoint, const EventPathParams & aEventPath,
613-
const Access::SubjectDescriptor & aSubjectDescriptor)
614-
{
615-
if (aEventPath.HasWildcardClusterId())
616-
{
617-
auto * endpointType = emberAfFindEndpointType(aEndpoint);
618-
if (endpointType == nullptr)
619-
{
620-
// Not going to have any valid paths in here.
621-
return false;
622-
}
623-
624-
for (decltype(endpointType->clusterCount) idx = 0; idx < endpointType->clusterCount; ++idx)
625-
{
626-
bool hasValidPath =
627-
HasValidEventPathForEndpointAndCluster(aEndpoint, &endpointType->cluster[idx], aEventPath, aSubjectDescriptor);
628-
if (hasValidPath)
629-
{
630-
return true;
631-
}
632-
}
633-
634-
return false;
635-
}
636-
637-
auto * cluster = emberAfFindServerCluster(aEndpoint, aEventPath.mClusterId);
638-
if (cluster == nullptr)
639-
{
640-
// Nothing valid here.
641-
return false;
642-
}
643-
return HasValidEventPathForEndpointAndCluster(aEndpoint, cluster, aEventPath, aSubjectDescriptor);
644-
}
645-
646551
CHIP_ERROR InteractionModelEngine::ParseEventPaths(const Access::SubjectDescriptor & aSubjectDescriptor,
647552
EventPathIBs::Parser & aEventPathListParser, bool & aHasValidEventPath,
648553
size_t & aRequestedEventPathCount)
@@ -670,6 +575,9 @@ CHIP_ERROR InteractionModelEngine::ParseEventPaths(const Access::SubjectDescript
670575
continue;
671576
}
672577

578+
#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
579+
aHasValidEventPath = mDataModelProvider->EventPathIncludesAccessibleConcretePath(eventPath, aSubjectDescriptor);
580+
#else
673581
// The definition of "valid path" is "path exists and ACL allows
674582
// access". We need to do some expansion of wildcards to handle that.
675583
if (eventPath.HasWildcardEndpointId())
@@ -690,6 +598,7 @@ CHIP_ERROR InteractionModelEngine::ParseEventPaths(const Access::SubjectDescript
690598
// emberAfFindEndpointType returns null for disabled endpoints.
691599
aHasValidEventPath = HasValidEventPathForEndpoint(eventPath.mEndpointId, eventPath, aSubjectDescriptor);
692600
}
601+
#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL
693602
}
694603

695604
if (err == CHIP_ERROR_END_OF_TLV)

src/app/InteractionModelEngine.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -470,9 +470,8 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,
470470
*
471471
* aRequestedEventPathCount will be updated to reflect the number of event paths in the request.
472472
*/
473-
static CHIP_ERROR ParseEventPaths(const Access::SubjectDescriptor & aSubjectDescriptor,
474-
EventPathIBs::Parser & aEventPathListParser, bool & aHasValidEventPath,
475-
size_t & aRequestedEventPathCount);
473+
CHIP_ERROR ParseEventPaths(const Access::SubjectDescriptor & aSubjectDescriptor, EventPathIBs::Parser & aEventPathListParser,
474+
bool & aHasValidEventPath, size_t & aRequestedEventPathCount);
476475

477476
/**
478477
* Called when Interaction Model receives a Read Request message. Errors processing

src/app/codegen-data-model-provider/BUILD.gn

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Copyright (c) 2024 Project CHIP Authors
2-
#
2+
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
55
# You may obtain a copy of the License at

src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,25 @@
1616
*/
1717
#include <app/codegen-data-model-provider/CodegenDataModelProvider.h>
1818

19+
#include <access/AccessControl.h>
1920
#include <app-common/zap-generated/attribute-type.h>
2021
#include <app/CommandHandlerInterface.h>
2122
#include <app/CommandHandlerInterfaceRegistry.h>
2223
#include <app/ConcreteClusterPath.h>
2324
#include <app/ConcreteCommandPath.h>
25+
#include <app/EventPathParams.h>
2426
#include <app/RequiredPrivilege.h>
2527
#include <app/data-model-provider/MetadataTypes.h>
2628
#include <app/util/IMClusterCommandHandler.h>
29+
#include <app/util/af-types.h>
2730
#include <app/util/attribute-storage.h>
2831
#include <app/util/endpoint-config-api.h>
2932
#include <lib/core/CHIPError.h>
3033
#include <lib/core/DataModelTypes.h>
3134

35+
// separated out for code-reuse
36+
#include <app/ember_coupling/EventPathValidity.mixin.h>
37+
3238
#include <optional>
3339
#include <variant>
3440

@@ -720,5 +726,30 @@ ConcreteCommandPath CodegenDataModelProvider::NextGeneratedCommand(const Concret
720726
return ConcreteCommandPath(before.mEndpointId, before.mClusterId, *commandId);
721727
}
722728

729+
bool CodegenDataModelProvider::EventPathIncludesAccessibleConcretePath(const EventPathParams & path,
730+
const Access::SubjectDescriptor & descriptor)
731+
{
732+
733+
if (!path.HasWildcardEndpointId())
734+
{
735+
// No need to check whether the endpoint is enabled, because
736+
// emberAfFindEndpointType returns null for disabled endpoints.
737+
return HasValidEventPathForEndpoint(path.mEndpointId, path, descriptor);
738+
}
739+
740+
for (uint16_t endpointIndex = 0; endpointIndex < emberAfEndpointCount(); ++endpointIndex)
741+
{
742+
if (!emberAfEndpointIndexIsEnabled(endpointIndex))
743+
{
744+
continue;
745+
}
746+
if (HasValidEventPathForEndpoint(emberAfEndpointFromIndex(endpointIndex), path, descriptor))
747+
{
748+
return true;
749+
}
750+
}
751+
return false;
752+
}
753+
723754
} // namespace app
724755
} // namespace chip

src/app/codegen-data-model-provider/CodegenDataModelProvider.h

+2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ class CodegenDataModelProvider : public chip::app::DataModel::Provider
8484
return CHIP_NO_ERROR;
8585
}
8686

87+
bool EventPathIncludesAccessibleConcretePath(const EventPathParams & path,
88+
const Access::SubjectDescriptor & descriptor) override;
8789
DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
8890
AttributeValueEncoder & encoder) override;
8991
DataModel::ActionReturnStatus WriteAttribute(const DataModel::WriteAttributeRequest & request,

src/app/codegen-data-model-provider/CodegenDataModelProvider_Write.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
* limitations under the License.
1616
*/
1717
#include <app/codegen-data-model-provider/CodegenDataModelProvider.h>
18-
#include <app/util/attribute-storage.h>
1918

2019
#include <access/AccessControl.h>
2120
#include <app-common/zap-generated/attribute-type.h>
@@ -29,6 +28,7 @@
2928
#include <app/util/attribute-metadata.h>
3029
#include <app/util/attribute-storage-detail.h>
3130
#include <app/util/attribute-storage-null-handling.h>
31+
#include <app/util/attribute-storage.h>
3232
#include <app/util/attribute-table-detail.h>
3333
#include <app/util/attribute-table.h>
3434
#include <app/util/ember-io-storage.h>

src/app/codegen-data-model-provider/model.gni

+1
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,6 @@ codegen_data_model_SOURCES = [
3737
codegen_data_model_PUBLIC_DEPS = [
3838
"${chip_root}/src/app/common:attribute-type",
3939
"${chip_root}/src/app/data-model-provider",
40+
"${chip_root}/src/app/ember_coupling",
4041
"${chip_root}/src/app/codegen-data-model-provider:instance-header",
4142
]

src/app/data-model-provider/Provider.h

+12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
*/
1717
#pragma once
1818

19+
#include "access/SubjectDescriptor.h"
20+
#include "app/EventPathParams.h"
1921
#include "lib/core/CHIPError.h"
2022
#include <lib/core/TLVReader.h>
2123
#include <lib/core/TLVWriter.h>
@@ -57,6 +59,16 @@ class Provider : public ProviderMetadataTree
5759
// event emitting, path marking and other operations
5860
virtual InteractionModelContext CurrentContext() const { return mContext; }
5961

62+
/// Validates that the given event path is supported, where path may contain wildcards.
63+
///
64+
/// If any wild cards exist on the given path, the implementation is expected to validate
65+
/// that an accessible event path exists on some wildcard expansion.
66+
///
67+
/// At the very minimum this will validate that a valid endpoint/cluster can be expanded
68+
/// from the input path and that the given descriptor has access to it.
69+
virtual bool EventPathIncludesAccessibleConcretePath(const EventPathParams & path,
70+
const Access::SubjectDescriptor & descriptor) = 0;
71+
6072
/// TEMPORARY/TRANSITIONAL requirement for transitioning from ember-specific code
6173
/// ReadAttribute is REQUIRED to perform:
6274
/// - ACL validation (see notes on OperationFlags::kInternal)

src/app/ember_coupling/BUILD.gn

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import("//build_overrides/chip.gni")
16+
17+
# The sources in this directory exist to limit the amount of code duplication
18+
# and assume strong ember and access coupling
19+
#
20+
# They are NOT stand-alone compilable and are rather for `#include` support.
21+
source_set("ember_coupling") {
22+
sources = [ "EventPathValidity.mixin.h" ]
23+
}

0 commit comments

Comments
 (0)