Skip to content

Commit

Permalink
Update usage of Event logic to be routable through DataModel::Provider (
Browse files Browse the repository at this point in the history
#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 <[email protected]>

* Renamed to ClusterSupportsEvent

* updated comment

* Typo fix

---------

Co-authored-by: Andrei Litvin <[email protected]>
Co-authored-by: Boris Zbarsky <[email protected]>
  • Loading branch information
3 people authored and pull[bot] committed Nov 28, 2024
1 parent 91e9f2e commit 4627689
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 105 deletions.
6 changes: 5 additions & 1 deletion src/app/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ static_library("interaction-model") {
"reporting/Read-Ember.cpp",
"reporting/Read-Ember.h",
]
public_deps += [ "${chip_root}/src/app/ember_coupling" ]
} else if (chip_use_data_model_interface == "check") {
sources += [
"reporting/Read-Checked.cpp",
Expand All @@ -266,7 +267,10 @@ static_library("interaction-model") {
"reporting/Read-Ember.cpp",
"reporting/Read-Ember.h",
]
public_deps += [ "${chip_root}/src/app/data-model-provider" ]
public_deps += [
"${chip_root}/src/app/data-model-provider",
"${chip_root}/src/app/ember_coupling",
]
} else { # enabled
sources += [
"reporting/Read-DataModel.cpp",
Expand Down
107 changes: 8 additions & 99 deletions src/app/InteractionModelEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
#include <app/codegen-data-model-provider/Instance.h>
#endif

#if !CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
#include <app/ember_coupling/EventPathValidity.mixin.h> // nogncheck
#endif

namespace chip {
namespace app {

Expand Down Expand Up @@ -544,105 +548,6 @@ CHIP_ERROR InteractionModelEngine::ParseAttributePaths(const Access::SubjectDesc
return err;
}

#if !CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
static bool CanAccessEvent(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteClusterPath & aPath,
Access::Privilege aNeededPrivilege)
{
Access::RequestPath requestPath{ .cluster = aPath.mClusterId,
.endpoint = aPath.mEndpointId,
.requestType = Access::RequestType::kEventReadRequest };
// leave requestPath.entityId optional value unset to indicate wildcard
CHIP_ERROR err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, aNeededPrivilege);
return (err == CHIP_NO_ERROR);
}
#endif

static bool CanAccessEvent(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteEventPath & aPath)
{
Access::RequestPath requestPath{ .cluster = aPath.mClusterId,
.endpoint = aPath.mEndpointId,
.requestType = Access::RequestType::kEventReadRequest,
.entityId = aPath.mEventId };
CHIP_ERROR err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, RequiredPrivilege::ForReadEvent(aPath));
return (err == CHIP_NO_ERROR);
}

/**
* Helper to handle wildcard events in the event path.
*/
static bool HasValidEventPathForEndpointAndCluster(EndpointId aEndpoint, const EmberAfCluster * aCluster,
const EventPathParams & aEventPath,
const Access::SubjectDescriptor & aSubjectDescriptor)
{
if (aEventPath.HasWildcardEventId())
{
#if CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
for (decltype(aCluster->eventCount) idx = 0; idx < aCluster->eventCount; ++idx)
{
ConcreteEventPath path(aEndpoint, aCluster->clusterId, aCluster->eventList[idx]);
// If we get here, the path exists. We just have to do an ACL check for it.
bool isValid = CanAccessEvent(aSubjectDescriptor, path);
if (isValid)
{
return true;
}
}

return false;
#else
// We have no way to expand wildcards. Just assume that we would need
// View permissions for whatever events are involved.
ConcreteClusterPath clusterPath(aEndpoint, aCluster->clusterId);
return CanAccessEvent(aSubjectDescriptor, clusterPath, Access::Privilege::kView);
#endif
}

ConcreteEventPath path(aEndpoint, aCluster->clusterId, aEventPath.mEventId);
if (CheckEventSupportStatus(path) != Status::Success)
{
// Not an existing event path.
return false;
}
return CanAccessEvent(aSubjectDescriptor, path);
}

/**
* Helper to handle wildcard clusters in the event path.
*/
static bool HasValidEventPathForEndpoint(EndpointId aEndpoint, const EventPathParams & aEventPath,
const Access::SubjectDescriptor & aSubjectDescriptor)
{
if (aEventPath.HasWildcardClusterId())
{
auto * endpointType = emberAfFindEndpointType(aEndpoint);
if (endpointType == nullptr)
{
// Not going to have any valid paths in here.
return false;
}

for (decltype(endpointType->clusterCount) idx = 0; idx < endpointType->clusterCount; ++idx)
{
bool hasValidPath =
HasValidEventPathForEndpointAndCluster(aEndpoint, &endpointType->cluster[idx], aEventPath, aSubjectDescriptor);
if (hasValidPath)
{
return true;
}
}

return false;
}

auto * cluster = emberAfFindServerCluster(aEndpoint, aEventPath.mClusterId);
if (cluster == nullptr)
{
// Nothing valid here.
return false;
}
return HasValidEventPathForEndpointAndCluster(aEndpoint, cluster, aEventPath, aSubjectDescriptor);
}

CHIP_ERROR InteractionModelEngine::ParseEventPaths(const Access::SubjectDescriptor & aSubjectDescriptor,
EventPathIBs::Parser & aEventPathListParser, bool & aHasValidEventPath,
size_t & aRequestedEventPathCount)
Expand Down Expand Up @@ -670,6 +575,9 @@ CHIP_ERROR InteractionModelEngine::ParseEventPaths(const Access::SubjectDescript
continue;
}

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

if (err == CHIP_ERROR_END_OF_TLV)
Expand Down
5 changes: 2 additions & 3 deletions src/app/InteractionModelEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,9 +470,8 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,
*
* aRequestedEventPathCount will be updated to reflect the number of event paths in the request.
*/
static CHIP_ERROR ParseEventPaths(const Access::SubjectDescriptor & aSubjectDescriptor,
EventPathIBs::Parser & aEventPathListParser, bool & aHasValidEventPath,
size_t & aRequestedEventPathCount);
CHIP_ERROR ParseEventPaths(const Access::SubjectDescriptor & aSubjectDescriptor, EventPathIBs::Parser & aEventPathListParser,
bool & aHasValidEventPath, size_t & aRequestedEventPathCount);

/**
* Called when Interaction Model receives a Read Request message. Errors processing
Expand Down
2 changes: 1 addition & 1 deletion src/app/codegen-data-model-provider/BUILD.gn
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Copyright (c) 2024 Project CHIP Authors
#

# 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
Expand Down
31 changes: 31 additions & 0 deletions src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,25 @@
*/
#include <app/codegen-data-model-provider/CodegenDataModelProvider.h>

#include <access/AccessControl.h>
#include <app-common/zap-generated/attribute-type.h>
#include <app/CommandHandlerInterface.h>
#include <app/CommandHandlerInterfaceRegistry.h>
#include <app/ConcreteClusterPath.h>
#include <app/ConcreteCommandPath.h>
#include <app/EventPathParams.h>
#include <app/RequiredPrivilege.h>
#include <app/data-model-provider/MetadataTypes.h>
#include <app/util/IMClusterCommandHandler.h>
#include <app/util/af-types.h>
#include <app/util/attribute-storage.h>
#include <app/util/endpoint-config-api.h>
#include <lib/core/CHIPError.h>
#include <lib/core/DataModelTypes.h>

// separated out for code-reuse
#include <app/ember_coupling/EventPathValidity.mixin.h>

#include <optional>
#include <variant>

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

bool CodegenDataModelProvider::EventPathIncludesAccessibleConcretePath(const EventPathParams & path,
const Access::SubjectDescriptor & descriptor)
{

if (!path.HasWildcardEndpointId())
{
// No need to check whether the endpoint is enabled, because
// emberAfFindEndpointType returns null for disabled endpoints.
return HasValidEventPathForEndpoint(path.mEndpointId, path, descriptor);
}

for (uint16_t endpointIndex = 0; endpointIndex < emberAfEndpointCount(); ++endpointIndex)
{
if (!emberAfEndpointIndexIsEnabled(endpointIndex))
{
continue;
}
if (HasValidEventPathForEndpoint(emberAfEndpointFromIndex(endpointIndex), path, descriptor))
{
return true;
}
}
return false;
}

} // namespace app
} // namespace chip
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class CodegenDataModelProvider : public chip::app::DataModel::Provider
return CHIP_NO_ERROR;
}

