Skip to content

Commit

Permalink
Refactor ACL persistent storage and events (#17357)
Browse files Browse the repository at this point in the history
* Refactor ACL storage

Refactor ACL persistent storage so it's in the server layer between the
system layer (below it) and the cluster layer (above it).

Refactor events using a new listener.

Slightly reorder server layer initialization (e.g. access control
system layer should initialize before cluster layer).

Issue #14451 (and more)

* Add subject descriptor to access control APIs

Needed for event attribution.

* More improvements

* Fix function docs

* Preserve deleted entry for notification (event)

* Calculate proper storage buffer size

* Address clang-tidy complaint

* Revert change to server init log strings

These are detected by the test harness. :-(

* Minor nits from review

* Inject dependencies into AclStorage

PersistentStorageDelegate and FabricTable are injected now.

* Address feedback from review

Mostly clarifying docs, removing a few unused functions that were
missed, etc.

* Remove obsolete include

* Add a different include to replace obsolete one
  • Loading branch information
mlepage-google authored Apr 29, 2022
1 parent 3005462 commit ad2520a
Show file tree
Hide file tree
Showing 13 changed files with 1,112 additions and 714 deletions.
134 changes: 125 additions & 9 deletions src/access/AccessControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,49 @@ CHIP_ERROR AccessControl::Finish()
return retval;
}

CHIP_ERROR AccessControl::RemoveFabric(FabricIndex fabricIndex)
void AccessControl::AddEntryListener(EntryListener & listener)
{
ChipLogProgress(DataManagement, "AccessControl: removing fabric %u", fabricIndex);
if (mEntryListener == nullptr)
{
mEntryListener = &listener;
listener.mNext = nullptr;
return;
}

CHIP_ERROR err;
do
for (EntryListener * l = mEntryListener; /**/; l = l->mNext)
{
err = DeleteEntry(0, &fabricIndex);
} while (err == CHIP_NO_ERROR);
if (l == &listener)
{
return;
}

if (l->mNext == nullptr)
{
l->mNext = &listener;
listener.mNext = nullptr;
return;
}
}
}

// Sentinel error is OK, just means there was no such entry.
ReturnErrorCodeIf(err != CHIP_ERROR_SENTINEL, err);
void AccessControl::RemoveEntryListener(EntryListener & listener)
{
if (mEntryListener == &listener)
{
mEntryListener = listener.mNext;
listener.mNext = nullptr;
return;
}

return CHIP_NO_ERROR;
for (EntryListener * l = mEntryListener; l != nullptr; l = l->mNext)
{
if (l->mNext == &listener)
{
l->mNext = listener.mNext;
listener.mNext = nullptr;
return;
}
}
}

CHIP_ERROR AccessControl::Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
Expand Down Expand Up @@ -368,6 +397,84 @@ CHIP_ERROR AccessControl::Check(const SubjectDescriptor & subjectDescriptor, con
return CHIP_ERROR_ACCESS_DENIED;
}

#if CHIP_ACCESS_CONTROL_DUMP_ENABLED
CHIP_ERROR AccessControl::Dump(const Entry & entry)
{
CHIP_ERROR err;

ChipLogDetail(DataManagement, "----- BEGIN ENTRY -----");

{
FabricIndex fabricIndex;
SuccessOrExit(err = entry.GetFabricIndex(fabricIndex));
ChipLogDetail(DataManagement, "fabricIndex: %u", fabricIndex);
}

{
Privilege privilege;
SuccessOrExit(err = entry.GetPrivilege(privilege));
ChipLogDetail(DataManagement, "privilege: %d", to_underlying(privilege));
}

{
AuthMode authMode;
SuccessOrExit(err = entry.GetAuthMode(authMode));
ChipLogDetail(DataManagement, "authMode: %d", to_underlying(authMode));
}

{
size_t count;
SuccessOrExit(err = entry.GetSubjectCount(count));
if (count)
{
ChipLogDetail(DataManagement, "subjects: %u", static_cast<unsigned>(count));
for (size_t i = 0; i < count; ++i)
{
NodeId subject;
SuccessOrExit(err = entry.GetSubject(i, subject));
ChipLogDetail(DataManagement, " %u: 0x" ChipLogFormatX64, static_cast<unsigned>(i), ChipLogValueX64(subject));
}
}
}

{
size_t count;
SuccessOrExit(err = entry.GetTargetCount(count));
if (count)
{
ChipLogDetail(DataManagement, "targets: %u", static_cast<unsigned>(count));
for (size_t i = 0; i < count; ++i)
{
Entry::Target target;
SuccessOrExit(err = entry.GetTarget(i, target));
if (target.flags & Entry::Target::kCluster)
{
ChipLogDetail(DataManagement, " %u: cluster: 0x" ChipLogFormatMEI, static_cast<unsigned>(i),
ChipLogValueMEI(target.cluster));
}
if (target.flags & Entry::Target::kEndpoint)
{
ChipLogDetail(DataManagement, " %u: endpoint: %u", static_cast<unsigned>(i), target.endpoint);
}
if (target.flags & Entry::Target::kDeviceType)
{
ChipLogDetail(DataManagement, " %u: deviceType: 0x" ChipLogFormatMEI, static_cast<unsigned>(i),
ChipLogValueMEI(target.deviceType));
}
}
}
}

ChipLogDetail(DataManagement, "----- END ENTRY -----");

return CHIP_NO_ERROR;

exit:
ChipLogError(DataManagement, "AccessControl: dump failed %" CHIP_ERROR_FORMAT, err.Format());
return err;
}
#endif

bool AccessControl::IsValid(const Entry & entry)
{
const char * log = "unexpected error";
Expand Down Expand Up @@ -436,6 +543,15 @@ bool AccessControl::IsValid(const Entry & entry)
return false;
}

void AccessControl::NotifyEntryChanged(const SubjectDescriptor * subjectDescriptor, FabricIndex fabric, size_t index,
const Entry * entry, EntryListener::ChangeType changeType)
{
for (EntryListener * listener = mEntryListener; listener != nullptr; listener = listener->mNext)
{
listener->OnEntryChanged(subjectDescriptor, fabric, index, entry, changeType);
}
}

AccessControl & GetAccessControl()
{
return *globalAccessControl;
Expand Down
Loading

0 comments on commit ad2520a

Please sign in to comment.