Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example implementation of access control #11550

Merged
merged 23 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4008c6b
Add full implementation of access control
mlepage-google Nov 8, 2021
ba57c95
Fix configuration
mlepage-google Nov 8, 2021
9405ff3
Address code review comments
mlepage-google Nov 9, 2021
77130a4
Restyled by clang-format
restyled-commits Nov 9, 2021
efbc851
Merge branch 'master' into access-control-delegate
mlepage-google Nov 9, 2021
374cc54
Address code review comments
mlepage-google Nov 10, 2021
2061acc
Add tests for fabric filtered indexing
mlepage-google Nov 11, 2021
0bc0ec7
Restyled by clang-format
restyled-commits Nov 11, 2021
5246b6a
Merge branch 'master' into HEAD
mlepage-google Nov 11, 2021
a1bf4da
Address code review comments
mlepage-google Nov 11, 2021
1de1315
Add docs and comments
mlepage-google Nov 11, 2021
6f37b35
Restyled by whitespace
restyled-commits Nov 11, 2021
034ff9c
Restyled by clang-format
restyled-commits Nov 11, 2021
f357aa2
Merge branch 'master' into access-control-delegate
mlepage-google Nov 12, 2021
34b3edd
Some code review suggestions
mlepage-google Nov 12, 2021
32456e6
Restyled by clang-format
restyled-commits Nov 12, 2021
a4f4418
Fix errors on other compilers
mlepage-google Nov 12, 2021
057b27c
Merge branch 'master' into access-control-delegate
mlepage-google Nov 12, 2021
06b8834
Fix more build errors on other compilers
mlepage-google Nov 12, 2021
df20d99
More code review suggestions
mlepage-google Nov 12, 2021
b9cf23b
Restyled by clang-format
restyled-commits Nov 12, 2021
e877fc9
Merge branch 'master' into access-control-delegate
mlepage-google Nov 12, 2021
3cc4171
Fix typo in config flag
mlepage-google Nov 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 118 additions & 59 deletions src/access/AccessControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,92 +23,151 @@ namespace {
using chip::FabricIndex;
using namespace chip::Access;

// Avoid GetAccessControl returning nullptr before SetAccessControl is called.
class UnimplementedDataProvider : public AccessControlDataProvider
AccessControl defaultAccessControl;
AccessControl * globalAccessControl = &defaultAccessControl;

static_assert(((unsigned(Privilege::kAdminister) & unsigned(Privilege::kManage)) == 0) &&
((unsigned(Privilege::kAdminister) & unsigned(Privilege::kOperate)) == 0) &&
((unsigned(Privilege::kAdminister) & unsigned(Privilege::kView)) == 0) &&
((unsigned(Privilege::kAdminister) & unsigned(Privilege::kProxyView)) == 0) &&
((unsigned(Privilege::kManage) & unsigned(Privilege::kOperate)) == 0) &&
((unsigned(Privilege::kManage) & unsigned(Privilege::kView)) == 0) &&
((unsigned(Privilege::kManage) & unsigned(Privilege::kProxyView)) == 0) &&
((unsigned(Privilege::kOperate) & unsigned(Privilege::kView)) == 0) &&
((unsigned(Privilege::kOperate) & unsigned(Privilege::kProxyView)) == 0) &&
((unsigned(Privilege::kView) & unsigned(Privilege::kProxyView)) == 0),
"Privilege bits must be unique");

bool CheckRequestPrivilegeAgainstEntryPrivilege(Privilege requestPrivilege, Privilege entryPrivilege)
{
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;
switch (entryPrivilege)
{
case Privilege::kView:
return requestPrivilege == Privilege::kView;
case Privilege::kProxyView:
return requestPrivilege == Privilege::kProxyView || requestPrivilege == Privilege::kView;
case Privilege::kOperate:
return requestPrivilege == Privilege::kOperate || requestPrivilege == Privilege::kView;
case Privilege::kManage:
return requestPrivilege == Privilege::kManage || requestPrivilege == Privilege::kOperate ||
requestPrivilege == Privilege::kView;
case Privilege::kAdminister:
return requestPrivilege == Privilege::kAdminister || requestPrivilege == Privilege::kManage ||
requestPrivilege == Privilege::kOperate || requestPrivilege == Privilege::kView ||
requestPrivilege == Privilege::kProxyView;
}
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

} // namespace

namespace chip {
namespace Access {

AccessControl::Entry::Delegate AccessControl::Entry::mDefaultDelegate;
AccessControl::EntryIterator::Delegate AccessControl::EntryIterator::mDefaultDelegate;
AccessControl::Delegate AccessControl::mDefaultDelegate;
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

CHIP_ERROR AccessControl::Init()
{
ChipLogDetail(DataManagement, "access control: initializing");
// ...
return CHIP_NO_ERROR;
ChipLogDetail(DataManagement, "AccessControl::Init");
return mDelegate.Init();
}

void AccessControl::Finish()
CHIP_ERROR AccessControl::Finish()
{
ChipLogDetail(DataManagement, "access control: finishing");
// ...
ChipLogDetail(DataManagement, "AccessControl::Finish");
return mDelegate.Finish();
}

CHIP_ERROR AccessControl::Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath, Privilege privilege)
CHIP_ERROR AccessControl::Check(const SubjectDescriptor & subjectDescriptor, const RequestPath & requestPath,
Privilege requestPrivilege)
{
CHIP_ERROR err = CHIP_ERROR_ACCESS_DENIED;
EntryIterator iterator;
ReturnErrorOnFailure(Entries(iterator, &subjectDescriptor.fabricIndex));

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())
Entry entry;
while (iterator.Next(entry) == CHIP_NO_ERROR)
{
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]))
AuthMode authMode = AuthMode::kNone;
ReturnErrorOnFailure(entry.GetAuthMode(authMode));
if (authMode != subjectDescriptor.authMode)
{
continue;
ChipLogDetail(DataManagement, " --> matched subject");
if (!entry->MatchesTarget(requestPath.endpoint, requestPath.cluster))
continue;
ChipLogDetail(DataManagement, " --> matched target");
}

