Amazon CloudFront
Developer Guide (API Version 2010-11-01)
Print this pageEmail this pageGo to the ForumsView the PDFShare this page on TwitterShare this page on FacebookBookmark this page on DeliciousSubmit this page to RedditSubmit this page to DiggDid this page help you?  Yes  No   Tell us about it...

.NET Sample Code for Digital Element

The following sample application gets the IP address of the end user and sends the IP address to Digital Element. Digital Element returns the country code (in XML format) that corresponds with the end user's IP address. The application parses the XML and evaluates whether the value returned by Digital Element matches the blocked country code. If the end user's country is blocked, the application displays a message to that effect. If the end user's country is not blocked, the application creates a signed URL that expires in one minute, performs the substitutions necessary to ensure that the URL doesn't include any invalid characters, and redirects the user's browser to the signed URL.

<%@ Page Language="C#" AutoEventWireup="true"  %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
   <title></title>
</head>
<body>
   <form id="form1" runat="server">
   <div>
   <%=GetContent()%>
   </div>
   </form>
</body>
</html>

<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Xml.Linq" %>
<%@ Import Namespace="System.Security.Cryptography" %>
<%@ Import Namespace="System.Net" %>
<%@ Import Namespace="System.IO" %>

<script runat="server">

   // Key pair ID for the CloudFront key pair
   private const string KEYPAIR_ID = "CloudFront key pair ID";

   // Private key for the CloudFront key pair. 
   // The value is derived from opensslkey.
   private const string PRIVATE_KEY = "private key";

   // JSON policy statement used in the expiring URL
   private const string POLICY = "{{\"Statement\":[{{\"Resource\":\"{0}\",\"Condition\":{{\"DateLessThan\":{{\"AWS:EpochTime\":{1}}}}}}}]}}";

   // Digital Element user token to be passed to geolocation service call
   
   private const string USERTOKEN = "Digital Element user token"; 
   private const string GEOAPIURL = "Digital Element URL";

   // GEO IP service URL with parameters: 
   // {0} = User Token and {1} = IP Address
   private const string SERVICEURL = GEOAPIURL + "?u={0}&ip={1}"; 

   // Array of countries to block
   private static readonly string[] COUNTRIES_TO_BLOCK = new String[] {"US"};
      
   private const string BLOCKED_MSG = "Your access to this content is blocked because you're visiting from '{0}'.";

   /// <summary>
   /// Returns the IP address coming from the request object.
   /// </summary>
   /// <returns>The IP address for the request.</returns>
   private string GetOriginIpAddress()
   {
      // .NET provides Request.UserHostAddress to get the 
      // remote IP address, but this could be the IP address of the 
      // last proxy in a chain, for example, an Elastic Load Balancer.
      // Instead, use the HTTP_X_FORWARDED_FOR header if one exists.
      string forwardedIpAddresses = this.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

      if (string.IsNullOrEmpty(forwardedIpAddresses))
      {
         // Simply return the UserHostAddress.
         return Request.UserHostAddress;
      }
      else
      {
         // Get the last item in the list.
         return forwardedIpAddresses.Split(',').Last().Trim();
      }
   }
   
   /// <summary>
   /// This function returns the country code 
   /// associated with the IP address in the request object.
   /// </summary>
   /// <returns>The country code for the request.</returns>
   private string GetCountryCodeFromIP()
   {
      var ipAddress = GetOriginIpAddress();
      var serviceURL = String.Format(SERVICEURL, Server.UrlEncode(USERTOKEN), Server.UrlEncode(ipAddress));

      try
      {
         var xDoc = XDocument.Load(serviceURL);
         var res = (from w in xDoc.Descendants("response") select w).First();         
         return res.Attribute("edge-two-letter-country").Value.ToUpper();
      }
      catch(Exception ex)
      {
         // There was an error in making the web request.
         this.Response.Write(serviceURL +  "<br><br>");
         this.Response.Write(ex.Message);
         this.Response.End();
      }
      return null;
   }   
   
   /// <summary>
   /// This function returns a signed URL that will expire in 1 minute. 
   /// For more information, see "Create a URL Signature Using C# and the 
   /// .NET Framework" in the Amazon CloudFront Developer Guide: 
   /// http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/CreateSignatureInCSharp.html?r=4472
   /// </summary>
   /// <param name="resourceUrl"></param>
   /// <returns></returns>
   private string GetSignedURL(string resourceUrl)
   {
      // Compute expiration date.
      var endTimeSpanFromNow = new TimeSpan(0, 1, 0);
      var intervalEnd = (DateTime.UtcNow.Add(endTimeSpanFromNow)) - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
      var endTimestamp = (int)intervalEnd.TotalSeconds; // Timestamp must be a whole number
      var expires = endTimestamp.ToString();      
      var strPolicy = string.Format(POLICY, resourceUrl, expires);
      
      // Encrypt the policy.
      var bufferPolicy = Encoding.ASCII.GetBytes(strPolicy);
      var cryptoSHA1 = new SHA1CryptoServiceProvider();
      bufferPolicy = cryptoSHA1.ComputeHash(bufferPolicy);
      var providerRSA = new RSACryptoServiceProvider();
      providerRSA.FromXmlString(PRIVATE_KEY);
      var rsaFormatter = new RSAPKCS1SignatureFormatter(providerRSA);
      rsaFormatter.SetHashAlgorithm("SHA1");
      var signedPolicyHash = rsaFormatter.CreateSignature(bufferPolicy);
      var strSignedPolicy = System.Convert.ToBase64String(signedPolicyHash);
      
      // Build the query string with the expiration, policy signature, 
      // and CloudFront key pair ID.
      var queryString = "Expires={0}&Signature={1}&Key-Pair-Id={2}";
      queryString = String.Format(queryString, Server.UrlEncode(expires), Server.UrlEncode(strSignedPolicy), Server.UrlEncode(KEYPAIR_ID));
      var urlString = resourceUrl + "?" + queryString;
      return urlString;
   }
   
   /// <summary>
   /// Return a message saying this is blocked because of your country, or 
   /// return an image tag.
   /// </summary>
   /// <returns></returns>
   public string GetContent()
   {
      var country = GetCountryCodeFromIP();
      if (COUNTRIES_TO_BLOCK.Contains(country))
      {
         // The country returned from the call to the geolocation service 
         // is listed in the array of blocked countries.
         return string.Format(BLOCKED_MSG, country);
      }
      else
      {
         // The country returned from the call to the geolocation service 
         // is NOT listed in the array of blocked countries
         // Get a CloudFront signed URL for the content and display it.
         var url = GetSignedURL("CloudFront URL");
         var img = "<img src='{0}' />";
         return String.Format(img, url);
      }
   }   
</script>