Skip to content

Commit

Permalink
Draft: Add configurable ep1 ACLs and bindings (#23212)
Browse files Browse the repository at this point in the history
* Draft: Add configurable ep1 ACLs and bindings

* address comments
  • Loading branch information
chrisdecenzo authored and pull[bot] committed Apr 5, 2023
1 parent f25e39f commit eb3d4e8
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 35 deletions.
13 changes: 13 additions & 0 deletions examples/tv-app/android/java/AppImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,19 @@ Access::Privilege ContentAppFactoryImpl::GetVendorPrivilege(uint16_t vendorId)
return Access::Privilege::kOperate;
}

std::list<ClusterId> ContentAppFactoryImpl::GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId,
uint16_t productId)
{
if (endpointId == kLocalVideoPlayerEndpointId)
{
return { chip::app::Clusters::Descriptor::Id, chip::app::Clusters::OnOff::Id,
chip::app::Clusters::WakeOnLan::Id, chip::app::Clusters::MediaPlayback::Id,
chip::app::Clusters::LowPower::Id, chip::app::Clusters::KeypadInput::Id,
chip::app::Clusters::ContentLauncher::Id, chip::app::Clusters::AudioOutput::Id };
}
return {};
}

} // namespace AppPlatform
} // namespace chip

Expand Down
5 changes: 5 additions & 0 deletions examples/tv-app/android/java/AppImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory
// When a vendor has admin privileges, it will get access to all clusters on ep1
Access::Privilege GetVendorPrivilege(uint16_t vendorId) override;

// Get the cluster list this vendorId/productId should have on static endpoints such as ep1 for casting video clients.
// When a vendor has admin privileges, it will get access to all clusters on ep1
std::list<ClusterId> GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId,
uint16_t productId) override;

void AddAdminVendorId(uint16_t vendorId);

void setContentAppAttributeDelegate(ContentAppAttributeDelegate * attributeDelegate);
Expand Down
95 changes: 93 additions & 2 deletions examples/tv-app/android/java/TVApp-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@
#include <lib/support/CHIPJNIError.h>
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>
#include <zap-generated/CHIPClusters.h>

using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::AppPlatform;
using namespace chip::Credentials;

Expand Down Expand Up @@ -201,9 +203,44 @@ class MyPostCommissioningListener : public PostCommissioningListener
void CommissioningCompleted(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr,
SessionHandle & sessionHandle) override
{
// read current binding list
chip::Controller::BindingCluster cluster(exchangeMgr, sessionHandle, kTargetBindingClusterEndpointId);

ContentAppPlatform::GetInstance().ManageClientAccess(
exchangeMgr, sessionHandle, vendorId, GetDeviceCommissioner()->GetNodeId(), OnSuccessResponse, OnFailureResponse);
cacheContext(vendorId, productId, nodeId, exchangeMgr, sessionHandle);

CHIP_ERROR err =
cluster.ReadAttribute<Binding::Attributes::Binding::TypeInfo>(this, OnReadSuccessResponse, OnReadFailureResponse);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed in reading binding. Error %s", ErrorStr(err));
clearContext();
}
}

/* Callback when command results in success */
static void
OnReadSuccessResponse(void * context,
const app::DataModel::DecodableList<Binding::Structs::TargetStruct::DecodableType> & responseData)
{
ChipLogProgress(Controller, "OnReadSuccessResponse - Binding Read Successfully");

MyPostCommissioningListener * listener = static_cast<MyPostCommissioningListener *>(context);
listener->finishTargetConfiguration(responseData);
}

/* Callback when command results in failure */
static void OnReadFailureResponse(void * context, CHIP_ERROR error)
{
ChipLogProgress(Controller, "OnReadFailureResponse - Binding Read Failed");

MyPostCommissioningListener * listener = static_cast<MyPostCommissioningListener *>(context);
listener->clearContext();

CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController();
if (cdc != nullptr)
{
cdc->PostCommissioningFailed(error);
}
}

/* Callback when command results in success */
Expand All @@ -227,6 +264,60 @@ class MyPostCommissioningListener : public PostCommissioningListener
cdc->PostCommissioningFailed(error);
}
}

