-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial prototype of AccessControl module (#10579)
* Add initial prototype of AccessControl module - Not complete, always allows actions - Not hooked up to interaction model or messaging layer - Progress toward issues #10236 and #10249 - Fully isolated as a module - Has unit tests * Remove file comments from files * Add 'k' prefix to enum values * Restyled by whitespace * Restyled by clang-format * Restyled by gn * Remove "empty" .cpp files * Apply suggestions from code review * Apply suggestions from code review * Fix compatibility under different compilers * Fix unit test compatability on different compilers * Restyled by clang-format * Change forward declaration to include Allows tooling to detect circular dependencies. * Changes from code review suggestions - rename namespace access --> Access - rename DataProvider --> AccessControlDataProvider - decouple DataProvider lifecycle (Init/Finish) - rename DataProviderImpl --> ExampleAccessControlDataProvider - change GetInstance/SetInstance to global functions - remove Config.h since global instance must be set - change EntryIterator::Next to return pointer - add comments to Privilege and AuthMode - remove SubjectDescriptor.isCommissioning for now - improve naming of CAT subjects in SubjectDescriptor - change SubjectId typedef to use NodeId * Make tests table-driven Should also fix some build complaints on ESP32 * Restyled by clang-format * Restyle * Add more metatesting Ensure not just that results are correct, but that they were correctly obtained. * Restyled by clang-format * Change enums to enum classes * Address review comments * Use basic types in lib/core Basic types (FabricIndex etc.) were moved in PR #10925 from app to lib/core, so now they can be used from this module. * A bit of cleanup * Refactor SubjectId and SubjectDescriptor Also, remove CatId and move PasscodeId into lib/core. * Restyled by clang-format * Add clarifying examples to documentation. Co-authored-by: Restyled.io <[email protected]>
- Loading branch information
1 parent
4b6486f
commit d3e76ec
Showing
15 changed files
with
1,238 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/* | ||
* | ||
* Copyright (c) 2021 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* 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. | ||
*/ | ||
|
||
#include "AccessControl.h" | ||
|
||
namespace { | ||
|
||
using chip::FabricIndex; | ||
using namespace chip::Access; | ||
|
||
// Avoid GetAccessControl returning nullptr before SetAccessControl is called. | ||
class UnimplementedDataProvider : public AccessControlDataProvider | ||
{ | ||
CHIP_ERROR Init() override { return CHIP_NO_ERROR; } | ||
|
||
void Finish() override {} | ||
|
||
EntryIterator * Entries() const override { return nullptr; } | ||
|
||
EntryIterator * Entries(FabricIndex fabricIndex) const override { return nullptr; } | ||
}; | ||
|
||
// Avoid GetAccessControl returning nullptr before SetAccessControl is called. | ||
UnimplementedDataProvider gUnimplementedDataProvider; | ||
AccessControl gUnimplementedAccessControl(gUnimplementedDataProvider); | ||
|
||
AccessControl * gAccessControl = &gUnimplementedAccessControl; | ||
|
||
} // namespace | ||
|
||
namespace chip { | ||
namespace Access { | ||
|
||
CHIP_ERROR AccessControl::Init() | ||
{ | ||
ChipLogDetail(DataManagement, "access control: initializing"); | ||
// ... | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
void AccessControl::Finish() | ||
{ | ||
ChipLogDetail(DataManagement, "access control: finishing"); | ||
// ... | ||
} | ||
|
||
CHIP_ERROR AccessControl::Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath, Privilege privilege) | ||
{ | ||
CHIP_ERROR err = CHIP_ERROR_ACCESS_DENIED; | ||
|
||
EntryIterator * iterator = mDataProvider.Entries(subjectDescriptor.fabricIndex); | ||
// TODO: check error (but can't until we have an implementation) | ||
#if 0 | ||
ReturnErrorCodeIf(iterator == nullptr, CHIP_ERROR_INTERNAL); | ||
#else | ||
ReturnErrorCodeIf(iterator == nullptr, CHIP_NO_ERROR); | ||
#endif | ||
|
||
// TODO: a few more cases (PASE commissioning, CASE Authenticated Tags, etc.) | ||
|
||
while (auto entry = iterator->Next()) | ||
{ | ||
ChipLogDetail(DataManagement, "Checking entry"); | ||
|
||
if (!entry->MatchesPrivilege(privilege)) | ||
continue; | ||
ChipLogDetail(DataManagement, " --> matched privilege"); | ||
if (!entry->MatchesAuthMode(subjectDescriptor.authMode)) | ||
continue; | ||
ChipLogDetail(DataManagement, " --> matched authmode"); | ||
if (!entry->MatchesSubject(subjectDescriptor.subjects[0])) | ||
continue; | ||
ChipLogDetail(DataManagement, " --> matched subject"); | ||
if (!entry->MatchesTarget(requestPath.endpoint, requestPath.cluster)) | ||
continue; | ||
ChipLogDetail(DataManagement, " --> matched target"); | ||
|
||
err = CHIP_NO_ERROR; | ||
break; | ||
} | ||
|
||
iterator->Release(); | ||
return err; | ||
} | ||
|
||
AccessControl * GetAccessControl() | ||
{ | ||
return gAccessControl; | ||
} | ||
|
||
void SetAccessControl(AccessControl * accessControl) | ||
{ | ||
if (accessControl != nullptr) | ||
{ | ||
gAccessControl = accessControl; | ||
} | ||
} | ||
|
||
} // namespace Access | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* | ||
* Copyright (c) 2021 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* 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 "AccessControlDataProvider.h" | ||
#include "Privilege.h" | ||
#include "RequestPath.h" | ||
#include "SubjectDescriptor.h" | ||
|
||
#include <lib/core/CHIPCore.h> | ||
|
||
namespace chip { | ||
namespace Access { | ||
|
||
class AccessControl | ||
{ | ||
public: | ||
/** | ||
* Create an access control module. Must be initialized before use, and | ||
* deinitialized when finished. Must be configured with an | ||
* AccessControlDataProvider, which must outlive this module. | ||
*/ | ||
AccessControl(AccessControlDataProvider & dataProvider) : mDataProvider(dataProvider) {} | ||
|
||
AccessControl(const AccessControl &) = delete; | ||
AccessControl & operator=(const AccessControl &) = delete; | ||
|
||
/** | ||
* Initialize the access control module. Must be called before first use. | ||
* | ||
* @retval various errors, probably fatal. | ||
*/ | ||
CHIP_ERROR Init(); | ||
|
||
/** | ||
* Deinitialize the access control module. Must be called when finished. | ||
*/ | ||
void Finish(); | ||
|
||
/** | ||
* Check whether access (by a subject descriptor, to a request path, | ||
* requiring a privilege) should be allowed or denied. | ||
* | ||
* @retval #CHIP_ERROR_ACCESS_DENIED if denied. | ||
* @retval other errors should also be treated as denied. | ||
* @retval #CHIP_NO_ERROR if allowed. | ||
*/ | ||
CHIP_ERROR Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath, Privilege privilege); | ||
|
||
private: | ||
AccessControlDataProvider & mDataProvider; | ||
}; | ||
|
||
/** | ||
* Instance getter for the global AccessControl. | ||
* | ||
* Callers have to externally synchronize usage of this function. | ||
* | ||
* @return The global AccessControl instance. Assume never null. | ||
*/ | ||
AccessControl * GetAccessControl(); | ||
|
||
/** | ||
* Instance setter for the global AccessControl. | ||
* | ||
* Callers have to externally synchronize usage of this function. | ||
* | ||
* @param[in] accessControl the instance to start returning with the getter; | ||
* if nullptr, no change occurs. | ||
*/ | ||
void SetAccessControl(AccessControl * accessControl); | ||
|
||
} // namespace Access | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
* | ||
* Copyright (c) 2021 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* 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 "AuthMode.h" | ||
#include "Privilege.h" | ||
#include "SubjectDescriptor.h" | ||
|
||
#include <lib/core/CHIPCore.h> | ||
#include <lib/core/DataModelTypes.h> | ||
|
||
namespace chip { | ||
namespace Access { | ||
|
||
class Entry | ||
{ | ||
public: | ||
virtual ~Entry() = default; | ||
|
||
/** | ||
* Whether the auth mode matches the entry. Must be called before calling | ||
* MatchesSubject. | ||
*/ | ||
virtual bool MatchesAuthMode(AuthMode authMode) const = 0; | ||
|
||
/** | ||
* Whether the fabric matches the entry. Entries with fabric index 0 will | ||
* match all fabrics. | ||
*/ | ||
virtual bool MatchesFabric(FabricIndex fabricIndex) const = 0; | ||
|
||
/** | ||
* Whether the privilege matches the entry, including subsumed privileges. | ||
* E.g. both Privilege::kOperate and Privilege::kView will match an entry | ||
* with Privilege::kOperate, but Privilege::kManage will not match such an | ||
* entry. | ||
*/ | ||
virtual bool MatchesPrivilege(Privilege privilege) const = 0; | ||
|
||
/** | ||
* Whether the subject matches the entry. Must only be called if auth mode | ||
* matches. | ||
*/ | ||
virtual bool MatchesSubject(SubjectId subject) const = 0; | ||
|
||
/** | ||
* Whether the target matches the entry. Some entries may match all | ||
* endpoints or all clusters. | ||
*/ | ||
virtual bool MatchesTarget(EndpointId endpoint, ClusterId cluster) const = 0; | ||
}; | ||
|
||
class EntryIterator | ||
{ | ||
public: | ||
/** | ||
* Create an entry iterator. Must call release when finished. | ||
*/ | ||
EntryIterator() = default; | ||
|
||
virtual ~EntryIterator() = default; | ||
|
||
/** | ||
* Returns the next entry, or nullptr if there is no next entry. | ||
*/ | ||
virtual Entry * Next() = 0; | ||
|
||
/** | ||
* Release the iterator. Must be called when finished. | ||
*/ | ||
virtual void Release() = 0; | ||
}; | ||
|
||
class AccessControlDataProvider | ||
{ | ||
public: | ||
/** | ||
* Create a data provider. Must be initialized before use, and deinitialized | ||
* when finished. | ||
*/ | ||
AccessControlDataProvider() = default; | ||
|
||
virtual ~AccessControlDataProvider() = default; | ||
|
||
AccessControlDataProvider(const AccessControlDataProvider &) = delete; | ||
AccessControlDataProvider & operator=(const AccessControlDataProvider &) = delete; | ||
|
||
/** | ||
* Initialize the data provider. | ||
* | ||
* @retval various errors, probably fatal. | ||
*/ | ||
virtual CHIP_ERROR Init() = 0; | ||
|
||
/** | ||
* Deinitialize the data provider. | ||
*/ | ||
virtual void Finish() = 0; | ||
|
||
/** | ||
* Get an iterator over all entries. | ||
* | ||
* @retval iterator, release when finished. | ||
* @retval nullptr if error, probably fatal, generally should not happen. | ||
*/ | ||
virtual EntryIterator * Entries() const = 0; | ||
|
||
/** | ||
* Get an iterator over all entries for a particular fabric. | ||
* | ||
* @retval iterator, release when finished. | ||
* @retval nullptr if error, probably fatal, generally should not happen. | ||
*/ | ||
virtual EntryIterator * Entries(FabricIndex fabricIndex) const = 0; | ||
}; | ||
|
||
} // namespace Access | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/* | ||
* | ||
* Copyright (c) 2021 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* 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 | ||
|
||
namespace chip { | ||
namespace Access { | ||
|
||
// Using bitfield values so auth mode and privilege set can be stored together. | ||
// Auth mode should have only one value expressed, which should not be None. | ||
enum class AuthMode | ||
{ | ||
kNone = 0, | ||
kPase = 1 << 5, | ||
kCase = 1 << 6, | ||
kGroup = 1 << 7 | ||
}; | ||
|
||
} // namespace Access | ||
} // namespace chip |
Oops, something went wrong.