Skip to content

Commit

Permalink
admin access for certain tv clients (#21282)
Browse files Browse the repository at this point in the history
* Draft: admin access for certain tv clients

* cleanup acl print shell command, disable placeholder endpoint
  • Loading branch information
chrisdecenzo authored Jul 28, 2022
1 parent fb9cd5c commit 8ee4bee
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 11 deletions.
29 changes: 29 additions & 0 deletions examples/tv-app/android/java/AppImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ class MyPostCommissioningListener : public PostCommissioningListener
MyPostCommissioningListener gMyPostCommissioningListener;
ContentAppFactoryImpl gFactory;

ContentAppFactoryImpl * GetContentAppFactoryImpl()
{
return &gFactory;
}

namespace chip {
namespace AppPlatform {

Expand Down Expand Up @@ -412,6 +417,24 @@ void ContentAppFactoryImpl::SendTestMessage(EndpointId epId, const char * messag
}
}

void ContentAppFactoryImpl::AddAdminVendorId(uint16_t vendorId)
{
mAdminVendorIds.push_back(vendorId);
}

Access::Privilege ContentAppFactoryImpl::GetVendorPrivilege(uint16_t vendorId)
{
for (size_t i = 0; i < mAdminVendorIds.size(); ++i)
{
auto & vendor = mAdminVendorIds.at(i);
if (vendorId == vendor)
{
return Access::Privilege::kAdminister;
}
}
return Access::Privilege::kOperate;
}

} // namespace AppPlatform
} // namespace chip

Expand Down Expand Up @@ -448,6 +471,12 @@ CHIP_ERROR InitVideoPlayerPlatform(JNIMyUserPrompter * userPrompter, jobject con
ChipLogProgress(AppServer, "Started commissioner");

#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE

// Disable last fixed endpoint, which is used as a placeholder for all of the
// supported clusters so that ZAP will generated the requisite code.
ChipLogDetail(DeviceLayer, "TV App: Disabling Fixed Content App Endpoints");
emberAfEndpointEnableDisable(3, false);

return CHIP_NO_ERROR;
}

Expand Down
12 changes: 12 additions & 0 deletions examples/tv-app/android/java/AppImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,28 @@ class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory
// and then writes it to destinationApp
CHIP_ERROR ConvertToPlatformCatalogVendorApp(const CatalogVendorApp & sourceApp, CatalogVendorApp * destinationApp) override;

// Get the privilege this vendorId should have on endpoints 1, 2, and content app endpoints
// In the case of casting video clients, this should usually be Access::Privilege::kOperate
// and for voice agents, this may be Access::Privilege::kAdminister
// When a vendor has admin privileges, it will get access to all clusters on ep1
Access::Privilege GetVendorPrivilege(uint16_t vendorId) override;

void AddAdminVendorId(uint16_t vendorId);

protected:
std::vector<ContentAppImpl *> mContentApps{
new ContentAppImpl("Vendor1", 1, "exampleid", 11, "Version1", "20202021", nullptr),
new ContentAppImpl("Vendor2", 65520, "exampleString", 32768, "Version2", "20202021", nullptr),
new ContentAppImpl("Vendor3", 9050, "App3", 22, "Version3", "20202021", nullptr),
new ContentAppImpl("TestSuiteVendor", 1111, "applicationId", 22, "v2", "20202021", nullptr)
};

std::vector<uint16_t> mAdminVendorIds{};
};

} // namespace AppPlatform
} // namespace chip

chip::AppPlatform::ContentAppFactoryImpl * GetContentAppFactoryImpl();

#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
2 changes: 1 addition & 1 deletion examples/tv-app/android/java/MediaPlaybackManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ void MediaPlaybackManager::InitializeWithObjects(jobject managerObject)
}