void
finishTargetConfiguration(const app::DataModel::DecodableList<Binding::Structs::TargetStruct::DecodableType> & responseList)
{
std::vector<app::Clusters::Binding::Structs::TargetStruct::Type> bindings;
NodeId localNodeId = GetDeviceCommissioner()->GetNodeId();

auto iter = responseList.begin();
while (iter.Next())
{
auto & binding = iter.GetValue();
ChipLogProgress(Controller, "Binding found nodeId=0x" ChipLogFormatX64 " my nodeId=0x" ChipLogFormatX64,
ChipLogValueX64(binding.node.ValueOr(0)), ChipLogValueX64(localNodeId));
if (binding.node.ValueOr(0) != localNodeId)
{
ChipLogProgress(Controller, "Found a binding for a different node, preserving");
bindings.push_back(binding);
}
else
{
ChipLogProgress(Controller, "Found a binding for a matching node, dropping");
}
}

Optional<SessionHandle> opt = mSecureSession.Get();
SessionHandle & sessionHandle = opt.Value();
ContentAppPlatform::GetInstance().ManageClientAccess(*mExchangeMgr, sessionHandle, mVendorId, mProductId, localNodeId,
bindings, OnSuccessResponse, OnFailureResponse);
clearContext();
}

void cacheContext(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr,
SessionHandle & sessionHandle)
{
mVendorId = vendorId;
mProductId = productId;
mNodeId = nodeId;
mExchangeMgr = &exchangeMgr;
mSecureSession.ShiftToSession(sessionHandle);
}

void clearContext()
{
mVendorId = 0;
mProductId = 0;
mNodeId = 0;
mExchangeMgr = nullptr;
mSecureSession.SessionReleased();
}
uint16_t mVendorId = 0;
uint16_t mProductId = 0;
NodeId mNodeId = 0;
Messaging::ExchangeManager * mExchangeMgr = nullptr;
SessionHolder mSecureSession;
};

MyPostCommissioningListener gMyPostCommissioningListener;
Expand Down
108 changes: 106 additions & 2 deletions examples/tv-app/linux/AppImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@
#include <lib/support/CodeUtils.h>
#include <lib/support/ZclString.h>
#include <platform/CHIPDeviceLayer.h>
#include <zap-generated/CHIPClusters.h>

using namespace chip;
using namespace chip::AppPlatform;
using namespace chip::app::Clusters;

#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
class MyUserPrompter : public UserPrompter
Expand Down Expand Up @@ -89,9 +91,44 @@ class MyPostCommissioningListener : public PostCommissioningListener
void CommissioningCompleted(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr,
SessionHandle & sessionHandle) override
{
// read current binding list
chip::Controller::BindingCluster cluster(exchangeMgr, sessionHandle, kTargetBindingClusterEndpointId);

ContentAppPlatform::GetInstance().ManageClientAccess(
exchangeMgr, sessionHandle, vendorId, GetDeviceCommissioner()->GetNodeId(), OnSuccessResponse, OnFailureResponse);
cacheContext(vendorId, productId, nodeId, exchangeMgr, sessionHandle);

CHIP_ERROR err =
cluster.ReadAttribute<Binding::Attributes::Binding::TypeInfo>(this, OnReadSuccessResponse, OnReadFailureResponse);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed in reading binding. Error %s", ErrorStr(err));
clearContext();
}
}

/* Callback when command results in success */
static void
OnReadSuccessResponse(void * context,
const app::DataModel::DecodableList<Binding::Structs::TargetStruct::DecodableType> & responseData)
{
ChipLogProgress(Controller, "OnReadSuccessResponse - Binding Read Successfully");

MyPostCommissioningListener * listener = static_cast<MyPostCommissioningListener *>(context);
listener->finishTargetConfiguration(responseData);
}

/* Callback when command results in failure */
static void OnReadFailureResponse(void * context, CHIP_ERROR error)
{
ChipLogProgress(Controller, "OnReadFailureResponse - Binding Read Failed");

MyPostCommissioningListener * listener = static_cast<MyPostCommissioningListener *>(context);
listener->clearContext();

CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController();
if (cdc != nullptr)
{
cdc->PostCommissioningFailed(error);
}
}

/* Callback when command results in success */
Expand All @@ -115,6 +152,60 @@ class MyPostCommissioningListener : public PostCommissioningListener
cdc->PostCommissioningFailed(error);
}
}