bool EventPathIncludesAccessibleConcretePath(const EventPathParams & path,
const Access::SubjectDescriptor & descriptor) override;
DataModel::ActionReturnStatus ReadAttribute(const DataModel::ReadAttributeRequest & request,
AttributeValueEncoder & encoder) override;
DataModel::ActionReturnStatus WriteAttribute(const DataModel::WriteAttributeRequest & request,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* limitations under the License.
*/
#include <app/codegen-data-model-provider/CodegenDataModelProvider.h>
#include <app/util/attribute-storage.h>

#include <access/AccessControl.h>
#include <app-common/zap-generated/attribute-type.h>
Expand All @@ -29,6 +28,7 @@
#include <app/util/attribute-metadata.h>
#include <app/util/attribute-storage-detail.h>
#include <app/util/attribute-storage-null-handling.h>
#include <app/util/attribute-storage.h>
#include <app/util/attribute-table-detail.h>
#include <app/util/attribute-table.h>
#include <app/util/ember-io-storage.h>
Expand Down
1 change: 1 addition & 0 deletions src/app/codegen-data-model-provider/model.gni
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ codegen_data_model_SOURCES = [
codegen_data_model_PUBLIC_DEPS = [
"${chip_root}/src/app/common:attribute-type",
"${chip_root}/src/app/data-model-provider",
"${chip_root}/src/app/ember_coupling",
"${chip_root}/src/app/codegen-data-model-provider:instance-header",
]
12 changes: 12 additions & 0 deletions src/app/data-model-provider/Provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
#pragma once

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

/// Validates that the given event path is supported, where path may contain wildcards.
///
/// If any wild cards exist on the given path, the implementation is expected to validate
/// that an accessible event path exists on some wildcard expansion.
///
/// At the very minimum this will validate that a valid endpoint/cluster can be expanded
/// from the input path and that the given descriptor has access to it.
virtual bool EventPathIncludesAccessibleConcretePath(const EventPathParams & path,
const Access::SubjectDescriptor & descriptor) = 0;

/// TEMPORARY/TRANSITIONAL requirement for transitioning from ember-specific code
/// ReadAttribute is REQUIRED to perform:
/// - ACL validation (see notes on OperationFlags::kInternal)
Expand Down
23 changes: 23 additions & 0 deletions src/app/ember_coupling/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) 2024 Project CHIP Authors
#
# 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.

import("//build_overrides/chip.gni")

# The sources in this directory exist to limit the amount of code duplication
# and assume strong ember and access coupling
#
# They are NOT stand-alone compilable and are rather for `#include` support.
source_set("ember_coupling") {
sources = [ "EventPathValidity.mixin.h" ]
}
Loading

0 comments on commit 4627689

Please sign in to comment.