mGetPositionMethod =
env->GetMethodID(mMediaPlaybackManagerClass, "getPosition", "()[Lcom/matter/tv/server/tvapp/MediaPlaybackPosition;");
env->GetMethodID(mMediaPlaybackManagerClass, "getPosition", "()Lcom/matter/tv/server/tvapp/MediaPlaybackPosition;");
if (mGetPositionMethod == nullptr)
{
ChipLogError(Zcl, "Failed to access MediaPlaybackManager 'getPosition' method");
Expand Down
23 changes: 23 additions & 0 deletions examples/tv-app/linux/AppImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ class MyPostCommissioningListener : public PostCommissioningListener
MyPostCommissioningListener gMyPostCommissioningListener;
ContentAppFactoryImpl gFactory;

ContentAppFactoryImpl * GetContentAppFactoryImpl()
{
return &gFactory;
}

namespace chip {
namespace AppPlatform {

Expand Down Expand Up @@ -383,6 +388,24 @@ ContentApp * ContentAppFactoryImpl::LoadContentApp(const CatalogVendorApp & vend
return nullptr;
}

void ContentAppFactoryImpl::AddAdminVendorId(uint16_t vendorId)
{
mAdminVendorIds.push_back(vendorId);
}

Access::Privilege ContentAppFactoryImpl::GetVendorPrivilege(uint16_t vendorId)
{
for (size_t i = 0; i < mAdminVendorIds.size(); ++i)
{
auto & vendor = mAdminVendorIds.at(i);
if (vendorId == vendor)
{
return Access::Privilege::kAdminister;
}
}
return Access::Privilege::kOperate;
}

} // namespace AppPlatform
} // namespace chip

Expand Down
12 changes: 12 additions & 0 deletions examples/tv-app/linux/AppImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,28 @@ class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory
// and then writes it to destinationApp
CHIP_ERROR ConvertToPlatformCatalogVendorApp(const CatalogVendorApp & sourceApp, CatalogVendorApp * destinationApp) override;

// Get the privilege this vendorId should have on endpoints 1, 2, and content app endpoints
// In the case of casting video clients, this should usually be Access::Privilege::kOperate
// and for voice agents, this may be Access::Privilege::kAdminister
// When a vendor has admin privileges, it will get access to all clusters on ep1
Access::Privilege GetVendorPrivilege(uint16_t vendorId) override;

void AddAdminVendorId(uint16_t vendorId);

protected:
ContentAppImpl mContentApps[APP_LIBRARY_SIZE] = {
ContentAppImpl("Vendor1", 1, "exampleid", 11, "Version1", "34567890"),
ContentAppImpl("Vendor2", 65521, "exampleString", 32768, "Version2", "20202021"),
ContentAppImpl("Vendor3", 9050, "App3", 22, "Version3", "20202021"),
ContentAppImpl("TestSuiteVendor", 1111, "applicationId", 22, "v2", "20202021")
};

std::vector<uint16_t> mAdminVendorIds{};
};

} // namespace AppPlatform
} // namespace chip

chip::AppPlatform::ContentAppFactoryImpl * GetContentAppFactoryImpl();

#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
117 changes: 117 additions & 0 deletions examples/tv-app/linux/AppPlatformShellCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
*/

#include "AppPlatformShellCommands.h"
#include "AppImpl.h"
#include "ControllerShellCommands.h"
#include <AppMain.h>
#include <access/AccessControl.h>
#include <inttypes.h>
#include <lib/core/CHIPCore.h>
#include <lib/shell/Commands.h>
Expand All @@ -39,6 +41,7 @@
using namespace ::chip::Controller;
#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
using namespace chip::AppPlatform;
using namespace chip::Access;
#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED
using namespace chip::app::Clusters;

Expand Down Expand Up @@ -103,6 +106,82 @@ static CHIP_ERROR pairApp(bool printHeader, size_t index)
return CHIP_NO_ERROR;
}