void
finishTargetConfiguration(const app::DataModel::DecodableList<Binding::Structs::TargetStruct::DecodableType> & responseList)
{
std::vector<app::Clusters::Binding::Structs::TargetStruct::Type> bindings;
NodeId localNodeId = GetDeviceCommissioner()->GetNodeId();

auto iter = responseList.begin();
while (iter.Next())
{
auto & binding = iter.GetValue();
ChipLogProgress(Controller, "Binding found nodeId=0x" ChipLogFormatX64 " my nodeId=0x" ChipLogFormatX64,
ChipLogValueX64(binding.node.ValueOr(0)), ChipLogValueX64(localNodeId));
if (binding.node.ValueOr(0) != localNodeId)
{
ChipLogProgress(Controller, "Found a binding for a different node, preserving");
bindings.push_back(binding);
}
else
{
ChipLogProgress(Controller, "Found a binding for a matching node, dropping");
}
}

Optional<SessionHandle> opt = mSecureSession.Get();
SessionHandle & sessionHandle = opt.Value();
ContentAppPlatform::GetInstance().ManageClientAccess(*mExchangeMgr, sessionHandle, mVendorId, mProductId, localNodeId,
bindings, OnSuccessResponse, OnFailureResponse);
clearContext();
}

void cacheContext(uint16_t vendorId, uint16_t productId, NodeId nodeId, Messaging::ExchangeManager & exchangeMgr,
SessionHandle & sessionHandle)
{
mVendorId = vendorId;
mProductId = productId;
mNodeId = nodeId;
mExchangeMgr = &exchangeMgr;
mSecureSession.ShiftToSession(sessionHandle);
}

void clearContext()
{
mVendorId = 0;
mProductId = 0;
mNodeId = 0;
mExchangeMgr = nullptr;
mSecureSession.SessionReleased();
}
uint16_t mVendorId = 0;
uint16_t mProductId = 0;
NodeId mNodeId = 0;
Messaging::ExchangeManager * mExchangeMgr = nullptr;
SessionHolder mSecureSession;
};

MyPostCommissioningListener gMyPostCommissioningListener;
Expand Down Expand Up @@ -407,6 +498,19 @@ Access::Privilege ContentAppFactoryImpl::GetVendorPrivilege(uint16_t vendorId)
return Access::Privilege::kOperate;
}

std::list<ClusterId> ContentAppFactoryImpl::GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId,
uint16_t productId)
{
if (endpointId == kLocalVideoPlayerEndpointId)
{
return { chip::app::Clusters::Descriptor::Id, chip::app::Clusters::OnOff::Id,
chip::app::Clusters::WakeOnLan::Id, chip::app::Clusters::MediaPlayback::Id,
chip::app::Clusters::LowPower::Id, chip::app::Clusters::KeypadInput::Id,
chip::app::Clusters::ContentLauncher::Id, chip::app::Clusters::AudioOutput::Id };
}
return {};
}

} // namespace AppPlatform
} // namespace chip

Expand Down
5 changes: 5 additions & 0 deletions examples/tv-app/linux/AppImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory
// When a vendor has admin privileges, it will get access to all clusters on ep1
Access::Privilege GetVendorPrivilege(uint16_t vendorId) override;

// Get the cluster list this vendorId/productId should have on static endpoints such as ep1 for casting video clients.
// When a vendor has admin privileges, it will get access to all clusters on ep1
std::list<ClusterId> GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId,
uint16_t productId) override;

void AddAdminVendorId(uint16_t vendorId);

protected:
Expand Down
48 changes: 18 additions & 30 deletions src/app/app-platform/ContentAppPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,27 +510,11 @@ CHIP_ERROR ContentAppPlatform::GetACLEntryIndex(size_t * foundIndex, FabricIndex
return CHIP_ERROR_NOT_FOUND;
}

constexpr EndpointId kTargetBindingClusterEndpointId = 0;
constexpr EndpointId kLocalVideoPlayerEndpointId = 1;
constexpr EndpointId kLocalSpeakerEndpointId = 2;
constexpr ClusterId kClusterIdDescriptor = 0x001d;
constexpr ClusterId kClusterIdOnOff = 0x0006;
constexpr ClusterId kClusterIdWakeOnLAN = 0x0503;
// constexpr ClusterId kClusterIdChannel = 0x0504;
// constexpr ClusterId kClusterIdTargetNavigator = 0x0505;
constexpr ClusterId kClusterIdMediaPlayback = 0x0506;
// constexpr ClusterId kClusterIdMediaInput = 0x0507;
constexpr ClusterId kClusterIdLowPower = 0x0508;
constexpr ClusterId kClusterIdKeypadInput = 0x0509;
constexpr ClusterId kClusterIdContentLauncher = 0x050a;
constexpr ClusterId kClusterIdAudioOutput = 0x050b;
// constexpr ClusterId kClusterIdApplicationLauncher = 0x050c;
// constexpr ClusterId kClusterIdAccountLogin = 0x050e;

