Skip to content

Commit 5ad899a

Browse files
Update ACL API to support ARL use cases (project-chip#34537)
* Update ACL API to support ARL use cases ARL needs to know what attribute/command/event is being accessed and with which interaction model action. This change brings this knowledge into the AccessControl classes Check method for further enhancement with ARL feature on top. * Addressed review comments * Addressed review comments * Clarified RequestType enum values and purpose * Renamed CanAccess to CanAccessEvent * Restyled by whitespace * Restyled by clang-format * Fixed some build issues - missed a spot to populate requestType and entityId - fix unused function definition for some cases * Fixed icd-management-server for ARL * fixed typo in previous fix :-( * Restyled by clang-format * Moved ARL related checks behind ARL feature flag Instead of validating requestType in AccessControl::Check, we will validate it is not unknown only if the ARL feature is enabled. * Add conditional ARL related validation Instead of removing ARL related validation from AccessControl::Check entirely, perform it only if the ARL feature is enabled. As of this commit, it is not enabled. * Restyled by clang-format --------- Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 972dbda commit 5ad899a

11 files changed

+115
-23
lines changed

src/access/AccessControl.cpp

+30-2
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,23 @@ char GetPrivilegeStringForLogging(Privilege privilege)
171171
return 'u';
172172
}
173173

174+
char GetRequestTypeStringForLogging(RequestType requestType)
175+
{
176+
switch (requestType)
177+
{
178+
case RequestType::kAttributeReadRequest:
179+
return 'r';
180+
case RequestType::kAttributeWriteRequest:
181+
return 'w';
182+
case RequestType::kCommandInvokeRequest:
183+
return 'i';
184+
case RequestType::kEventReadOrSubscribeRequest:
185+
return 'e';
186+
default:
187+
return '?';
188+
}
189+
}
190+
174191
#endif // CHIP_PROGRESS_LOGGING && CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
175192

176193
} // namespace
@@ -306,6 +323,11 @@ void AccessControl::RemoveEntryListener(EntryListener & listener)
306323
}
307324
}
308325

326+
bool AccessControl::IsAccessRestrictionListSupported() const
327+
{
328+
return false; // not yet supported
329+
}
330+
309331
CHIP_ERROR AccessControl::Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
310332
Privilege requestPrivilege)
311333
{
@@ -316,14 +338,20 @@ CHIP_ERROR AccessControl::Check(const SubjectDescriptor & subjectDescriptor, con
316338
constexpr size_t kMaxCatsToLog = 6;
317339
char catLogBuf[kMaxCatsToLog * kCharsPerCatForLogging];
318340
ChipLogProgress(DataManagement,
319-
"AccessControl: checking f=%u a=%c s=0x" ChipLogFormatX64 " t=%s c=" ChipLogFormatMEI " e=%u p=%c",
341+
"AccessControl: checking f=%u a=%c s=0x" ChipLogFormatX64 " t=%s c=" ChipLogFormatMEI " e=%u p=%c r=%c",
320342
subjectDescriptor.fabricIndex, GetAuthModeStringForLogging(subjectDescriptor.authMode),
321343
ChipLogValueX64(subjectDescriptor.subject),
322344
GetCatStringForLogging(catLogBuf, sizeof(catLogBuf), subjectDescriptor.cats),
323-
ChipLogValueMEI(requestPath.cluster), requestPath.endpoint, GetPrivilegeStringForLogging(requestPrivilege));
345+
ChipLogValueMEI(requestPath.cluster), requestPath.endpoint, GetPrivilegeStringForLogging(requestPrivilege),
346+
GetRequestTypeStringForLogging(requestPath.requestType));
324347
}
325348
#endif // CHIP_PROGRESS_LOGGING && CHIP_CONFIG_ACCESS_CONTROL_POLICY_LOGGING_VERBOSITY > 1
326349