err = CHIP_NO_ERROR;
break;
Privilege privilege = Privilege::kView;
ReturnErrorOnFailure(entry.GetPrivilege(privilege));
if (!CheckRequestPrivilegeAgainstEntryPrivilege(requestPrivilege, privilege))
{
continue;
}

size_t subjectCount = 0;
ReturnErrorOnFailure(entry.GetSubjectCount(subjectCount));
if (subjectCount > 0)
{
mlepage-google marked this conversation as resolved.
Show resolved Hide resolved
bool subjectMatched = false;
for (size_t i = 0; i < subjectCount; ++i)
{
NodeId subject = kUndefinedNodeId;
ReturnErrorOnFailure(entry.GetSubject(i, subject));
if (subject == subjectDescriptor.subjects[0])
{
subjectMatched = true;
break;
}
// TODO: check against CATs in subject descriptor
}
if (!subjectMatched)
{
continue;
}
}

size_t targetCount = 0;
ReturnErrorOnFailure(entry.GetTargetCount(targetCount));
if (targetCount > 0)
{
bool targetMatched = false;
for (size_t i = 0; i < targetCount; ++i)
{
Entry::Target target;
ReturnErrorOnFailure(entry.GetTarget(i, target));
if ((target.flags & Entry::Target::kCluster) && target.cluster != requestPath.cluster)
{
continue;
}
if ((target.flags & Entry::Target::kEndpoint) && target.endpoint != requestPath.endpoint)
{
continue;
}
// TODO: check against target.deviceType (requires lookup)
targetMatched = true;
break;
}
if (!targetMatched)
{
continue;
}
}

// Entry passed all checks: access is allowed.
return CHIP_NO_ERROR;
}

iterator->Release();
return err;
// No entry was found which passed all checks: access is denied.
return CHIP_ERROR_ACCESS_DENIED;
mlepage-google marked this conversation as resolved.
Show resolved Hide resolved
}

AccessControl * GetAccessControl()
AccessControl & GetAccessControl()
{
return gAccessControl;
return *globalAccessControl;
}

void SetAccessControl(AccessControl * accessControl)
void SetAccessControl(AccessControl & accessControl)
{
if (accessControl != nullptr)
{
gAccessControl = accessControl;
}
globalAccessControl = &accessControl;
}

} // namespace Access
Expand Down
Loading