// Add ACLs on this device for the given client,
// and create bindings on the given client so that it knows what it has access to.
CHIP_ERROR ContentAppPlatform::ManageClientAccess(Messaging::ExchangeManager & exchangeMgr, SessionHandle & sessionHandle,
uint16_t targetVendorId, NodeId localNodeId,
uint16_t targetVendorId, uint16_t targetProductId, NodeId localNodeId,
std::vector<Binding::Structs::TargetStruct::Type> bindings,
Controller::WriteResponseSuccessCallback successCb,
Controller::WriteResponseFailureCallback failureCb)
{
Expand Down Expand Up @@ -564,8 +548,6 @@ CHIP_ERROR ContentAppPlatform::ManageClientAccess(Messaging::ExchangeManager & e
ReturnErrorOnFailure(entry.SetPrivilege(vendorPrivilege));
ReturnErrorOnFailure(entry.AddSubject(nullptr, subjectNodeId));

std::vector<Binding::Structs::TargetStruct::Type> bindings;

/**
* Here we are creating a single ACL entry containing:
* a) selection of clusters on video player endpoint (8 targets)
Expand All @@ -588,21 +570,22 @@ CHIP_ERROR ContentAppPlatform::ManageClientAccess(Messaging::ExchangeManager & e

ChipLogProgress(Controller, "Create video player endpoint ACL and binding");
{
bool hasClusterAccess = false;
if (vendorPrivilege == Access::Privilege::kAdminister)
{
ChipLogProgress(Controller, "ContentAppPlatform::ManageClientAccess Admin privilege granted");
// a vendor with admin privilege gets access to all clusters on ep1
Access::AccessControl::Entry::Target target = { .flags = Access::AccessControl::Entry::Target::kEndpoint,
.endpoint = kLocalVideoPlayerEndpointId };
ReturnErrorOnFailure(entry.AddTarget(nullptr, target));
hasClusterAccess = true;
}
else
{
ChipLogProgress(Controller, "ContentAppPlatform::ManageClientAccess non-Admin privilege granted");
// a vendor with non-admin privilege gets access to select clusters on ep1
std::list<ClusterId> allowedClusterList = { kClusterIdDescriptor, kClusterIdOnOff, kClusterIdWakeOnLAN,
kClusterIdMediaPlayback, kClusterIdLowPower, kClusterIdKeypadInput,
kClusterIdContentLauncher, kClusterIdAudioOutput };
std::list<ClusterId> allowedClusterList = mContentAppFactory->GetAllowedClusterListForStaticEndpoint(
kLocalVideoPlayerEndpointId, targetVendorId, targetProductId);

for (const auto & clusterId : allowedClusterList)
{
Expand All @@ -611,16 +594,21 @@ CHIP_ERROR ContentAppPlatform::ManageClientAccess(Messaging::ExchangeManager & e
.cluster = clusterId,
.endpoint = kLocalVideoPlayerEndpointId };
ReturnErrorOnFailure(entry.AddTarget(nullptr, target));
hasClusterAccess = true;
}
}

bindings.push_back(Binding::Structs::TargetStruct::Type{
.node = MakeOptional(localNodeId),
.group = NullOptional,
.endpoint = MakeOptional(kLocalVideoPlayerEndpointId),
.cluster = NullOptional,
.fabricIndex = kUndefinedFabricIndex,
});
if (hasClusterAccess)
{
ChipLogProgress(Controller, "ContentAppPlatform::ManageClientAccess adding a binding on ep1");
bindings.push_back(Binding::Structs::TargetStruct::Type{
.node = MakeOptional(localNodeId),
.group = NullOptional,
.endpoint = MakeOptional(kLocalVideoPlayerEndpointId),
.cluster = NullOptional,
.fabricIndex = kUndefinedFabricIndex,
});
}
}

ChipLogProgress(Controller, "Create speaker endpoint ACL and binding");
Expand Down
Loading

0 comments on commit eb3d4e8

Please sign in to comment.