350+
if (IsAccessRestrictionListSupported())
351+
{
352+
VerifyOrReturnError(requestPath.requestType != RequestType::kRequestTypeUnknown, CHIP_ERROR_INVALID_ARGUMENT);
353+
}
354+
327355
{
328356
CHIP_ERROR result = mDelegate->Check(subjectDescriptor, requestPath, requestPrivilege);
329357
if (result != CHIP_ERROR_NOT_IMPLEMENTED)

src/access/AccessControl.h

+7
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,13 @@ class AccessControl
627627
// Removes a listener from the listener list, if in the list.
628628
void RemoveEntryListener(EntryListener & listener);
629629

630+
/**
631+
* Check whether or not Access Restriction List is supported.
632+
*
633+
* @retval true if Access Restriction List is supported.
634+
*/
635+
bool IsAccessRestrictionListSupported() const;
636+
630637
/**
631638
* Check whether access (by a subject descriptor, to a request path,
632639
* requiring a privilege) should be allowed or denied.

src/access/RequestPath.h

+16-2
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,29 @@
1919
#pragma once
2020

2121
#include <lib/core/DataModelTypes.h>
22+
#include <optional>
2223

2324
namespace chip {
2425
namespace Access {
2526

27+
enum class RequestType : uint8_t
28+
{
29+
kRequestTypeUnknown,
30+
kAttributeReadRequest,
31+
kAttributeWriteRequest,
32+
kCommandInvokeRequest,
33+
kEventReadOrSubscribeRequest
34+
};
35+
2636
struct RequestPath
2737
{
2838
// NOTE: eventually this will likely also contain node, for proxying
29-
ClusterId cluster = 0;
30-
EndpointId endpoint = 0;
39+
ClusterId cluster = 0;
40+
EndpointId endpoint = 0;
41+
RequestType requestType = RequestType::kRequestTypeUnknown;
42+
43+
// entityId represents an attribute, command, or event ID, which is determined by the requestType. Wildcard if omitted.
44+
std::optional<uint32_t> entityId;
3145
};
3246

3347
} // namespace Access

src/app/CommandHandlerImpl.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,10 @@ Status CommandHandlerImpl::ProcessCommandDataIB(CommandDataIB::Parser & aCommand
402402

403403
{
404404
Access::SubjectDescriptor subjectDescriptor = GetSubjectDescriptor();
405-
Access::RequestPath requestPath{ .cluster = concretePath.mClusterId, .endpoint = concretePath.mEndpointId };
405+
Access::RequestPath requestPath{ .cluster = concretePath.mClusterId,
406+
.endpoint = concretePath.mEndpointId,
407+
.requestType = Access::RequestType::kCommandInvokeRequest,
408+
.entityId = concretePath.mCommandId };
406409
Access::Privilege requestPrivilege = RequiredPrivilege::ForInvokeCommand(concretePath);
407410
err = Access::GetAccessControl().Check(subjectDescriptor, requestPath, requestPrivilege);
408411
if (err != CHIP_NO_ERROR)
@@ -548,7 +551,10 @@ Status CommandHandlerImpl::ProcessGroupCommandDataIB(CommandDataIB::Parser & aCo
548551

549552
{
550553
Access::SubjectDescriptor subjectDescriptor = GetSubjectDescriptor();
551-
Access::RequestPath requestPath{ .cluster = concretePath.mClusterId, .endpoint = concretePath.mEndpointId };
554+
Access::RequestPath requestPath{ .cluster = concretePath.mClusterId,
555+
.endpoint = concretePath.mEndpointId,
556+
.requestType = Access::RequestType::kCommandInvokeRequest,
557+
.entityId = concretePath.mCommandId };
552558
Access::Privilege requestPrivilege = RequiredPrivilege::ForInvokeCommand(concretePath);
553559
err = Access::GetAccessControl().Check(subjectDescriptor, requestPath, requestPrivilege);
554560
if (err != CHIP_NO_ERROR)

src/app/EventManagement.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,10 @@ CHIP_ERROR EventManagement::CheckEventContext(EventLoadOutContext * eventLoadOut
554554

555555
ReturnErrorOnFailure(ret);
556556

557-
Access::RequestPath requestPath{ .cluster = event.mClusterId, .endpoint = event.mEndpointId };
557+
Access::RequestPath requestPath{ .cluster = event.mClusterId,
558+
.endpoint = event.mEndpointId,
559+
.requestType = Access::RequestType::kEventReadOrSubscribeRequest,
560+
.entityId = event.mEventId };
558561
Access::Privilege requestPrivilege = RequiredPrivilege::ForReadEvent(path);
559562
CHIP_ERROR accessControlError =
560563
Access::GetAccessControl().Check(eventLoadOutContext->mSubjectDescriptor, requestPath, requestPrivilege);

src/app/InteractionModelEngine.cpp

+26-10
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,10 @@ CHIP_ERROR InteractionModelEngine::ParseAttributePaths(const Access::SubjectDesc
494494
// AttributePathExpandIterator. So we just need to check the ACL bits.
495495
for (; pathIterator.Get(readPath); pathIterator.Next())
496496
{
497-
Access::RequestPath requestPath{ .cluster = readPath.mClusterId, .endpoint = readPath.mEndpointId };
497+
// leave requestPath.entityId optional value unset to indicate wildcard
498+
Access::RequestPath requestPath{ .cluster = readPath.mClusterId,
499+
.endpoint = readPath.mEndpointId,
500+
.requestType = Access::RequestType::kAttributeReadRequest };
498501
err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath,
499502
RequiredPrivilege::ForReadAttribute(readPath));
500503
if (err == CHIP_NO_ERROR)
@@ -510,7 +513,10 @@ CHIP_ERROR InteractionModelEngine::ParseAttributePaths(const Access::SubjectDesc
510513
paramsList.mValue.mAttributeId);
511514
if (ConcreteAttributePathExists(concretePath))
512515
{
513-
Access::RequestPath requestPath{ .cluster = concretePath.mClusterId, .endpoint = concretePath.mEndpointId };
516+
Access::RequestPath requestPath{ .cluster = concretePath.mClusterId,
517+
.endpoint = concretePath.mEndpointId,
518+
.requestType = Access::RequestType::kAttributeReadRequest,
519+
.entityId = paramsList.mValue.mAttributeId };
514520

515521
err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath,
516522
RequiredPrivilege::ForReadAttribute(concretePath));
@@ -532,17 +538,27 @@ CHIP_ERROR InteractionModelEngine::ParseAttributePaths(const Access::SubjectDesc
532538
return err;
533539
}
534540

535-
static bool CanAccess(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteClusterPath & aPath,
536-
Access::Privilege aNeededPrivilege)
541+
#if !CHIP_CONFIG_ENABLE_EVENTLIST_ATTRIBUTE
542+
static bool CanAccessEvent(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteClusterPath & aPath,
543+
Access::Privilege aNeededPrivilege)
537544
{
538-
Access::RequestPath requestPath{ .cluster = aPath.mClusterId, .endpoint = aPath.mEndpointId };
545+
Access::RequestPath requestPath{ .cluster = aPath.mClusterId,
546+
.endpoint = aPath.mEndpointId,
547+
.requestType = Access::RequestType::kEventReadOrSubscribeRequest };
548+
// leave requestPath.entityId optional value unset to indicate wildcard
539549
CHIP_ERROR err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, aNeededPrivilege);
540550
return (err == CHIP_NO_ERROR);
541551
}
552+
#endif
542553

543-
static bool CanAccess(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteEventPath & aPath)
554+
static bool CanAccessEvent(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteEventPath & aPath)
544555
{
545-
return CanAccess(aSubjectDescriptor, aPath, RequiredPrivilege::ForReadEvent(aPath));
556+
Access::RequestPath requestPath{ .cluster = aPath.mClusterId,
557+
.endpoint = aPath.mEndpointId,
558+
.requestType = Access::RequestType::kEventReadOrSubscribeRequest,
559+
.entityId = aPath.mEventId };
560+
CHIP_ERROR err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, RequiredPrivilege::ForReadEvent(aPath));
561+
return (err == CHIP_NO_ERROR);
546562
}
547563

548564
/**
@@ -559,7 +575,7 @@ static bool HasValidEventPathForEndpointAndCluster(EndpointId aEndpoint, const E
559575
{
560576
ConcreteEventPath path(aEndpoint, aCluster->clusterId, aCluster->eventList[idx]);
561577
// If we get here, the path exists. We just have to do an ACL check for it.
562-
bool isValid = CanAccess(aSubjectDescriptor, path);
578+
bool isValid = CanAccessEvent(aSubjectDescriptor, path);
563579
if (isValid)
564580
{
565581
return true;
@@ -571,7 +587,7 @@ static bool HasValidEventPathForEndpointAndCluster(EndpointId aEndpoint, const E
571587
// We have no way to expand wildcards. Just assume that we would need
572588
// View permissions for whatever events are involved.
573589
ConcreteClusterPath clusterPath(aEndpoint, aCluster->clusterId);
574-
return CanAccess(aSubjectDescriptor, clusterPath, Access::Privilege::kView);
590+
return CanAccessEvent(aSubjectDescriptor, clusterPath, Access::Privilege::kView);
575591
#endif
576592
}
577593

@@ -581,7 +597,7 @@ static bool HasValidEventPathForEndpointAndCluster(EndpointId aEndpoint, const E
581597
// Not an existing event path.
582598
return false;
583599
}
584-
return CanAccess(aSubjectDescriptor, path);
600+
return CanAccessEvent(aSubjectDescriptor, path);
585601
}
586602

587603
/**

src/app/clusters/icd-management-server/icd-management-server.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,10 @@ CHIP_ERROR IcdManagementAttributeAccess::ReadMaximumCheckInBackOff(EndpointId en
240240
*/
241241
CHIP_ERROR CheckAdmin(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, bool & isClientAdmin)
242242
{
243-
RequestPath requestPath{ .cluster = commandPath.mClusterId, .endpoint = commandPath.mEndpointId };
243+
RequestPath requestPath{ .cluster = commandPath.mClusterId,
244+
.endpoint = commandPath.mEndpointId,
245+
.requestType = RequestType::kCommandInvokeRequest,
246+
.entityId = commandPath.mCommandId };
244247
CHIP_ERROR err = GetAccessControl().Check(commandObj->GetSubjectDescriptor(), requestPath, Privilege::kAdminister);
245248
if (CHIP_NO_ERROR == err)
246249
{

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,10 @@ DataModel::ActionReturnStatus CodegenDataModelProvider::ReadAttribute(const Data
273273
{
274274
ReturnErrorCodeIf(!request.subjectDescriptor.has_value(), CHIP_ERROR_INVALID_ARGUMENT);
275275

276-
Access::RequestPath requestPath{ .cluster = request.path.mClusterId, .endpoint = request.path.mEndpointId };
276+
Access::RequestPath requestPath{ .cluster = request.path.mClusterId,
277+
.endpoint = request.path.mEndpointId,
278+
.requestType = Access::RequestType::kAttributeReadRequest,
279+
.entityId = request.path.mAttributeId };
277280
CHIP_ERROR err = Access::GetAccessControl().Check(*request.subjectDescriptor, requestPath,
278281
RequiredPrivilege::ForReadAttribute(request.path));
279282
if (err != CHIP_NO_ERROR)

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,10 @@ DataModel::ActionReturnStatus CodegenDataModelProvider::WriteAttribute(const Dat
278278
{
279279
ReturnErrorCodeIf(!request.subjectDescriptor.has_value(), Status::UnsupportedAccess);
280280

281-
Access::RequestPath requestPath{ .cluster = request.path.mClusterId, .endpoint = request.path.mEndpointId };
281+
Access::RequestPath requestPath{ .cluster = request.path.mClusterId,
282+
.endpoint = request.path.mEndpointId,
283+
.requestType = Access::RequestType::kAttributeWriteRequest,
284+
.entityId = request.path.mAttributeId };
282285
CHIP_ERROR err = Access::GetAccessControl().Check(*request.subjectDescriptor, requestPath,
283286
RequiredPrivilege::ForWriteAttribute(request.path));
284287

src/app/reporting/Engine.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,10 @@ CHIP_ERROR Engine::CheckAccessDeniedEventPaths(TLV::TLVWriter & aWriter, bool &
339339
aHasEncodedData = true;
340340
}
341341

342-
Access::RequestPath requestPath{ .cluster = current->mValue.mClusterId, .endpoint = current->mValue.mEndpointId };
342+
Access::RequestPath requestPath{ .cluster = current->mValue.mClusterId,
343+
.endpoint = current->mValue.mEndpointId,
344+
.requestType = RequestType::kEventReadOrSubscribeRequest,
345+
.entityId = current->mValue.mEventId };
343346
Access::Privilege requestPrivilege = RequiredPrivilege::ForReadEvent(path);
344347

345348
err = Access::GetAccessControl().Check(apReadHandler->GetSubjectDescriptor(), requestPath, requestPrivilege);

src/app/util/ember-compatibility-functions.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,10 @@ CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, b
294294
// depending on whether the path was expanded.
295295

296296
{
297-
Access::RequestPath requestPath{ .cluster = aPath.mClusterId, .endpoint = aPath.mEndpointId };
297+
Access::RequestPath requestPath{ .cluster = aPath.mClusterId,
298+
.endpoint = aPath.mEndpointId,
299+
.requestType = Access::RequestType::kAttributeReadRequest,
300+
.entityId = aPath.mAttributeId };
298301
Access::Privilege requestPrivilege = RequiredPrivilege::ForReadAttribute(aPath);
299302
CHIP_ERROR err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, requestPrivilege);
300303
if (err != CHIP_NO_ERROR)
@@ -686,7 +689,10 @@ CHIP_ERROR WriteSingleClusterData(const SubjectDescriptor & aSubjectDescriptor,
686689
}
687690

688691
{
689-
Access::RequestPath requestPath{ .cluster = aPath.mClusterId, .endpoint = aPath.mEndpointId };
692+
Access::RequestPath requestPath{ .cluster = aPath.mClusterId,
693+
.endpoint = aPath.mEndpointId,
694+
.requestType = Access::RequestType::kAttributeWriteRequest,
695+
.entityId = aPath.mAttributeId };
690696
Access::Privilege requestPrivilege = RequiredPrivilege::ForWriteAttribute(aPath);
691697
CHIP_ERROR err = CHIP_NO_ERROR;
692698
if (!apWriteHandler->ACLCheckCacheHit({ aPath, requestPrivilege }))

0 commit comments

Comments
 (0)