From 10833319296c43d3768d776170af5ba5a94d1704 Mon Sep 17 00:00:00 2001 From: Andy Salisbury Date: Tue, 21 Dec 2021 09:17:14 -0500 Subject: [PATCH] Add persistent storage for the example ACL implementation. (#12814) It uses a persistent storage delegate to store the data as a TLV-formatted blob. Platforms or applications that want content-aware storage can either implement a persistent storage delegate that reads the TLV-formatted blob or implement the AccessControl::Delegate interface. * Copy the AccessControlEntryCodec to the access folder. Make it independent of the cluster constants. * Replace the access control cluster's entry codec. Now it uses the generic codec, and defines a set of constants to use. * Update the persistence for the example ACL delegate to use the entry codec. Also includes fixes suggested by Boris Zbarsky. * Fixes from testing. * Style fixes. --- src/access/AccessControlEntryCodec.h | 333 ++++++++++++++++++ src/access/BUILD.gn | 1 + .../examples/ExampleAccessControlDelegate.cpp | 128 ++++++- .../examples/ExampleAccessControlDelegate.h | 3 + .../access-control-server.cpp | 298 ++-------------- src/lib/support/DefaultStorageKeyAllocator.h | 5 + 6 files changed, 489 insertions(+), 279 deletions(-) create mode 100644 src/access/AccessControlEntryCodec.h diff --git a/src/access/AccessControlEntryCodec.h b/src/access/AccessControlEntryCodec.h new file mode 100644 index 00000000000000..541ff4c1735ec1 --- /dev/null +++ b/src/access/AccessControlEntryCodec.h @@ -0,0 +1,333 @@ +/* + * + * Copyright (c) 2021 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. + */ +#pragma once + +#include +#include +#include + +namespace chip { +namespace Access { + +struct AccessControlEntryCodecConstants +{ + uint32_t encodedAuthPase; + uint32_t encodedAuthCase; + uint32_t encodedAuthGroup; + uint32_t encodedPrivilegeView; + uint32_t encodedPrivilegeProxyView; + uint32_t encodedPrivilegeOperate; + uint32_t encodedPrivilegeManage; + uint32_t encodedPrivilegeAdminister; + + TLV::Tag fabricIndexTag; + TLV::Tag privilegeTag; + TLV::Tag authModeTag; + TLV::Tag subjectsTag; + TLV::Tag targetsTag; + + TLV::Tag targetClusterTag; + TLV::Tag targetEndpointTag; + TLV::Tag targetDeviceTypeTag; +}; +static_assert(std::is_trivially_copyable::value, "Constants type must be trivially copyable"); + +template +class AccessControlEntryCodec +{ +public: + static_assert(std::is_base_of::value, + "T must inherit from AccessControlEntryCodecConstants"); + + AccessControlEntryCodec() : mConstants(T()) {} + + CHIP_ERROR Convert(AuthMode from, uint32_t & to) const + { + switch (from) + { + case AuthMode::kPase: + to = mConstants.encodedAuthPase; + break; + case AuthMode::kCase: + to = mConstants.encodedAuthCase; + break; + case AuthMode::kGroup: + to = mConstants.encodedAuthGroup; + break; + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + return CHIP_NO_ERROR; + } + + CHIP_ERROR Convert(uint32_t from, AuthMode & to) const + { + if (from == mConstants.encodedAuthPase) + { + to = AuthMode::kPase; + } + else if (from == mConstants.encodedAuthCase) + { + to = AuthMode::kCase; + } + else if (from == mConstants.encodedAuthGroup) + { + to = AuthMode::kGroup; + } + else + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + return CHIP_NO_ERROR; + } + + CHIP_ERROR Convert(Privilege from, uint32_t & to) const + { + switch (from) + { + case Privilege::kView: + to = mConstants.encodedPrivilegeView; + break; + case Privilege::kProxyView: + to = mConstants.encodedPrivilegeProxyView; + break; + case Privilege::kOperate: + to = mConstants.encodedPrivilegeOperate; + break; + case Privilege::kManage: + to = mConstants.encodedPrivilegeManage; + break; + case Privilege::kAdminister: + to = mConstants.encodedPrivilegeAdminister; + break; + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + return CHIP_NO_ERROR; + } + + CHIP_ERROR Convert(uint32_t from, Privilege & to) const + { + if (from == mConstants.encodedPrivilegeView) + { + to = Privilege::kView; + } + else if (from == mConstants.encodedPrivilegeProxyView) + { + to = Privilege::kProxyView; + } + else if (from == mConstants.encodedPrivilegeOperate) + { + to = Privilege::kOperate; + } + else if (from == mConstants.encodedPrivilegeManage) + { + to = Privilege::kManage; + } + else if (from == mConstants.encodedPrivilegeAdminister) + { + to = Privilege::kAdminister; + } + else + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + return CHIP_NO_ERROR; + } + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const + { + TLV::TLVType accessControlEntryContainer; + ReturnErrorOnFailure(aWriter.StartContainer(aTag, TLV::kTLVType_Structure, accessControlEntryContainer)); + { + FabricIndex fabricIndex; + ReturnErrorOnFailure(entry.GetFabricIndex(fabricIndex)); + ReturnErrorOnFailure(aWriter.Put(mConstants.fabricIndexTag, fabricIndex)); + } + { + Privilege privilege; + ReturnErrorOnFailure(entry.GetPrivilege(privilege)); + uint32_t privilegeTemp; + ReturnErrorOnFailure(Convert(privilege, privilegeTemp)); + ReturnErrorOnFailure(aWriter.Put(mConstants.privilegeTag, privilegeTemp)); + } + { + AuthMode authMode; + ReturnErrorOnFailure(entry.GetAuthMode(authMode)); + uint32_t authModeTemp; + ReturnErrorOnFailure(Convert(authMode, authModeTemp)); + ReturnErrorOnFailure(aWriter.Put(mConstants.authModeTag, authModeTemp)); + } + { + size_t count = 0; + ReturnErrorOnFailure(entry.GetSubjectCount(count)); + if (count > 0) + { + TLV::TLVType subjectsContainer; + ReturnErrorOnFailure(aWriter.StartContainer(mConstants.subjectsTag, TLV::kTLVType_Array, subjectsContainer)); + for (size_t i = 0; i < count; ++i) + { + NodeId subject; + ReturnErrorOnFailure(entry.GetSubject(i, subject)); + ReturnErrorOnFailure(aWriter.Put(TLV::AnonymousTag, subject)); + } + ReturnErrorOnFailure(aWriter.EndContainer(subjectsContainer)); + } + } + { + size_t count = 0; + ReturnErrorOnFailure(entry.GetTargetCount(count)); + if (count > 0) + { + TLV::TLVType targetsContainer; + ReturnErrorOnFailure(aWriter.StartContainer(mConstants.targetsTag, TLV::kTLVType_Array, targetsContainer)); + for (size_t i = 0; i < count; ++i) + { + TLV::TLVType targetContainer; + ReturnErrorOnFailure(aWriter.StartContainer(TLV::AnonymousTag, TLV::kTLVType_Structure, targetContainer)); + AccessControl::Entry::Target target; + ReturnErrorOnFailure(entry.GetTarget(i, target)); + if (target.flags & AccessControl::Entry::Target::kCluster) + { + ReturnErrorOnFailure(aWriter.Put(mConstants.targetClusterTag, target.cluster)); + } + if (target.flags & AccessControl::Entry::Target::kEndpoint) + { + ReturnErrorOnFailure(aWriter.Put(mConstants.targetEndpointTag, target.endpoint)); + } + if (target.flags & AccessControl::Entry::Target::kDeviceType) + { + ReturnErrorOnFailure(aWriter.Put(mConstants.targetDeviceTypeTag, target.deviceType)); + } + ReturnErrorOnFailure(aWriter.EndContainer(targetContainer)); + } + ReturnErrorOnFailure(aWriter.EndContainer(targetsContainer)); + } + } + ReturnErrorOnFailure(aWriter.EndContainer(accessControlEntryContainer)); + return CHIP_NO_ERROR; + } + + CHIP_ERROR Decode(TLV::TLVReader & aReader) + { + ReturnErrorOnFailure(GetAccessControl().PrepareEntry(entry)); + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVType accessControlEntryContainer; + VerifyOrReturnError(TLV::kTLVType_Structure == aReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(aReader.EnterContainer(accessControlEntryContainer)); + while ((err = aReader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(TLV::IsContextTag(aReader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + auto tag = aReader.GetTag(); + if (tag == mConstants.fabricIndexTag) + { + chip::FabricIndex fabricIndex; + ReturnErrorOnFailure(aReader.Get(fabricIndex)); + ReturnErrorOnFailure(entry.SetFabricIndex(fabricIndex)); + } + else if (tag == mConstants.privilegeTag) + { + uint32_t privilegeTemp; + ReturnErrorOnFailure(aReader.Get(privilegeTemp)); + Privilege privilege; + ReturnErrorOnFailure(Convert(privilegeTemp, privilege)); + ReturnErrorOnFailure(entry.SetPrivilege(privilege)); + } + else if (tag == mConstants.authModeTag) + { + uint32_t authModeTemp; + ReturnErrorOnFailure(aReader.Get(authModeTemp)); + AuthMode authMode; + ReturnErrorOnFailure(Convert(authModeTemp, authMode)); + ReturnErrorOnFailure(entry.SetAuthMode(authMode)); + } + else if (tag == mConstants.subjectsTag) + { + TLV::TLVType subjectsContainer; + VerifyOrReturnError(TLV::kTLVType_Array == aReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(aReader.EnterContainer(subjectsContainer)); + while ((err = aReader.Next()) == CHIP_NO_ERROR) + { + NodeId subject = kUndefinedNodeId; + ReturnErrorOnFailure(aReader.Get(subject)); + ReturnErrorOnFailure(entry.AddSubject(nullptr, subject)); + } + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(aReader.ExitContainer(subjectsContainer)); + } + else if (tag == mConstants.targetsTag) + { + TLV::TLVType targetsContainer; + VerifyOrReturnError(TLV::kTLVType_Array == aReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(aReader.EnterContainer(targetsContainer)); + while ((err = aReader.Next()) == CHIP_NO_ERROR) + { + AccessControl::Entry::Target target; + TLV::TLVType targetContainer; + VerifyOrReturnError(TLV::kTLVType_Structure == aReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); + ReturnErrorOnFailure(aReader.EnterContainer(targetContainer)); + while ((err = aReader.Next()) == CHIP_NO_ERROR) + { + VerifyOrReturnError(TLV::IsContextTag(aReader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); + auto targetTag = TLV::TagNumFromTag(aReader.GetTag()); + if (targetTag == mConstants.targetClusterTag) + { + if (aReader.GetType() != TLV::kTLVType_Null) + { + ReturnErrorOnFailure(aReader.Get(target.cluster)); + target.flags |= target.kCluster; + } + } + else if (targetTag == mConstants.targetEndpointTag) + { + if (aReader.GetType() != TLV::kTLVType_Null) + { + ReturnErrorOnFailure(aReader.Get(target.endpoint)); + target.flags |= target.kEndpoint; + } + } + else if (targetTag == mConstants.targetDeviceTypeTag) + { + if (aReader.GetType() != TLV::kTLVType_Null) + { + ReturnErrorOnFailure(aReader.Get(target.deviceType)); + target.flags |= target.kDeviceType; + } + } + } + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(aReader.ExitContainer(targetContainer)); + ReturnErrorOnFailure(entry.AddTarget(nullptr, target)); + } + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(aReader.ExitContainer(targetsContainer)); + break; + } + } + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(aReader.ExitContainer(accessControlEntryContainer)); + return CHIP_NO_ERROR; + } + + AccessControl::Entry entry; + +private: + const AccessControlEntryCodecConstants mConstants; +}; + +} // namespace Access +} // namespace chip diff --git a/src/access/BUILD.gn b/src/access/BUILD.gn index bca34a9f1a9bd3..dbea6209123eff 100644 --- a/src/access/BUILD.gn +++ b/src/access/BUILD.gn @@ -20,6 +20,7 @@ static_library("access") { sources = [ "AccessControl.cpp", "AccessControl.h", + "AccessControlEntryCodec.h", "AuthMode.h", "Privilege.h", "RequestPath.h", diff --git a/src/access/examples/ExampleAccessControlDelegate.cpp b/src/access/examples/ExampleAccessControlDelegate.cpp index f5ea7d02d0bd38..1cca4b31386752 100644 --- a/src/access/examples/ExampleAccessControlDelegate.cpp +++ b/src/access/examples/ExampleAccessControlDelegate.cpp @@ -18,7 +18,10 @@ #include "ExampleAccessControlDelegate.h" +#include #include +#include +#include #include #include @@ -1097,10 +1100,125 @@ class AccessControlDelegate : public AccessControl::Delegate bool IsTransitional() const override { return false; } +public: + void SetStorageDelegate(chip::PersistentStorageDelegate * storageDelegate) { mStorageDelegate = storageDelegate; } + private: - CHIP_ERROR LoadFromFlash() { return CHIP_NO_ERROR; } + chip::PersistentStorageDelegate * mStorageDelegate = nullptr; + + // The version of the storage data format. Increment this key when the format of the data model changes. + static const uint32_t kExampleAclStorageVersion = 1; + static const size_t kMetadataStorageBufferSize = 32; + static const size_t kEntryStorageBufferSize = 192; + static const chip::TLV::Tag kTagVersion = chip::TLV::ContextTag(1); + static const chip::TLV::Tag kTagEntryCount = chip::TLV::ContextTag(2); + + struct Constants : public chip::Access::AccessControlEntryCodecConstants + { + Constants() + { + encodedAuthPase = 1; + encodedAuthCase = 2; + encodedAuthGroup = 3; + encodedPrivilegeView = 4; + encodedPrivilegeProxyView = 5; + encodedPrivilegeOperate = 6; + encodedPrivilegeManage = 7; + encodedPrivilegeAdminister = 8; + fabricIndexTag = chip::TLV::ContextTag(1); + privilegeTag = chip::TLV::ContextTag(2); + authModeTag = chip::TLV::ContextTag(3); + subjectsTag = chip::TLV::ContextTag(4); + targetsTag = chip::TLV::ContextTag(5); + targetClusterTag = chip::TLV::ContextTag(6); + targetEndpointTag = chip::TLV::ContextTag(7); + targetDeviceTypeTag = chip::TLV::ContextTag(8); + } + }; + + CHIP_ERROR LoadFromFlash() + { + VerifyOrReturnError(mStorageDelegate != nullptr, CHIP_ERROR_INCORRECT_STATE); + + uint8_t buffer[kMetadataStorageBufferSize] = { 0 }; + uint16_t size = static_cast(sizeof(buffer)); + chip::DefaultStorageKeyAllocator key; + ReturnErrorOnFailure(mStorageDelegate->SyncGetKeyValue(key.AccessControlList(), buffer, size)); + + chip::TLV::TLVReader reader; + reader.Init(buffer, size); + + ReturnErrorOnFailure(reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag)); + + chip::TLV::TLVType container; + ReturnErrorOnFailure(reader.EnterContainer(container)); - CHIP_ERROR SaveToFlash() { return CHIP_NO_ERROR; } + // Version + ReturnErrorOnFailure(reader.Next(kTagVersion)); + uint32_t version; + ReturnErrorOnFailure(reader.Get(version)); + VerifyOrReturnError(version == kExampleAclStorageVersion, CHIP_ERROR_VERSION_MISMATCH); + + // Entry count + ReturnErrorOnFailure(reader.Next(kTagEntryCount)); + uint32_t entryCount; + ReturnErrorOnFailure(reader.Get(entryCount)); + + for (auto & storage : EntryStorage::acl) + { + storage.Clear(); + } + + // Entries + chip::Access::AccessControlEntryCodec codec; + for (size_t i = 0; i < entryCount; ++i) + { + uint8_t entryBuffer[kEntryStorageBufferSize] = { 0 }; + uint16_t bufferSize = static_cast(sizeof(buffer)); + ReturnErrorOnFailure(mStorageDelegate->SyncGetKeyValue(key.AccessControlEntry(i), entryBuffer, bufferSize)); + chip::TLV::TLVReader entryReader; + entryReader.Init(entryBuffer, bufferSize); + ReturnErrorOnFailure(entryReader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag)); + ReturnErrorOnFailure(codec.Decode(entryReader)); + ReturnErrorOnFailure(CreateEntry(nullptr, codec.entry, nullptr)); + } + return reader.ExitContainer(container); + } + + CHIP_ERROR SaveToFlash() + { + VerifyOrReturnError(mStorageDelegate != nullptr, CHIP_ERROR_INCORRECT_STATE); + + uint8_t buffer[kMetadataStorageBufferSize] = { 0 }; + chip::TLV::TLVWriter writer; + writer.Init(buffer); + chip::DefaultStorageKeyAllocator key; + chip::TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(chip::TLV::AnonymousTag, chip::TLV::TLVType::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.Put(kTagVersion, kExampleAclStorageVersion)); + + size_t entryCount; + ReturnErrorOnFailure(GetEntryCount(entryCount)); + ReturnErrorOnFailure(writer.Put(kTagEntryCount, static_cast(entryCount))); + + ReturnErrorOnFailure(writer.EndContainer(container)); + ReturnErrorOnFailure(writer.Finalize()); + + chip::Access::AccessControlEntryCodec codec; + for (size_t i = 0; i < entryCount; ++i) + { + uint8_t entryBuffer[kEntryStorageBufferSize] = { 0 }; + chip::TLV::TLVWriter entryWriter; + entryWriter.Init(entryBuffer); + ReturnErrorOnFailure(ReadEntry(i, codec.entry, nullptr)); + ReturnErrorOnFailure(codec.Encode(entryWriter, chip::TLV::AnonymousTag)); + ReturnErrorOnFailure(entryWriter.Finalize()); + ReturnErrorOnFailure(mStorageDelegate->SyncSetKeyValue(key.AccessControlEntry(i), entryBuffer, + static_cast(entryWriter.GetLengthWritten()))); + } + + return mStorageDelegate->SyncSetKeyValue(key.AccessControlList(), buffer, static_cast(writer.GetLengthWritten())); + } }; static_assert(std::is_pod(), "Storage type must be POD"); @@ -1124,6 +1242,12 @@ AccessControl::Delegate & GetAccessControlDelegate() return accessControlDelegate; } +void SetAccessControlDelegateStorage(chip::PersistentStorageDelegate * storageDelegate) +{ + AccessControlDelegate & accessControlDelegate = static_cast(GetAccessControlDelegate()); + accessControlDelegate.SetStorageDelegate(storageDelegate); +} + } // namespace Examples } // namespace Access } // namespace chip diff --git a/src/access/examples/ExampleAccessControlDelegate.h b/src/access/examples/ExampleAccessControlDelegate.h index f411de1339df3c..e2a3bd04d913e3 100644 --- a/src/access/examples/ExampleAccessControlDelegate.h +++ b/src/access/examples/ExampleAccessControlDelegate.h @@ -17,6 +17,7 @@ #pragma once #include "access/AccessControl.h" +#include namespace chip { namespace Access { @@ -24,6 +25,8 @@ namespace Examples { AccessControl::Delegate & GetAccessControlDelegate(); +void SetAccessControlDelegateStorage(chip::PersistentStorageDelegate * storageDelegate); + } // namespace Examples } // namespace Access } // namespace chip diff --git a/src/app/clusters/access-control-server/access-control-server.cpp b/src/app/clusters/access-control-server/access-control-server.cpp index bc60dbafc08477..36ae21cde4a9e0 100644 --- a/src/app/clusters/access-control-server/access-control-server.cpp +++ b/src/app/clusters/access-control-server/access-control-server.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -37,284 +38,27 @@ namespace AccessControlCluster = chip::app::Clusters::AccessControl; namespace { -struct AccessControlEntryCodec +struct Constants : public AccessControlEntryCodecConstants { - static CHIP_ERROR Convert(AuthMode from, AccessControlCluster::AuthMode & to) + Constants() { - switch (from) - { - case AuthMode::kPase: - to = AccessControlCluster::AuthMode::kPase; - break; - case AuthMode::kCase: - to = AccessControlCluster::AuthMode::kCase; - break; - case AuthMode::kGroup: - to = AccessControlCluster::AuthMode::kGroup; - break; - default: - return CHIP_ERROR_INVALID_ARGUMENT; - } - return CHIP_NO_ERROR; - } - - static CHIP_ERROR Convert(AccessControlCluster::AuthMode from, AuthMode & to) - { - switch (from) - { - case AccessControlCluster::AuthMode::kPase: - to = AuthMode::kPase; - break; - case AccessControlCluster::AuthMode::kCase: - to = AuthMode::kCase; - break; - case AccessControlCluster::AuthMode::kGroup: - to = AuthMode::kGroup; - break; - default: - return CHIP_ERROR_INVALID_ARGUMENT; - } - return CHIP_NO_ERROR; - } - - static CHIP_ERROR Convert(Privilege from, AccessControlCluster::Privilege & to) - { - switch (from) - { - case Privilege::kView: - to = AccessControlCluster::Privilege::kView; - break; - case Privilege::kProxyView: - to = AccessControlCluster::Privilege::kProxyView; - break; - case Privilege::kOperate: - to = AccessControlCluster::Privilege::kOperate; - break; - case Privilege::kManage: - to = AccessControlCluster::Privilege::kManage; - break; - case Privilege::kAdminister: - to = AccessControlCluster::Privilege::kAdminister; - break; - default: - return CHIP_ERROR_INVALID_ARGUMENT; - } - return CHIP_NO_ERROR; - } - - static CHIP_ERROR Convert(AccessControlCluster::Privilege from, Privilege & to) - { - switch (from) - { - case AccessControlCluster::Privilege::kView: - to = Privilege::kView; - break; - case AccessControlCluster::Privilege::kProxyView: - to = Privilege::kProxyView; - break; - case AccessControlCluster::Privilege::kOperate: - to = Privilege::kOperate; - break; - case AccessControlCluster::Privilege::kManage: - to = Privilege::kManage; - break; - case AccessControlCluster::Privilege::kAdminister: - to = Privilege::kAdminister; - break; - default: - return CHIP_ERROR_INVALID_ARGUMENT; - } - return CHIP_NO_ERROR; + encodedAuthPase = static_cast(AccessControlCluster::AuthMode::kPase); + encodedAuthCase = static_cast(AccessControlCluster::AuthMode::kCase); + encodedAuthGroup = static_cast(AccessControlCluster::AuthMode::kGroup); + encodedPrivilegeView = static_cast(AccessControlCluster::Privilege::kView); + encodedPrivilegeProxyView = static_cast(AccessControlCluster::Privilege::kProxyView); + encodedPrivilegeOperate = static_cast(AccessControlCluster::Privilege::kOperate); + encodedPrivilegeManage = static_cast(AccessControlCluster::Privilege::kManage); + encodedPrivilegeAdminister = static_cast(AccessControlCluster::Privilege::kAdminister); + fabricIndexTag = TLV::ContextTag(to_underlying(AccessControlCluster::Structs::AccessControlEntry::Fields::kFabricIndex)); + privilegeTag = TLV::ContextTag(to_underlying(AccessControlCluster::Structs::AccessControlEntry::Fields::kPrivilege)); + authModeTag = TLV::ContextTag(to_underlying(AccessControlCluster::Structs::AccessControlEntry::Fields::kAuthMode)); + subjectsTag = TLV::ContextTag(to_underlying(AccessControlCluster::Structs::AccessControlEntry::Fields::kSubjects)); + targetsTag = TLV::ContextTag(to_underlying(AccessControlCluster::Structs::AccessControlEntry::Fields::kTargets)); + targetClusterTag = TLV::ContextTag(to_underlying(AccessControlCluster::Structs::Target::Fields::kCluster)); + targetEndpointTag = TLV::ContextTag(to_underlying(AccessControlCluster::Structs::Target::Fields::kEndpoint)); + targetDeviceTypeTag = TLV::ContextTag(to_underlying(AccessControlCluster::Structs::Target::Fields::kDeviceType)); } - - CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const - { - TLV::TLVType accessControlEntryContainer; - ReturnErrorOnFailure(aWriter.StartContainer(aTag, TLV::kTLVType_Structure, accessControlEntryContainer)); - using Fields = AccessControlCluster::Structs::AccessControlEntry::Fields; - { - FabricIndex fabricIndex; - ReturnErrorOnFailure(entry.GetFabricIndex(fabricIndex)); - ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(to_underlying(Fields::kFabricIndex)), fabricIndex)); - } - { - Privilege privilege; - ReturnErrorOnFailure(entry.GetPrivilege(privilege)); - AccessControlCluster::Privilege privilegeTemp; - ReturnErrorOnFailure(Convert(privilege, privilegeTemp)); - ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(to_underlying(Fields::kPrivilege)), privilegeTemp)); - } - { - AuthMode authMode; - ReturnErrorOnFailure(entry.GetAuthMode(authMode)); - AccessControlCluster::AuthMode authModeTemp; - ReturnErrorOnFailure(Convert(authMode, authModeTemp)); - ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(to_underlying(Fields::kAuthMode)), authModeTemp)); - } - { - size_t count = 0; - ReturnErrorOnFailure(entry.GetSubjectCount(count)); - if (count > 0) - { - TLV::TLVType subjectsContainer; - ReturnErrorOnFailure(aWriter.StartContainer(TLV::ContextTag(to_underlying(Fields::kSubjects)), TLV::kTLVType_Array, - subjectsContainer)); - for (size_t i = 0; i < count; ++i) - { - NodeId subject; - ReturnErrorOnFailure(entry.GetSubject(i, subject)); - ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::AnonymousTag, subject)); - } - ReturnErrorOnFailure(aWriter.EndContainer(subjectsContainer)); - } - } - { - size_t count = 0; - ReturnErrorOnFailure(entry.GetTargetCount(count)); - if (count > 0) - { - TLV::TLVType targetsContainer; - ReturnErrorOnFailure(aWriter.StartContainer(TLV::ContextTag(to_underlying(Fields::kTargets)), TLV::kTLVType_Array, - targetsContainer)); - using TargetFields = AccessControlCluster::Structs::Target::Fields; - for (size_t i = 0; i < count; ++i) - { - TLV::TLVType targetContainer; - ReturnErrorOnFailure(aWriter.StartContainer(TLV::AnonymousTag, TLV::kTLVType_Structure, targetContainer)); - AccessControl::Entry::Target target; - ReturnErrorOnFailure(entry.GetTarget(i, target)); - if (target.flags & AccessControl::Entry::Target::kCluster) - { - ReturnErrorOnFailure( - DataModel::Encode(aWriter, TLV::ContextTag(to_underlying(TargetFields::kCluster)), target.cluster)); - } - if (target.flags & AccessControl::Entry::Target::kEndpoint) - { - ReturnErrorOnFailure( - DataModel::Encode(aWriter, TLV::ContextTag(to_underlying(TargetFields::kEndpoint)), target.endpoint)); - } - if (target.flags & AccessControl::Entry::Target::kDeviceType) - { - ReturnErrorOnFailure(DataModel::Encode(aWriter, TLV::ContextTag(to_underlying(TargetFields::kDeviceType)), - target.deviceType)); - } - ReturnErrorOnFailure(aWriter.EndContainer(targetContainer)); - } - ReturnErrorOnFailure(aWriter.EndContainer(targetsContainer)); - } - } - ReturnErrorOnFailure(aWriter.EndContainer(accessControlEntryContainer)); - return CHIP_NO_ERROR; - } - - CHIP_ERROR Decode(TLV::TLVReader & aReader) - { - ReturnErrorOnFailure(GetAccessControl().PrepareEntry(entry)); - CHIP_ERROR err = CHIP_NO_ERROR; - TLV::TLVType accessControlEntryContainer; - VerifyOrReturnError(TLV::kTLVType_Structure == aReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); - ReturnErrorOnFailure(aReader.EnterContainer(accessControlEntryContainer)); - using Fields = AccessControlCluster::Structs::AccessControlEntry::Fields; - while ((err = aReader.Next()) == CHIP_NO_ERROR) - { - VerifyOrReturnError(TLV::IsContextTag(aReader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); - switch (TLV::TagNumFromTag(aReader.GetTag())) - { - case to_underlying(Fields::kFabricIndex): { - chip::FabricIndex fabricIndex; - ReturnErrorOnFailure(DataModel::Decode(aReader, fabricIndex)); - ReturnErrorOnFailure(entry.SetFabricIndex(fabricIndex)); - break; - } - case to_underlying(Fields::kPrivilege): { - AccessControlCluster::Privilege privilegeTemp; - ReturnErrorOnFailure(DataModel::Decode(aReader, privilegeTemp)); - Privilege privilege; - ReturnErrorOnFailure(Convert(privilegeTemp, privilege)); - ReturnErrorOnFailure(entry.SetPrivilege(privilege)); - break; - } - case to_underlying(Fields::kAuthMode): { - AccessControlCluster::AuthMode authModeTemp; - ReturnErrorOnFailure(DataModel::Decode(aReader, authModeTemp)); - AuthMode authMode; - ReturnErrorOnFailure(Convert(authModeTemp, authMode)); - ReturnErrorOnFailure(entry.SetAuthMode(authMode)); - break; - } - case to_underlying(Fields::kSubjects): { - TLV::TLVType subjectsContainer; - VerifyOrReturnError(TLV::kTLVType_Array == aReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); - ReturnErrorOnFailure(aReader.EnterContainer(subjectsContainer)); - while ((err = aReader.Next()) == CHIP_NO_ERROR) - { - NodeId subject = kUndefinedNodeId; - ReturnErrorOnFailure(DataModel::Decode(aReader, subject)); - ReturnErrorOnFailure(entry.AddSubject(nullptr, subject)); - } - VerifyOrReturnError(err == CHIP_END_OF_TLV, err); - ReturnErrorOnFailure(aReader.ExitContainer(subjectsContainer)); - break; - } - case to_underlying(Fields::kTargets): { - TLV::TLVType targetsContainer; - VerifyOrReturnError(TLV::kTLVType_Array == aReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); - ReturnErrorOnFailure(aReader.EnterContainer(targetsContainer)); - while ((err = aReader.Next()) == CHIP_NO_ERROR) - { - AccessControl::Entry::Target target; - TLV::TLVType targetContainer; - VerifyOrReturnError(TLV::kTLVType_Structure == aReader.GetType(), CHIP_ERROR_WRONG_TLV_TYPE); - ReturnErrorOnFailure(aReader.EnterContainer(targetContainer)); - using TargetFields = AccessControlCluster::Structs::Target::Fields; - while ((err = aReader.Next()) == CHIP_NO_ERROR) - { - VerifyOrReturnError(TLV::IsContextTag(aReader.GetTag()), CHIP_ERROR_INVALID_TLV_TAG); - switch (TLV::TagNumFromTag(aReader.GetTag())) - { - case to_underlying(TargetFields::kCluster): - if (aReader.GetType() != TLV::kTLVType_Null) - { - ReturnErrorOnFailure(DataModel::Decode(aReader, target.cluster)); - target.flags |= target.kCluster; - } - break; - case to_underlying(TargetFields::kEndpoint): - if (aReader.GetType() != TLV::kTLVType_Null) - { - ReturnErrorOnFailure(DataModel::Decode(aReader, target.endpoint)); - target.flags |= target.kEndpoint; - } - break; - case to_underlying(TargetFields::kDeviceType): - if (aReader.GetType() != TLV::kTLVType_Null) - { - ReturnErrorOnFailure(DataModel::Decode(aReader, target.deviceType)); - target.flags |= target.kDeviceType; - } - break; - default: - break; - } - } - VerifyOrReturnError(err == CHIP_END_OF_TLV, err); - ReturnErrorOnFailure(aReader.ExitContainer(targetContainer)); - ReturnErrorOnFailure(entry.AddTarget(nullptr, target)); - } - VerifyOrReturnError(err == CHIP_END_OF_TLV, err); - ReturnErrorOnFailure(aReader.ExitContainer(targetsContainer)); - break; - } - default: - break; - } - } - VerifyOrReturnError(err == CHIP_END_OF_TLV, err); - ReturnErrorOnFailure(aReader.ExitContainer(accessControlEntryContainer)); - return CHIP_NO_ERROR; - } - - AccessControl::Entry entry; }; class AccessControlAttribute : public chip::app::AttributeAccessInterface @@ -353,7 +97,7 @@ CHIP_ERROR AccessControlAttribute::Read(const ConcreteReadAttributePath & aPath, CHIP_ERROR AccessControlAttribute::ReadAcl(AttributeValueEncoder & aEncoder) { - AccessControlEntryCodec codec; + AccessControlEntryCodec codec; AccessControl::EntryIterator iterator; ReturnErrorOnFailure(GetAccessControl().Entries(iterator)); @@ -389,7 +133,7 @@ CHIP_ERROR AccessControlAttribute::Write(const ConcreteDataAttributePath & aPath CHIP_ERROR AccessControlAttribute::WriteAcl(AttributeValueDecoder & aDecoder) { - DataModel::DecodableList list; + DataModel::DecodableList> list; ReturnErrorOnFailure(aDecoder.Decode(list)); size_t oldCount; diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index 4a8ada7e653b72..4846a04139d2e9 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -34,6 +34,11 @@ class DefaultStorageKeyAllocator const char * FabricTable(chip::FabricIndex fabric) { return Format("f/%x/t", fabric); } + // Access Control List + + const char * AccessControlList() { return Format("acl"); } + const char * AccessControlEntry(size_t index) { return Format("acl/%x", index); } + // Group Data Provider const char * FabricGroups(chip::FabricIndex fabric) { return Format("f/%x/g", fabric); }