diff --git a/alpha/apps/kaltura/lib/kPlaybackContextDataHelper.php b/alpha/apps/kaltura/lib/kPlaybackContextDataHelper.php
index 0463143efb2..7933278c966 100644
--- a/alpha/apps/kaltura/lib/kPlaybackContextDataHelper.php
+++ b/alpha/apps/kaltura/lib/kPlaybackContextDataHelper.php
@@ -666,7 +666,6 @@ private static function getDrmData(entry $dbEntry, $flavorAssets, $deliveryProfi
$playbackContextDataParams->setDeliveryProfile($deliveryProfile);
$playbackContextDataParams->setFlavors(array_values($flavorAssets));
$playbackContextDataParams->setType('drm');
-
$result = new kPlaybackContextDataResult();
$pluginInstances = KalturaPluginManager::getPluginInstances('IKalturaPlaybackContextDataContributor');
foreach ($pluginInstances as $pluginInstance)
diff --git a/alpha/apps/kaltura/lib/kPlaybackContextDataParams.php b/alpha/apps/kaltura/lib/kPlaybackContextDataParams.php
index f5b8e5296ad..c7f8e5fd271 100644
--- a/alpha/apps/kaltura/lib/kPlaybackContextDataParams.php
+++ b/alpha/apps/kaltura/lib/kPlaybackContextDataParams.php
@@ -65,5 +65,4 @@ public function setDeliveryProfile($deliveryProfile)
{
$this->deliveryProfile = $deliveryProfile;
}
-
-}
\ No newline at end of file
+}
diff --git a/alpha/lib/model/Partner.php b/alpha/lib/model/Partner.php
index e78d4e619cd..4f20306d50b 100644
--- a/alpha/lib/model/Partner.php
+++ b/alpha/lib/model/Partner.php
@@ -133,6 +133,7 @@ class Partner extends BasePartner
const EXTERNAL_IDENTIFIER = 'externalIdentifier';
+ const CUSTOM_DATA_DRM_KEY_MANAGEMENT_POLICY = 'drmKeyManagementPolicy';
const ALLOWED_REDIRECT_DOMAINS = 'allowedRedirectDomains';
public function save(PropelPDO $con = null)
@@ -2485,6 +2486,17 @@ public function setExternalIdentifier($v)
return $this->putInCustomData(self::EXTERNAL_IDENTIFIER, $v);
}
+ public function getDrmKeyManagementPolicy()
+ {
+ $policy = $this->getFromCustomData(self::CUSTOM_DATA_DRM_KEY_MANAGEMENT_POLICY);
+ return $policy !== null ? $policy : DrmKeyManagementPolicy::UNKNOWN;
+ }
+
+ public function setDrmKeyManagementPolicy($v)
+ {
+ return $this->putInCustomData(self::CUSTOM_DATA_DRM_KEY_MANAGEMENT_POLICY, $v);
+ }
+
public function getAllowedRedirectDomains()
{
return $this->getFromCustomData(self::ALLOWED_REDIRECT_DOMAINS);
diff --git a/alpha/lib/model/entry.php b/alpha/lib/model/entry.php
index 00835e7c176..a94fe681e24 100644
--- a/alpha/lib/model/entry.php
+++ b/alpha/lib/model/entry.php
@@ -144,6 +144,8 @@ class entry extends Baseentry implements ISyncableFile, IIndexable, IOwnable, IR
const LIVE_THUMB_PATH = "content/templates/entry/thumbnail/live_thumb.jpg";
const CUSTOM_DATA_INTERACTIVITY_VERSION = 'interactivity_version';
const CUSTOM_DATA_VOLATILE_INTERACTIVITY_VERSION = 'volatile_interactivity_version';
+
+ const CUSTOM_DATA_DRM_KEY_MANAGEMENT_POLICY = 'drmKeyManagementPolicy';
const CUSTOM_DATA_IS_SCHEDULED = 'isScheduled';
const NAME = 'name';
@@ -4651,6 +4653,16 @@ public function getVolatileInteractivityVersion()
return $this->getFromCustomData( self::CUSTOM_DATA_VOLATILE_INTERACTIVITY_VERSION ,null, null);
}
+ public function getDrmKeyManagementPolicy()
+ {
+ return $this->getFromCustomData(self::CUSTOM_DATA_DRM_KEY_MANAGEMENT_POLICY);
+ }
+
+ public function setDrmKeyManagementPolicy($v)
+ {
+ return $this->putInCustomData(self::CUSTOM_DATA_DRM_KEY_MANAGEMENT_POLICY, $v);
+ }
+
public function getIsScheduled()
{
return $this->getFromCustomData(self::CUSTOM_DATA_IS_SCHEDULED, null, false);
diff --git a/api_v3/lib/types/partner/KalturaPartner.php b/api_v3/lib/types/partner/KalturaPartner.php
index e409005c0fa..e1f1d1eb1b2 100644
--- a/api_v3/lib/types/partner/KalturaPartner.php
+++ b/api_v3/lib/types/partner/KalturaPartner.php
@@ -563,7 +563,7 @@ public function fromPartner(Partner $partner)
public function doFromObject($partner, KalturaDetachedResponseProfile $responseProfile = null)
{
parent::doFromObject($partner);
-
+
$this->updatePasswordStructureFromPartner($partner);
$this->name = kString::stripUtf8InvalidChars($this->name);
diff --git a/deployment/permissions/service.drm.keymanagementpolicy.ini b/deployment/permissions/service.drm.keymanagementpolicy.ini
new file mode 100644
index 00000000000..22b18d1fb94
--- /dev/null
+++ b/deployment/permissions/service.drm.keymanagementpolicy.ini
@@ -0,0 +1,18 @@
+[action_permission_items]
+permissionItem1.service = drm_keymanagementpolicy
+permissionItem1.action = get
+permissionItem1.partnerId = 0
+permissionItem1.param3 =
+permissionItem1.param4 =
+permissionItem1.param5 =
+permissionItem1.tags =
+permissionItem1.permissions = ALWAYS_ALLOWED_FROM_INTERNAL_IP_ACTIONS
+
+permissionItem2.service = drm_keymanagementpolicy
+permissionItem2.action = update
+permissionItem2.partnerId = 0
+permissionItem2.param3 =
+permissionItem2.param4 =
+permissionItem2.param5 =
+permissionItem2.tags =
+permissionItem2.permissions = ALWAYS_ALLOWED_FROM_INTERNAL_IP_ACTIONS
diff --git a/deployment/updates/scripts/add_permissions/2026_07_08_drm_key_management_policy_permission.php b/deployment/updates/scripts/add_permissions/2026_07_08_drm_key_management_policy_permission.php
new file mode 100644
index 00000000000..ba0d2dad70a
--- /dev/null
+++ b/deployment/updates/scripts/add_permissions/2026_07_08_drm_key_management_policy_permission.php
@@ -0,0 +1,9 @@
+appendChild($tagsConfiguration);
$arguments['tagsparam'] = $tagsDoc->saveXML();
+ $partner = $this->entry->getPartner();
+ if ($partner && $partner->getPluginEnabled(DrmPlugin::PLUGIN_NAME))
+ {
+ $arguments['keyManagementPolicy'] = (string)DrmPlugin::getDrmKeyManagementPolicy($this->entry);
+ }
return $arguments;
}
@@ -288,4 +293,4 @@ private function createAppendXml($tag, $tagsDoc, $xmlNodeName, $propertyName)
return $nameNode;
}
-}
\ No newline at end of file
+}
diff --git a/plugins/content_distribution/providers/tvinci/lib/xml/tvinci_default.xslt b/plugins/content_distribution/providers/tvinci/lib/xml/tvinci_default.xslt
index d633305b35e..bba8427d996 100644
--- a/plugins/content_distribution/providers/tvinci/lib/xml/tvinci_default.xslt
+++ b/plugins/content_distribution/providers/tvinci/lib/xml/tvinci_default.xslt
@@ -102,6 +102,8 @@
+
+
@@ -244,6 +246,11 @@
+
+
+
+
+
diff --git a/plugins/drm/BaseDrmPlugin.php b/plugins/drm/BaseDrmPlugin.php
index e274f738d7a..216b408055a 100644
--- a/plugins/drm/BaseDrmPlugin.php
+++ b/plugins/drm/BaseDrmPlugin.php
@@ -25,6 +25,39 @@ public static function shouldContributeToPlaybackContext(array $actions)
return false;
}
-}
+ public static function getDrmKeyManagementPolicy($entry)
+ {
+ $drmKeyManagementPolicy = $entry->getDrmKeyManagementPolicy();
+ if (is_null($drmKeyManagementPolicy))
+ {
+ $partner = $entry->getPartner();
+ if ($partner)
+ {
+ $drmKeyManagementPolicy = $partner->getDrmKeyManagementPolicy();
+ }
+ else
+ {
+ $drmKeyManagementPolicy = DrmKeyManagementPolicy::UNKNOWN;
+ }
+ }
+ return $drmKeyManagementPolicy;
+ }
+
+ protected function getLicenseExpirationAndDuration($policyId, $entry)
+ {
+ $licenseExpiration = null;
+ $licenseDuration = null;
+ if ($policyId)
+ {
+ $drmPolicy = DrmPolicyPeer::retrieveByPK($policyId);
+ if ($drmPolicy)
+ {
+ $licenseExpiration = DrmLicenseUtils::calculateExpirationDate($drmPolicy, $entry);
+ $licenseDuration = $drmPolicy->getDuration();
+ }
+ }
+ return [$licenseExpiration, $licenseDuration];
+ }
+}
diff --git a/plugins/drm/DrmBulkUploadXmlPlugin.php b/plugins/drm/DrmBulkUploadXmlPlugin.php
new file mode 100644
index 00000000000..0e304b3c969
--- /dev/null
+++ b/plugins/drm/DrmBulkUploadXmlPlugin.php
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+ The DRM key management policy to apply to this entry.
+ Values correspond to the DrmKeyManagementPolicy enum:
+ 0 = UNKNOWN
+ 1 = CLEAR
+ 2 = SHARED_KEY
+ 3 = ALL_VIDEO
+ 4 = SD_HD
+ 5 = SD_HD_UHD
+ 6 = SD_HD_UHD1_UHD2
+ 7 = SD_HD1_HD2_UHD1_UHD2
+ 8 = SD_HD1_HD2_UHD
+ 9 = SDHD1_HD2_UHD
+ 10 = SDHD1_HD2_UHD1_UHD2
+ If omitted, the entry inherits the partner-level DRM key management policy.
+ If no partner-level policy is set either, the policy defaults to UNKNOWN (0).
+
+
+
+
+
+
+
+
+ DRM key management policy configuration for this entry
+
+
+
+ 3
+
+
+
+
+
+ ';
+
+ return $xsd;
+ }
+
+ /* (non-PHPdoc)
+ * @see IKalturaBulkUploadXmlHandler::configureBulkUploadXmlHandler()
+ */
+ public function configureBulkUploadXmlHandler(BulkUploadEngineXml $xmlBulkUploadEngine)
+ {
+
+ }
+
+ /* (non-PHPdoc)
+ * @see IKalturaBulkUploadXmlHandler::handleItemAdded()
+ */
+ public function handleItemAdded(KalturaObjectBase $object, SimpleXMLElement $item)
+ {
+ if(!($object instanceof KalturaBaseEntry))
+ return;
+
+ if(!isset($item->drmConfiguration))
+ return;
+
+ $this->handleDrmConfiguration($object->id, $item);
+ }
+
+ /* (non-PHPdoc)
+ * @see IKalturaBulkUploadXmlHandler::handleItemUpdated()
+ */
+ public function handleItemUpdated(KalturaObjectBase $object, SimpleXMLElement $item)
+ {
+ if(!($object instanceof KalturaBaseEntry))
+ return;
+
+ if(!isset($item->drmConfiguration))
+ return;
+
+ $this->handleDrmConfiguration($object->id, $item);
+ }
+
+ /* (non-PHPdoc)
+ * @see IKalturaBulkUploadXmlHandler::handleItemDeleted()
+ */
+ public function handleItemDeleted(KalturaObjectBase $object, SimpleXMLElement $item)
+ {
+ // No handling required
+ }
+
+ /* (non-PHPdoc)
+ * @see IKalturaBulkUploadXmlHandler::getContainerName()
+ */
+ public function getContainerName()
+ {
+ return 'drmConfiguration';
+ }
+
+ /**
+ * Set the DRM key management policy on the entry via the keyManagementPolicy service.
+ *
+ * @param string $entryId
+ * @param SimpleXMLElement $item
+ */
+ private function handleDrmConfiguration($entryId, SimpleXMLElement $item)
+ {
+ KalturaLog::debug("Handling DRM key management policy for entry: " . $entryId);
+
+ $policy = new KalturaKeyManagementPolicy();
+ if (isset($item->drmConfiguration->keyManagementPolicy))
+ {
+ $policy->keyManagementPolicy = (int)$item->drmConfiguration->keyManagementPolicy;
+ }
+ else
+ {
+ KalturaLog::warning('No keyManagementPolicy specified for entry [' . $entryId . '], will use partner/default fallback.');
+ $policy->keyManagementPolicy = null;
+ }
+ try
+ {
+ KBatchBase::$kClient->keyManagementPolicy->update(
+ KalturaKeyManagementPolicyObjectType::ENTRY,
+ $entryId,
+ $policy
+ );
+ }
+ catch (Exception $e)
+ {
+ if ($e->getCode() == 'ENTRY_DRM_KEY_MANAGEMENT_POLICY_ALREADY_SET')
+ {
+ KalturaLog::info('DRM key management policy already set for entry [' . $entryId . '], skipping.');
+ return;
+ }
+ KalturaLog::err('drmConfiguration handling failed for entry [' . $entryId . ']: ' . $e->getMessage());
+ throw $e;
+ }
+ }
+}
diff --git a/plugins/drm/DrmPlugin.php b/plugins/drm/DrmPlugin.php
index af6819cae3a..94020081ea8 100644
--- a/plugins/drm/DrmPlugin.php
+++ b/plugins/drm/DrmPlugin.php
@@ -21,7 +21,8 @@ public static function getServicesMap() {
$map = array(
'drmPolicy' => 'DrmPolicyService',
'drmProfile' => 'DrmProfileService',
- 'drmLicenseAccess' => 'DrmLicenseAccessService'
+ 'drmLicenseAccess' => 'DrmLicenseAccessService',
+ 'keyManagementPolicy' => 'DrmKeyManagementPolicyService',
);
return $map;
}
@@ -63,7 +64,7 @@ public static function isAllowedPartner($partnerId) {
public static function getEnums($baseEnumName = null)
{
if(is_null($baseEnumName))
- return array('DrmPermissionName', 'DrmConversionEngineType', 'DrmAccessControlActionType', 'CencSchemeName' );
+ return array('DrmPermissionName', 'DrmConversionEngineType', 'DrmAccessControlActionType', 'CencSchemeName', 'DrmKeyManagementPolicy', 'KeyManagementPolicyObjectType');
if($baseEnumName == 'PermissionName')
return array('DrmPermissionName');
if($baseEnumName == 'conversionEngineType')
@@ -72,6 +73,10 @@ public static function getEnums($baseEnumName = null)
return array('DrmAccessControlActionType');
if ($baseEnumName == 'DrmSchemeName')
return array('CencSchemeName');
+ if ($baseEnumName == 'DrmKeyManagementPolicy')
+ return array('DrmKeyManagementPolicy');
+ if ($baseEnumName == 'KeyManagementPolicyObjectType')
+ return array('KeyManagementPolicyObjectType');
return array();
}
@@ -178,7 +183,17 @@ public function contributeToPlaybackContextDataResult(entry $entry, kPlaybackCon
$signingKey = $dbProfile->getSigningKey();
if ($signingKey)
{
- $customDataJson = DrmLicenseUtils::createCustomDataForEntry($entry->getId(), $entryPlayingDataParams->getFlavors(), $signingKey);
+ $policyId = null;
+ foreach ($contextDataHelper->getContextDataResult()->getActions() as $action) {
+ if ($action instanceof kAccessControlDrmPolicyAction && $action->getPolicyId()) {
+ $policyId = $action->getPolicyId();
+ break;
+ }
+ }
+
+ [$licenseExpiration, $licenseDuration] = $this->getLicenseExpirationAndDuration($policyId, $entry);
+ $drmKeyManagementPolicy = self::getDrmKeyManagementPolicy($entry);
+ $customDataJson = DrmLicenseUtils::createCustomDataForEntry($entry->getId(), $entryPlayingDataParams->getFlavors(), $signingKey, $policyId, $licenseExpiration, $licenseDuration, $drmKeyManagementPolicy);
$customDataObject = reset($customDataJson);
foreach (CencSchemeName::getAdditionalValues() as $scheme)
@@ -294,5 +309,3 @@ public static function isAllowAdminApi($actionApi = null)
}
}
-
-
diff --git a/plugins/drm/lib/DrmLicenseUtils.php b/plugins/drm/lib/DrmLicenseUtils.php
index 5f25d1a4919..cf5231d31a4 100644
--- a/plugins/drm/lib/DrmLicenseUtils.php
+++ b/plugins/drm/lib/DrmLicenseUtils.php
@@ -61,11 +61,12 @@ public static function signDataWithKey($dataToSign, $signingKey)
return rawurlencode(base64_encode(sha1($signingKey.$dataToSign,TRUE)));
}
- public static function createCustomDataForEntry($entryId, $flavors, $signingKey){
- return self::createCustomData($entryId, $flavors, $signingKey);
+ public static function createCustomDataForEntry($entryId, $flavors, $signingKey, $policyId = null, $licenseExpiration = null, $licenseDuration = null, $drmKeyManagementPolicy = null)
+ {
+ return self::createCustomData($entryId, $flavors, $signingKey, $policyId, $licenseExpiration, $licenseDuration, $drmKeyManagementPolicy);
}
- public static function createCustomData($entryId, $flavorAssets, $signingKey)
+ public static function createCustomData($entryId, $flavorAssets, $signingKey, $policyId = null, $licenseExpiration = null, $licenseDuration = null, $drmKeyManagementPolicy = null)
{
$flavorIds = "";
$first = true;
@@ -92,6 +93,23 @@ public static function createCustomData($entryId, $flavorAssets, $signingKey)
$innerData["content_id"] = $entryId;
$innerData["files"] = $flavorIds;
+ if($policyId !== null)
+ {
+ $innerData["drm_policy_id"] = $policyId;
+ }
+
+ if($licenseExpiration !== null)
+ {
+ $innerData["drm_license_expiration"] = $licenseExpiration;
+ }
+
+ if($licenseDuration !== null)
+ {
+ $innerData["drm_duration"] = $licenseDuration;
+ }
+
+ $innerData["drm_key_management_policy"] = $drmKeyManagementPolicy !== null ? $drmKeyManagementPolicy : DrmKeyManagementPolicy::UNKNOWN;
+
$innerDataJson = json_encode($innerData);
$innerDataSignature = self::signDataWithKey($innerDataJson, $signingKey);
$innerDataJsonEncoded = rawurlencode(base64_encode($innerDataJson));
@@ -120,4 +138,4 @@ public static function prepareUrl($url)
$url = preg_replace('/\s+/', '', $url);
return $url;
}
-}
\ No newline at end of file
+}
diff --git a/plugins/drm/lib/api/KalturaKeyManagementPolicy.php b/plugins/drm/lib/api/KalturaKeyManagementPolicy.php
new file mode 100644
index 00000000000..c2140e4fac8
--- /dev/null
+++ b/plugins/drm/lib/api/KalturaKeyManagementPolicy.php
@@ -0,0 +1,12 @@
+getId(), $entryPlayingDataParams->getFlavors(), $signingKey);
+ $policyId = null;
+ foreach ($contextDataHelper->getContextDataResult()->getActions() as $action) {
+ if ($action instanceof kAccessControlDrmPolicyAction && $action->getPolicyId()) {
+ $policyId = $action->getPolicyId();
+ break;
+ }
+ }
+
+ [$licenseExpiration, $licenseDuration] = $this->getLicenseExpirationAndDuration($policyId, $entry);
+ $drmKeyManagementPolicy = self::getDrmKeyManagementPolicy($entry);
+ $customDataJson = DrmLicenseUtils::createCustomDataForEntry($entry->getId(), $entryPlayingDataParams->getFlavors(), $signingKey, $policyId, $licenseExpiration, $licenseDuration, $drmKeyManagementPolicy);
$customDataObject = reset($customDataJson);
$data = new kFairPlayPlaybackPluginData();
$licenseUrl = $this->constructUrl($fairplayProfile, self::getUrlName(), $customDataObject);
@@ -241,4 +251,4 @@ public function constructUrl($fairplayProfile, $scheme, $customDataObject)
return $fairplayProfile->getLicenseServerUrl() . "/" . $scheme . "/license?custom_data=" . $customDataObject['custom_data'] . "&signature=" . $customDataObject['signature'];
}
-}
\ No newline at end of file
+}
diff --git a/plugins/drm/providers/playready/PlayReadyPlugin.php b/plugins/drm/providers/playready/PlayReadyPlugin.php
index 88758ce5ebc..038d2d4c314 100644
--- a/plugins/drm/providers/playready/PlayReadyPlugin.php
+++ b/plugins/drm/providers/playready/PlayReadyPlugin.php
@@ -254,7 +254,17 @@ public function contributeToPlaybackContextDataResult(entry $entry, kPlaybackCon
$signingKey = kConf::get('signing_key', 'drm', null);
if ($signingKey)
{
- $customDataJson = DrmLicenseUtils::createCustomDataForEntry($entry->getId(), $entryPlayingDataParams->getFlavors(), $signingKey);
+ $policyId = null;
+ foreach ($contextDataHelper->getContextDataResult()->getActions() as $action) {
+ if ($action instanceof kAccessControlDrmPolicyAction && $action->getPolicyId()) {
+ $policyId = $action->getPolicyId();
+ break;
+ }
+ }
+
+ [$licenseExpiration, $licenseDuration] = $this->getLicenseExpirationAndDuration($policyId, $entry);
+ $drmKeyManagementPolicy = self::getDrmKeyManagementPolicy($entry);
+ $customDataJson = DrmLicenseUtils::createCustomDataForEntry($entry->getId(), $entryPlayingDataParams->getFlavors(), $signingKey, $policyId, $licenseExpiration, $licenseDuration, $drmKeyManagementPolicy);
$customDataObject = reset($customDataJson);
$data = new kDrmPlaybackPluginData();
$data->setScheme($this->getDrmSchemeCoreValue());
@@ -285,4 +295,3 @@ public function constructUrl($playReadyProfile, $scheme, $customDataObject)
return $playReadyProfile->getLicenseServerUrl() . "/" . $scheme . "/license?custom_data=" . $customDataObject['custom_data'] . "&signature=" . $customDataObject['signature'];
}
}
-
diff --git a/plugins/drm/providers/widevine/WidevinePlugin.php b/plugins/drm/providers/widevine/WidevinePlugin.php
index fa4417dc720..e6889312a57 100644
--- a/plugins/drm/providers/widevine/WidevinePlugin.php
+++ b/plugins/drm/providers/widevine/WidevinePlugin.php
@@ -352,7 +352,17 @@ public function contributeToPlaybackContextDataResult(entry $entry, kPlaybackCon
$signingKey = kConf::get('signing_key', 'drm', null);
if ($signingKey)
{
- $customDataJson = DrmLicenseUtils::createCustomDataForEntry($entry->getId(), $entryPlayingDataParams->getFlavors(), $signingKey);
+ $policyId = null;
+ foreach ($contextDataHelper->getContextDataResult()->getActions() as $action) {
+ if ($action instanceof kAccessControlDrmPolicyAction && $action->getPolicyId()) {
+ $policyId = $action->getPolicyId();
+ break;
+ }
+ }
+
+ [$licenseExpiration, $licenseDuration] = $this->getLicenseExpirationAndDuration($policyId, $entry);
+ $drmKeyManagementPolicy = self::getDrmKeyManagementPolicy($entry);
+ $customDataJson = DrmLicenseUtils::createCustomDataForEntry($entry->getId(), $entryPlayingDataParams->getFlavors(), $signingKey, $policyId, $licenseExpiration, $licenseDuration, $drmKeyManagementPolicy);
$customDataObject = reset($customDataJson);
$data = new kDrmPlaybackPluginData();
$licenseUrl = $this->constructUrl($widevineProfile, self::getPluginName(), $customDataObject);
diff --git a/plugins/drm/services/DrmKeyManagementPolicyService.php b/plugins/drm/services/DrmKeyManagementPolicyService.php
new file mode 100644
index 00000000000..f8f7a07560d
--- /dev/null
+++ b/plugins/drm/services/DrmKeyManagementPolicyService.php
@@ -0,0 +1,151 @@
+getPluginEnabled(DrmPlugin::PLUGIN_NAME))
+ {
+ throw new KalturaAPIException(KalturaErrors::PLUGIN_NOT_AVAILABLE_FOR_PARTNER, DrmPlugin::getPluginName(), $partnerId);
+ }
+
+ return $partner;
+ }
+
+ protected function getValidatedEntry($entryId)
+ {
+ $entry = entryPeer::retrieveByPKNoFilter($entryId);
+ if (!$entry)
+ {
+ throw new KalturaAPIException(KalturaErrors::INVALID_OBJECT_ID, $entryId);
+ }
+
+ $partner = $entry->getPartner();
+ if (!$partner || !$partner->getPluginEnabled(DrmPlugin::PLUGIN_NAME))
+ {
+ throw new KalturaAPIException(KalturaErrors::PLUGIN_NOT_AVAILABLE_FOR_PARTNER, DrmPlugin::getPluginName(), $entry->getPartnerId());
+ }
+
+ return $entry;
+ }
+
+ /**
+ * @action get
+ * @param KalturaKeyManagementPolicyObjectType $objectType
+ * @param string $objectId
+ * @return KalturaKeyManagementPolicy
+ * @throws KalturaErrors::INVALID_ENUM_VALUE
+ * @throws KalturaErrors::INVALID_PARTNER_ID
+ * @throws KalturaErrors::INVALID_OBJECT_ID
+ * @throws KalturaErrors::PLUGIN_NOT_AVAILABLE_FOR_PARTNER
+ * @ksIgnored
+ */
+ public function getAction($objectType, $objectId)
+ {
+ $this->validateObjectType($objectType);
+ $result = new KalturaKeyManagementPolicy();
+
+ if ($objectType == KeyManagementPolicyObjectType::PARTNER)
+ {
+ $partner = $this->getValidatedPartner($objectId);
+ $result->keyManagementPolicy = $partner->getDrmKeyManagementPolicy();
+ }
+ else
+ {
+ $entry = $this->getValidatedEntry($objectId);
+ $result->keyManagementPolicy = DrmPlugin::getDrmKeyManagementPolicy($entry);
+ }
+ return $result;
+ }
+
+ /**
+ * @action update
+ * @param KalturaKeyManagementPolicyObjectType $objectType
+ * @param string $objectId
+ * @param KalturaKeyManagementPolicy $keyManagementPolicy
+ * @return KalturaKeyManagementPolicy
+ * @throws KalturaErrors::INVALID_ENUM_VALUE
+ * @throws KalturaErrors::INVALID_PARTNER_ID
+ * @throws KalturaErrors::INVALID_OBJECT_ID
+ * @throws KalturaErrors::PLUGIN_NOT_AVAILABLE_FOR_PARTNER
+ * @throws DrmErrors::ENTRY_DRM_KEY_MANAGEMENT_POLICY_ALREADY_SET
+ * @throws KalturaErrors::PROPERTY_VALIDATION_CANNOT_BE_NULL
+ * @ksIgnored
+ */
+ public function updateAction($objectType, $objectId, KalturaKeyManagementPolicy $keyManagementPolicy)
+ {
+ $this->validateObjectType($objectType);
+
+ $result = new KalturaKeyManagementPolicy();
+ if ($objectType == KeyManagementPolicyObjectType::PARTNER)
+ {
+ $keyManagementPolicy->validatePropertyNotNull('keyManagementPolicy');
+ $partner = $this->getValidatedPartner($objectId);
+ $partner->setDrmKeyManagementPolicy($keyManagementPolicy->keyManagementPolicy);
+ $partner->save();
+ $result->keyManagementPolicy = $partner->getDrmKeyManagementPolicy();
+ }
+ else
+ {
+ $entry = $this->getValidatedEntry($objectId);
+
+ $existingStatus = $entry->getDrmKeyManagementPolicy();
+ if(!is_null($existingStatus))
+ {
+ throw new KalturaAPIException(DrmErrors::ENTRY_DRM_KEY_MANAGEMENT_POLICY_ALREADY_SET, $entry->getId());
+ }
+
+ $this->setDrmKeyManagementPolicyForEntry($entry, $keyManagementPolicy);
+ $entry->save();
+ $result->keyManagementPolicy = DrmPlugin::getDrmKeyManagementPolicy($entry);
+ }
+ return $result;
+ }
+
+ protected function setDrmKeyManagementPolicyForEntry(entry $entry, KalturaKeyManagementPolicy $keyManagementPolicy)
+ {
+ $partner = $entry->getPartner();
+ $partnerDrmKeyManagementPolicy = !is_null($partner) ? $partner->getDrmKeyManagementPolicy() : null;
+
+ if(!is_null($keyManagementPolicy->keyManagementPolicy))
+ {
+ $entry->setDrmKeyManagementPolicy($keyManagementPolicy->keyManagementPolicy);
+ }
+ elseif(!is_null($partnerDrmKeyManagementPolicy))
+ {
+ $entry->setDrmKeyManagementPolicy($partnerDrmKeyManagementPolicy);
+ }
+ else
+ {
+ $entry->setDrmKeyManagementPolicy(DrmKeyManagementPolicy::UNKNOWN);
+ }
+ }
+}
diff --git a/release-notes.md b/release-notes.md
index a87e022dd0e..1ff2e41d4ef 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -1,3 +1,10 @@
+# West-23.6.0
+## Add DRM Key Management Policy service and permissions ##
+- Issue Type: Task
+- Issue ID: PLAT-25846
+### Deployment Scripts ###
+ php deployment/updates/scripts/add_permissions/2026_07_08_drm_key_management_policy_permission.php
+
# West-23.4.0
## Disallowed from-email domain enforcement with fallback ##
- Issue Type: Task