// </ConfigureWidevineLicenseTempate> /// <summary> /// Configures FairPlay policy options. /// </summary> /// <returns></returns> // <ConfigureFairPlayPolicyOptions> private static ContentKeyPolicyFairPlayConfiguration ConfigureFairPlayPolicyOptions() { string askHex = ""; string FairPlayPfxPassword = ""; var appCert = new X509Certificate2("FairPlayPfxPath", FairPlayPfxPassword, X509KeyStorageFlags.Exportable); byte[] askBytes = Enumerable .Range(0, askHex.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(askHex.Substring(x, 2), 16)) .ToArray(); ContentKeyPolicyFairPlayConfiguration fairPlayConfiguration = new ContentKeyPolicyFairPlayConfiguration { Ask = askBytes, FairPlayPfx = Convert.ToBase64String(appCert.Export(X509ContentType.Pfx, FairPlayPfxPassword)), FairPlayPfxPassword = FairPlayPfxPassword, RentalAndLeaseKeyType = ContentKeyPolicyFairPlayRentalAndLeaseKeyType .PersistentUnlimited, RentalDuration = 2249 }; return(fairPlayConfiguration); }
/// <summary> /// Configures FairPlay license template. /// </summary> /// <param name="askHex">The ASK hex string.</param> /// <param name="fairPlayPfxPath">The path of the PFX file.</param> /// <param name="fairPlayPfxPassword">The password for the PFX.</param> /// <returns>ContentKeyPolicyFairPlayConfiguration</returns> private static ContentKeyPolicyFairPlayConfiguration ConfigureFairPlayLicenseTemplate(string askHex, string fairPlayPfxPath, string fairPlayPfxPassword) { byte[] askBytes = Enumerable .Range(0, askHex.Length) .Where(x => x % 2 == 0) .Select(x => Convert.ToByte(askHex.Substring(x, 2), 16)) .ToArray(); byte[] buf = File.ReadAllBytes(fairPlayPfxPath); string appCertBase64 = Convert.ToBase64String(buf); ContentKeyPolicyFairPlayConfiguration objContentKeyPolicyPlayReadyConfiguration = new ContentKeyPolicyFairPlayConfiguration { Ask = askBytes, FairPlayPfx = appCertBase64, FairPlayPfxPassword = fairPlayPfxPassword, RentalAndLeaseKeyType = ContentKeyPolicyFairPlayRentalAndLeaseKeyType.DualExpiry, RentalDuration = 0, OfflineRentalConfiguration = new ContentKeyPolicyFairPlayOfflineRentalConfiguration() { StorageDurationSeconds = 300000, PlaybackDurationSeconds = 500000 } }; return(objContentKeyPolicyPlayReadyConfiguration); }
/// <summary> /// Create the content key policy that configures how the content key is delivered to end clients /// via the Key Delivery component of Azure Media Services. /// </summary> /// <param name="client">The Media Services client.</param> /// <param name="resourceGroupName">The name of the resource group within the Azure subscription.</param> /// <param name="accountName"> The Media Services account name.</param> /// <param name="contentKeyPolicyName">The name of the content key policy resource.</param> /// <returns></returns> private static async Task <ContentKeyPolicy> GetOrCreateContentKeyPolicyAsync( IAzureMediaServicesClient client, ConfigWrapper config, string contentKeyPolicyName) { // Call Media Services API to create or update the policy. Console.WriteLine("Creating or updating the content key policy..."); ContentKeyPolicyOpenRestriction restriction = new(); ContentKeyPolicyFairPlayConfiguration fairPlay = ConfigureFairPlayLicenseTemplate(config.AskHex, config.FairPlayPfxPath, config.FairPlayPfxPassword); List <ContentKeyPolicyOption> options = new() { new ContentKeyPolicyOption() { Configuration = fairPlay, Restriction = restriction } }; Console.WriteLine("Creating or updating the content key policy..."); ContentKeyPolicy policy = await client.ContentKeyPolicies.CreateOrUpdateAsync(config.ResourceGroup, config.AccountName, contentKeyPolicyName, options); return(policy); }
public static async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation($"AMS v3 Function - CreateContentKeyPolicy was triggered!"); string requestBody = new StreamReader(req.Body).ReadToEnd(); dynamic data = JsonConvert.DeserializeObject(requestBody); if (data.contentKeyPolicyName == null) { return(new BadRequestObjectResult("Please pass contentKeyPolicyName in the input object")); } string contentKeyPolicyName = data.contentKeyPolicyName; string contentKeyPolicyDescription = null; if (data.contentKeyPolicyDescription == null) { contentKeyPolicyDescription = data.contentKeyPolicyDescription; } string mode = data.mode; if (mode != "simple" && mode != "advanced") { return(new BadRequestObjectResult("Please pass valid mode in the input object")); } // // Simple Mode // if (mode == "simple") { if (data.policyOptionName == null) { return(new BadRequestObjectResult("Please pass policyOptionName in the input object")); } if (data.openRestriction == null) { return(new BadRequestObjectResult("Please pass openRestriction in the input object")); } if (data.openRestriction == false) { if (data.audience == null && data.issuer == null && data.tokenType == null && data.tokenKeyType == null && data.tokenKey == null) { return(new BadRequestObjectResult("Please pass required parameters for Token Restriction in the input object")); } } } // // Advanced Mode // if (mode == "advanced") { if (data.contentKeyPolicyOptions == null) { return(new BadRequestObjectResult("Please pass contentKeyPolicyOptions in the input object")); } } MediaServicesConfigWrapper amsconfig = new MediaServicesConfigWrapper(); ContentKeyPolicy policy = null; JsonConverter[] jsonReaders = { new MediaServicesHelperJsonReader(), new MediaServicesHelperTimeSpanJsonConverter() }; try { IAzureMediaServicesClient client = MediaServicesHelper.CreateMediaServicesClientAsync(amsconfig); policy = client.ContentKeyPolicies.Get(amsconfig.ResourceGroup, amsconfig.AccountName, contentKeyPolicyName); if (policy == null) { List <ContentKeyPolicyOption> options = new List <ContentKeyPolicyOption>(); if (mode == "simple") { ContentKeyPolicyOption option = new ContentKeyPolicyOption(); option.Name = data.policyOptionName; // Restrictions if ((bool)data.openRestriction) { option.Restriction = new ContentKeyPolicyOpenRestriction(); } else { ContentKeyPolicyTokenRestriction restriction = new ContentKeyPolicyTokenRestriction(); restriction.Audience = data.audience; restriction.Issuer = data.issuer; string tokenType = data.tokenType; switch (tokenType) { case "Jwt": restriction.RestrictionTokenType = ContentKeyPolicyRestrictionTokenType.Jwt; break; case "Swt": restriction.RestrictionTokenType = ContentKeyPolicyRestrictionTokenType.Swt; break; default: return(new BadRequestObjectResult("Please pass valid tokenType in the input object")); } string tokenKeyType = data.tokenKeyType; switch (tokenKeyType) { case "Symmetric": restriction.PrimaryVerificationKey = new ContentKeyPolicySymmetricTokenKey(Convert.FromBase64String(data.tokenKey.ToString())); break; case "X509": restriction.PrimaryVerificationKey = new ContentKeyPolicyX509CertificateTokenKey(Convert.FromBase64String(data.tokenKey.ToString())); break; case "RSA": restriction.PrimaryVerificationKey = new ContentKeyPolicyRsaTokenKey(); break; default: return(new BadRequestObjectResult("Please pass valid tokenKeyType in the input object")); } if (data.tokenClaims != null) { restriction.RequiredClaims = new List <ContentKeyPolicyTokenClaim>(); String[] tokenClaims = data.tokenClaims.ToString().Split(';'); foreach (string tokenClaim in tokenClaims) { String[] tokenClaimKVP = tokenClaim.Split('='); if (tokenClaimKVP.Length == 2) { restriction.RequiredClaims.Add(new ContentKeyPolicyTokenClaim(tokenClaimKVP[0], tokenClaimKVP[1] == "null" ? null : tokenClaimKVP[1])); } else if (tokenClaimKVP.Length == 1) { restriction.RequiredClaims.Add(new ContentKeyPolicyTokenClaim(tokenClaimKVP[0])); } else { return(new BadRequestObjectResult("Please pass valid tokenClaims in the input object")); } } } if (data.openIdConnectDiscoveryDocument != null) { restriction.OpenIdConnectDiscoveryDocument = data.openIdConnectDiscoveryDocument; } option.Restriction = restriction; } // Configuration string configurationType = data.configurationType; switch (configurationType) { case "ClearKey": option.Configuration = new ContentKeyPolicyClearKeyConfiguration(); break; case "FairPlay": ContentKeyPolicyFairPlayConfiguration configFairPlay = new ContentKeyPolicyFairPlayConfiguration(); configFairPlay.Ask = Convert.FromBase64String(data.fairPlayAsk); configFairPlay.FairPlayPfx = data.fairPlayPfx; configFairPlay.FairPlayPfxPassword = data.fairPlayPfxPassword; switch (data.faiPlayRentalAndLeaseKeyType) { case "Undefined": configFairPlay.RentalAndLeaseKeyType = ContentKeyPolicyFairPlayRentalAndLeaseKeyType.Undefined; break; case "PersistentLimited": configFairPlay.RentalAndLeaseKeyType = ContentKeyPolicyFairPlayRentalAndLeaseKeyType.PersistentLimited; break; case "PersistentUnlimited": configFairPlay.RentalAndLeaseKeyType = ContentKeyPolicyFairPlayRentalAndLeaseKeyType.PersistentUnlimited; break; default: return(new BadRequestObjectResult("Please pass valid faiPlayRentalAndLeaseKeyType in the input object")); } configFairPlay.RentalDuration = data.faiPlayRentalDuration; break; case "PlayReady": ContentKeyPolicyPlayReadyConfiguration configPlayReady = new ContentKeyPolicyPlayReadyConfiguration(); configPlayReady.Licenses = JsonConvert.DeserializeObject <List <ContentKeyPolicyPlayReadyLicense> >(data.playReadyTemplates.ToString(), jsonReaders); if (data.playReadyResponseCustomData != null) { configPlayReady.ResponseCustomData = data.playReadyResponseCustomData; } option.Configuration = configPlayReady; break; case "Widevine": ContentKeyPolicyWidevineConfiguration configWideVine = JsonConvert.DeserializeObject <ContentKeyPolicyWidevineConfiguration>(data.widevineTemplate.ToString(), jsonReaders); option.Configuration = configWideVine; break; default: return(new BadRequestObjectResult("Please pass valid configurationType in the input object")); } options.Add(option); } else if (mode == "advanced") { options = JsonConvert.DeserializeObject <List <ContentKeyPolicyOption> >(data.contentKeyPolicyOptions.ToString(), jsonReaders); } foreach (ContentKeyPolicyOption o in options) { o.Validate(); } policy = client.ContentKeyPolicies.CreateOrUpdate(amsconfig.ResourceGroup, amsconfig.AccountName, contentKeyPolicyName, options, contentKeyPolicyDescription); } } catch (ApiErrorException e) { log.LogError($"ERROR: AMS API call failed with error code: {e.Body.Error.Code} and message: {e.Body.Error.Message}"); return(new BadRequestObjectResult("AMS API call error: " + e.Message + "\nError Code: " + e.Body.Error.Code + "\nMessage: " + e.Body.Error.Message)); } catch (Exception e) { log.LogError($"ERROR: Exception with message: {e.Message}"); return(new BadRequestObjectResult("Error: " + e.Message)); } return((ActionResult) new OkObjectResult(new { policyId = policy.PolicyId })); }