static CHIP_ERROR DumpAccessControlEntry(const Access::AccessControl::Entry & entry)
{
CHIP_ERROR err;

ChipLogDetail(DeviceLayer, "----- BEGIN ENTRY -----");

{
FabricIndex fabricIndex;
SuccessOrExit(err = entry.GetFabricIndex(fabricIndex));
ChipLogDetail(DeviceLayer, "fabricIndex: %u", fabricIndex);
}

{
Privilege privilege;
SuccessOrExit(err = entry.GetPrivilege(privilege));
ChipLogDetail(DeviceLayer, "privilege: %d", to_underlying(privilege));
}

{
AuthMode authMode;
SuccessOrExit(err = entry.GetAuthMode(authMode));
ChipLogDetail(DeviceLayer, "authMode: %d", to_underlying(authMode));
}

{
size_t count;
SuccessOrExit(err = entry.GetSubjectCount(count));
if (count)
{
ChipLogDetail(DeviceLayer, "subjects: %u", static_cast<unsigned>(count));
for (size_t i = 0; i < count; ++i)
{
NodeId subject;
SuccessOrExit(err = entry.GetSubject(i, subject));
ChipLogDetail(DeviceLayer, " %u: 0x" ChipLogFormatX64, static_cast<unsigned>(i), ChipLogValueX64(subject));
}
}
}

{
size_t count;
SuccessOrExit(err = entry.GetTargetCount(count));
if (count)
{
ChipLogDetail(DeviceLayer, "targets: %u", static_cast<unsigned>(count));
for (size_t i = 0; i < count; ++i)
{
Access::AccessControl::Entry::Target target;
SuccessOrExit(err = entry.GetTarget(i, target));
if (target.flags & Access::AccessControl::Entry::Target::kCluster)
{
ChipLogDetail(DeviceLayer, " %u: cluster: 0x" ChipLogFormatMEI, static_cast<unsigned>(i),
ChipLogValueMEI(target.cluster));
}
if (target.flags & Access::AccessControl::Entry::Target::kEndpoint)
{
ChipLogDetail(DeviceLayer, " %u: endpoint: %u", static_cast<unsigned>(i), target.endpoint);
}
if (target.flags & Access::AccessControl::Entry::Target::kDeviceType)
{
ChipLogDetail(DeviceLayer, " %u: deviceType: 0x" ChipLogFormatMEI, static_cast<unsigned>(i),
ChipLogValueMEI(target.deviceType));
}
}
}
}

ChipLogDetail(DeviceLayer, "----- END ENTRY -----");

return CHIP_NO_ERROR;

exit:
ChipLogError(DeviceLayer, "DumpAccessControlEntry: dump failed %" CHIP_ERROR_FORMAT, err.Format());
return err;
}

