Skip to content

Commit

Permalink
Managed ACL: Add AccessRestrictionList support (#34932)
Browse files Browse the repository at this point in the history
* Add AccessRestrictionList support

* Update src/access/AccessConfig.h

Co-authored-by: C Freeman <cecille@google.com>

* Reworked data manipulators and other cleanup

* Fixed encode/decode so reading CommissioningARL and Arl attributes work

* Reworked ARL storage

Previously ARL related data was persisted in KVS.  This has been
removed and now the responsibility for managing/maintaining the
related data (CommissioningARL and ARL attributes) is up to the
app to set on AccessRestrictionProvider class.

* Review fixes

cleanup ArlEncoder interface.
return error to client if arl review request fails
return token to client in FabricRestrictionReviewUpdate

* Fixed GetEntries vector pointer arg

* Updated core restriction logic/integration

* Restyled by clang-format

* fixed include check for renamed AccessRestrictionProvider.h file

* M-ACL updates

- refactored AccessControl::Check into CheckACL and CheckARL
- added placeholders for the upcoming CHIP_ERROR_ACCESS_RESTRICTED_BY_ARL
- extracted ARL exception processing to standalone class for better
  testing

* Add plumbing for subject descriptor IsCommissioning field

- Make session manager update that state on a message-per-message basis
- Add tests

Missing test: MRP test against a not-yet-committed fabric over CASE showing
that IsCommissioning is true.

* Fix crash

* Use new IsCommissioning in ARL check

* Updates for review comments

* restyled

* Review updates

- fixed return type for some command failures
- enhanced unit tests

* restyled

* Updated ARL tests per review comments

* work around nuttx and jsoncpp contention

* Review comments and nuttx build failure fix attempt

* review updates

---------

Co-authored-by: C Freeman <cecille@google.com>
Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: tennessee.carmelveilleux@gmail.com <tennessee.carmelveilleux@gmail.com>
  • Loading branch information
4 people authored Aug 27, 2024
1 parent 32c961f commit 87f6277
Show file tree
Hide file tree
Showing 40 changed files with 2,349 additions and 63 deletions.
3 changes: 3 additions & 0 deletions examples/network-manager-app/linux/args.gni
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ chip_project_config_include_dirs = [
]

chip_config_network_layer_ble = false

# This enables AccessRestrictionList (ARL) support used by the NIM sample app
chip_enable_access_restrictions = true
Original file line number Diff line number Diff line change
Expand Up @@ -1623,16 +1623,23 @@ endpoint 0 {
server cluster AccessControl {
emits event AccessControlEntryChanged;
emits event AccessControlExtensionChanged;
emits event AccessRestrictionEntryChanged;
emits event FabricRestrictionReviewUpdate;
callback attribute acl;
callback attribute extension;
callback attribute subjectsPerAccessControlEntry;
callback attribute targetsPerAccessControlEntry;
callback attribute accessControlEntriesPerFabric;
callback attribute commissioningARL;
callback attribute arl;
callback attribute generatedCommandList;
callback attribute acceptedCommandList;
callback attribute attributeList;
ram attribute featureMap default = 0;
ram attribute featureMap default = 1;
callback attribute clusterRevision;

handle command ReviewFabricRestrictions;
handle command ReviewFabricRestrictionsResponse;
}

server cluster BasicInformation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,24 @@
"define": "ACCESS_CONTROL_CLUSTER",
"side": "server",
"enabled": 1,
"commands": [
{
"name": "ReviewFabricRestrictions",
"code": 0,
"mfgCode": null,
"source": "client",
"isIncoming": 1,
"isEnabled": 1
},
{
"name": "ReviewFabricRestrictionsResponse",
"code": 1,
"mfgCode": null,
"source": "server",
"isIncoming": 0,
"isEnabled": 1
}
],
"attributes": [
{
"name": "ACL",
Expand Down Expand Up @@ -395,6 +413,38 @@
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "CommissioningARL",
"code": 5,
"mfgCode": null,
"side": "server",
"type": "array",
"included": 1,
"storageOption": "External",
"singleton": 0,
"bounded": 0,
"defaultValue": null,
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "ARL",
"code": 6,
"mfgCode": null,
"side": "server",
"type": "array",
"included": 1,
"storageOption": "External",
"singleton": 0,
"bounded": 0,
"defaultValue": "",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
"reportableChange": 0
},
{
"name": "GeneratedCommandList",
"code": 65528,
Expand Down Expand Up @@ -453,7 +503,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0",
"defaultValue": "1",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
Expand Down Expand Up @@ -490,6 +540,20 @@
"mfgCode": null,
"side": "server",
"included": 1
},
{
"name": "AccessRestrictionEntryChanged",
"code": 2,
"mfgCode": null,
"side": "server",
"included": 1
},
{
"name": "FabricRestrictionReviewUpdate",
"code": 3,
"mfgCode": null,
"side": "server",
"included": 1
}
]
},
Expand Down
27 changes: 27 additions & 0 deletions examples/platform/linux/AppMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@
#include "AppMain.h"
#include "CommissionableInit.h"

#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
#include "ExampleAccessRestrictionProvider.h"
#endif

#if CHIP_DEVICE_LAYER_TARGET_DARWIN
#include <platform/Darwin/NetworkCommissioningDriver.h>
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI
Expand All @@ -121,6 +125,7 @@ using namespace chip::DeviceLayer;
using namespace chip::Inet;
using namespace chip::Transport;
using namespace chip::app::Clusters;
using namespace chip::Access;

// Network comissioning implementation
namespace {
Expand Down Expand Up @@ -180,6 +185,10 @@ Optional<app::Clusters::NetworkCommissioning::Instance> sWiFiNetworkCommissionin
app::Clusters::NetworkCommissioning::Instance sEthernetNetworkCommissioningInstance(kRootEndpointId, &sEthernetDriver);
#endif // CHIP_APP_MAIN_HAS_ETHERNET_DRIVER

#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
auto exampleAccessRestrictionProvider = std::make_unique<ExampleAccessRestrictionProvider>();
#endif

void EnableThreadNetworkCommissioning()
{
#if CHIP_APP_MAIN_HAS_THREAD_DRIVER
Expand Down Expand Up @@ -593,9 +602,27 @@ void ChipLinuxAppMainLoop(AppMainLoopImplementation * impl)
chip::app::RuntimeOptionsProvider::Instance().SetSimulateNoInternalTime(
LinuxDeviceOptions::GetInstance().mSimulateNoInternalTime);

#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
initParams.accessRestrictionProvider = exampleAccessRestrictionProvider.get();
#endif

// Init ZCL Data Model and CHIP App Server
Server::GetInstance().Init(initParams);

#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
if (LinuxDeviceOptions::GetInstance().commissioningArlEntries.HasValue())
{
exampleAccessRestrictionProvider->SetCommissioningEntries(
LinuxDeviceOptions::GetInstance().commissioningArlEntries.Value());
}

if (LinuxDeviceOptions::GetInstance().arlEntries.HasValue())
{
// This example use of the ARL feature proactively installs the provided entries on fabric index 1
exampleAccessRestrictionProvider->SetEntries(1, LinuxDeviceOptions::GetInstance().arlEntries.Value());
}
#endif

#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
// Set ReadHandler Capacity for Subscriptions
chip::app::InteractionModelEngine::GetInstance()->SetHandlerCapacityForSubscriptions(
Expand Down
8 changes: 8 additions & 0 deletions examples/platform/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import("${chip_root}/src/lib/core/core.gni")
import("${chip_root}/src/lib/lib.gni")
import("${chip_root}/src/tracing/tracing_args.gni")

if (current_os != "nuttx") {
import("//build_overrides/jsoncpp.gni")
}

declare_args() {
chip_enable_smoke_co_trigger = false
chip_enable_boolean_state_configuration_trigger = false
Expand Down Expand Up @@ -101,6 +105,10 @@ source_set("app-main") {
"${chip_root}/src/app/server",
]

if (current_os != "nuttx") {
public_deps += [ jsoncpp_root ]
}

if (chip_enable_pw_rpc) {
defines += [ "PW_RPC_ENABLED" ]
}
Expand Down
55 changes: 55 additions & 0 deletions examples/platform/linux/ExampleAccessRestrictionProvider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
*
* Copyright (c) 2024 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.
*/

/*
* AccessRestriction implementation for Linux examples.
*/

#pragma once

#include <access/AccessRestrictionProvider.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app/EventLogging.h>

namespace chip {
namespace Access {

class ExampleAccessRestrictionProvider : public AccessRestrictionProvider
{
public:
ExampleAccessRestrictionProvider() : AccessRestrictionProvider() {}

~ExampleAccessRestrictionProvider() {}

protected:
CHIP_ERROR DoRequestFabricRestrictionReview(const FabricIndex fabricIndex, uint64_t token, const std::vector<Entry> & arl)
{
// this example simply removes all restrictions and will generate AccessRestrictionEntryChanged events
Access::GetAccessControl().GetAccessRestrictionProvider()->SetEntries(fabricIndex, std::vector<Entry>{});

chip::app::Clusters::AccessControl::Events::FabricRestrictionReviewUpdate::Type event{ .token = token,
.fabricIndex = fabricIndex };
EventNumber eventNumber;
ReturnErrorOnFailure(chip::app::LogEvent(event, kRootEndpointId, eventNumber));

return CHIP_NO_ERROR;
}
};

} // namespace Access
} // namespace chip
77 changes: 77 additions & 0 deletions examples/platform/linux/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <app/server/OnboardingCodesUtil.h>

#include <crypto/CHIPCryptoPAL.h>
#include <json/json.h>
#include <lib/core/CHIPError.h>
#include <lib/support/Base64.h>
#include <lib/support/BytesToHex.h>
Expand All @@ -47,6 +48,11 @@

using namespace chip;
using namespace chip::ArgParser;
using namespace chip::Platform;

#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
using namespace chip::Access;
#endif

namespace {
LinuxDeviceOptions gDeviceOptions;
Expand Down Expand Up @@ -82,6 +88,10 @@ enum
kDeviceOption_TraceFile,
kDeviceOption_TraceLog,
kDeviceOption_TraceDecode,
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
kDeviceOption_CommissioningArlEntries,
kDeviceOption_ArlEntries,
#endif
kOptionCSRResponseCSRIncorrectType,
kOptionCSRResponseCSRNonceIncorrectType,
kOptionCSRResponseCSRNonceTooLong,
Expand Down Expand Up @@ -154,6 +164,10 @@ OptionDef sDeviceOptionDefs[] = {
{ "trace_log", kArgumentRequired, kDeviceOption_TraceLog },
{ "trace_decode", kArgumentRequired, kDeviceOption_TraceDecode },
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
{ "commissioning-arl-entries", kArgumentRequired, kDeviceOption_CommissioningArlEntries },
{ "arl-entries", kArgumentRequired, kDeviceOption_ArlEntries },
#endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
{ "cert_error_csr_incorrect_type", kNoArgument, kOptionCSRResponseCSRIncorrectType },
{ "cert_error_csr_existing_keypair", kNoArgument, kOptionCSRResponseCSRExistingKeyPair },
{ "cert_error_csr_nonce_incorrect_type", kNoArgument, kOptionCSRResponseCSRNonceIncorrectType },
Expand Down Expand Up @@ -280,6 +294,14 @@ const char * sDeviceOptionHelp =
" --trace_decode <1/0>\n"
" A value of 1 enables traces decoding, 0 disables this (default 0).\n"
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
" --commissioning-arl-entries <CommissioningARL JSON>\n"
" Enable ACL cluster access restrictions used during commissioning with the provided JSON. Example:\n"
" \"[{\\\"endpoint\\\": 1,\\\"cluster\\\": 1105,\\\"restrictions\\\": [{\\\"type\\\": 0,\\\"id\\\": 0}]}]\"\n"
" --arl-entries <ARL JSON>\n"
" Enable ACL cluster access restrictions applied to fabric index 1 with the provided JSON. Example:\n"
" \"[{\\\"endpoint\\\": 1,\\\"cluster\\\": 1105,\\\"restrictions\\\": [{\\\"type\\\": 0,\\\"id\\\": 0}]}]\"\n"
#endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
" --cert_error_csr_incorrect_type\n"
" Configure the CSRResponse to be built with an invalid CSR type.\n"
" --cert_error_csr_existing_keypair\n"
Expand Down Expand Up @@ -320,6 +342,39 @@ const char * sDeviceOptionHelp =
#endif
"\n";

#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
bool ParseAccessRestrictionEntriesFromJson(const char * jsonString, std::vector<AccessRestrictionProvider::Entry> & entries)
{
Json::Value root;
Json::Reader reader;
VerifyOrReturnValue(reader.parse(jsonString, root), false);

for (Json::Value::const_iterator eIt = root.begin(); eIt != root.end(); eIt++)
{
AccessRestrictionProvider::Entry entry;

entry.endpointNumber = static_cast<EndpointId>((*eIt)["endpoint"].asUInt());
entry.clusterId = static_cast<ClusterId>((*eIt)["cluster"].asUInt());

Json::Value restrictions = (*eIt)["restrictions"];
for (Json::Value::const_iterator rIt = restrictions.begin(); rIt != restrictions.end(); rIt++)
{
AccessRestrictionProvider::Restriction restriction;
restriction.restrictionType = static_cast<AccessRestrictionProvider::Type>((*rIt)["type"].asUInt());
if ((*rIt).isMember("id"))
{
restriction.id.SetValue((*rIt)["id"].asUInt());
}
entry.restrictions.push_back(restriction);
}

entries.push_back(entry);
}

return true;
}
#endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS

bool Base64ArgToVector(const char * arg, size_t maxSize, std::vector<uint8_t> & outVector)
{
size_t maxBase64Size = BASE64_ENCODED_LEN(maxSize);
Expand Down Expand Up @@ -529,6 +584,28 @@ bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier,
break;
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED

#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
// TODO(#35189): change to use a path to JSON files instead
case kDeviceOption_CommissioningArlEntries: {
std::vector<AccessRestrictionProvider::Entry> entries;
retval = ParseAccessRestrictionEntriesFromJson(aValue, entries);
if (retval)
{
LinuxDeviceOptions::GetInstance().commissioningArlEntries.SetValue(std::move(entries));
}
}
break;
case kDeviceOption_ArlEntries: {
std::vector<AccessRestrictionProvider::Entry> entries;
retval = ParseAccessRestrictionEntriesFromJson(aValue, entries);
if (retval)
{
LinuxDeviceOptions::GetInstance().arlEntries.SetValue(std::move(entries));
}
}
break;
#endif // CHIP_CONFIG_USE_ACCESS_RESTRICTIONS

case kOptionCSRResponseCSRIncorrectType:
LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrIncorrectType = true;
break;
Expand Down
Loading

0 comments on commit 87f6277

Please sign in to comment.