static CHIP_ERROR PrintAllCommands()
{
streamer_t * sout = streamer_get();
Expand All @@ -114,6 +193,11 @@ static CHIP_ERROR PrintAllCommands()
streamer_printf(sout,
" commission <udc-entry> Commission given udc-entry using given pincode from corresponding app. Usage: "
"app commission 0\r\n");
streamer_printf(sout,
" add-admin-vendor <vid> Add vendor ID to list which will receive admin privileges. Usage: app "
"add-admin-vendor 65521\r\n");
streamer_printf(sout, " print-app-access Print all ACLs for app platform fabric. Usage: app print-app-access\r\n");
streamer_printf(sout, " remove-app-access Remove all ACLs for app platform fabric. Usage: app remove-app-access\r\n");
streamer_printf(sout, "\r\n");

return CHIP_NO_ERROR;
Expand All @@ -127,6 +211,22 @@ static CHIP_ERROR AppPlatformHandler(int argc, char ** argv)
{
return PrintAllCommands();
}
else if (strcmp(argv[0], "add-admin-vendor") == 0)
{
if (argc < 2)
{
return PrintAllCommands();
}
char * eptr;

uint16_t vid = (uint16_t) strtol(argv[1], &eptr, 10);
ContentAppFactoryImpl * factory = GetContentAppFactoryImpl();
factory->AddAdminVendorId(vid);

ChipLogProgress(DeviceLayer, "added admin-vendor");

return CHIP_NO_ERROR;
}
else if (strcmp(argv[0], "add") == 0)
{
if (argc < 2)
Expand Down Expand Up @@ -205,6 +305,23 @@ static CHIP_ERROR AppPlatformHandler(int argc, char ** argv)
size_t index = (size_t) strtol(argv[1], &eptr, 10);
return error = pairApp(true, index);
}
else if (strcmp(argv[0], "print-app-access") == 0)
{
Access::AccessControl::EntryIterator iterator;
ReturnErrorOnFailure(Access::GetAccessControl().Entries(GetDeviceCommissioner()->GetFabricIndex(), iterator));

Access::AccessControl::Entry entry;
while (iterator.Next(entry) == CHIP_NO_ERROR)
{
DumpAccessControlEntry(entry);
}
return CHIP_NO_ERROR;
}
else if (strcmp(argv[0], "remove-app-access") == 0)
{
Access::GetAccessControl().DeleteAllEntriesForFabric(GetDeviceCommissioner()->GetFabricIndex());
return CHIP_NO_ERROR;
}
else
{
return CHIP_ERROR_INVALID_ARGUMENT;
Expand Down
11 changes: 10 additions & 1 deletion examples/tv-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,16 @@ static TargetNavigatorManager targetNavigatorManager;
static WakeOnLanManager wakeOnLanManager;
} // namespace

void ApplicationInit() {}
void ApplicationInit()
{
ChipLogProgress(Zcl, "TV Linux App: ApplicationInit()");

// Disable last fixed endpoint, which is used as a placeholder for all of the
// supported clusters so that ZAP will generated the requisite code.
ChipLogDetail(DeviceLayer, "TV Linux App: Warning - Fixed Content App Endpoint Not Disabled");
// Can't disable this without breaking CI unit tests that act upon account login cluster (only available on ep3)
// emberAfEndpointEnableDisable(3, false);
}

int main(int argc, char * argv[])
{
Expand Down
33 changes: 24 additions & 9 deletions src/app/app-platform/ContentAppPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,11 +414,13 @@ CHIP_ERROR ContentAppPlatform::ManageClientAccess(OperationalDeviceProxy * targe
VerifyOrReturnError(successCb != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(failureCb != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

Access::Privilege vendorPrivilege = mContentAppFactory->GetVendorPrivilege(targetVendorId);

Access::AccessControl::Entry entry;
ReturnErrorOnFailure(GetAccessControl().PrepareEntry(entry));
ReturnErrorOnFailure(entry.SetAuthMode(Access::AuthMode::kCase));
entry.SetFabricIndex(targetDeviceProxy->GetFabricIndex());
ReturnErrorOnFailure(entry.SetPrivilege(Access::Privilege::kOperate));
ReturnErrorOnFailure(entry.SetPrivilege(vendorPrivilege));
ReturnErrorOnFailure(entry.AddSubject(nullptr, targetDeviceProxy->GetDeviceId()));

std::vector<Binding::Structs::TargetStruct::Type> bindings;
Expand All @@ -438,18 +440,31 @@ CHIP_ERROR ContentAppPlatform::ManageClientAccess(OperationalDeviceProxy * targe

ChipLogProgress(Controller, "Create video player endpoint ACL and binding");
{
std::list<ClusterId> allowedClusterList = { kClusterIdDescriptor, kClusterIdOnOff, kClusterIdWakeOnLAN,
kClusterIdMediaPlayback, kClusterIdLowPower, kClusterIdKeypadInput,
kClusterIdContentLauncher, kClusterIdAudioOutput };

for (const auto & clusterId : allowedClusterList)
if (vendorPrivilege == Access::Privilege::kAdminister)
{
Access::AccessControl::Entry::Target target = { .flags = Access::AccessControl::Entry::Target::kCluster |
Access::AccessControl::Entry::Target::kEndpoint,
.cluster = clusterId,
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));
}
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 };

for (const auto & clusterId : allowedClusterList)
{
Access::AccessControl::Entry::Target target = { .flags = Access::AccessControl::Entry::Target::kCluster |
Access::AccessControl::Entry::Target::kEndpoint,
.cluster = clusterId,
.endpoint = kLocalVideoPlayerEndpointId };
ReturnErrorOnFailure(entry.AddTarget(nullptr, target));
}
}

bindings.push_back(Binding::Structs::TargetStruct::Type{
.node = MakeOptional(localNodeId),
Expand Down
Loading

0 comments on commit 8ee4bee

Please sign in to comment.