Configure Country Access Control in CloudFront Using .NET

The following sample application gets the IP address of the end user and sends the IP address to the IP2Location.io IP Geolocation API. The API returns a JSON string containing the country code that corresponds with the end user’s IP address. The application then evaluates whether the value returned by IP2Location.io API matches the blocked country code. If the end user’s country is blocked, the application will show 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.

/*
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 */
 
 
<%@ Page Language="C#" AutoEventWireup="true" Inherits="CloudFront.cloudfront"  %>
 
<!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>Example of Country Access Control</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" %>
<%@ Import Namespace="System.Text.RegularExpressions" %> 
 
<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}}}}}}}]}}";
 
   // IP2Location.io API key to be passed to geolocation service call
 
   private const string API_KEY = "IP2Location.io key";
 
   // IP2Location.io API
   // {0} = IP Address and {1} = IP2Location.io API key
   private const string APIURL = "https://api.ip2location.io/?ip={0}&key={1}";
 
   // Setting array of countries to block
   private static readonly string[] BLOCKED_COUNTRIES = new string[] {"VN"};
 
   private const string BLOCKED_MSG = "You are not authorized to view the content because you're visiting from '{0}'.";
 
 
   // Get IP address of visitor and determine the country code
   private string GetCountryCodeFromIP()
   {
       // Get IP address from HTTP_X_FORWARDED_FOR
       string ip_address = this.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
 
       // If HTTP_X_FORWARDED_FOR does not exists or no IP address
       if (string.IsNullOrEmpty(ip_address))
       {
           // Get UserHostAddress.
           ip_address = Request.UserHostAddress;
       }
       else
       {
           // Get the last item in the list.
           ip_address = ip_address.Split(',').Last().Trim();
       }
 
       // Format the API_URL with the IP address and API key
       var API_URL = string.Format(APIURL, Server.UrlEncode(ip_address), Server.UrlEncode(API_KEY));
 
      // Setting up connection to geolocation service
      try
      {
          var request = HttpWebRequest.Create(APIURL);
          var response = request.GetResponse().GetResponseStream();
          var reader = new StreamReader(response);
          var strRes = reader.ReadToEnd();
          reader.Close();
          Regex r = new Regex(@"""country_code"":""([^\""]+)""");
          Match m = r.Match(strRes);
          if (m.Success)
          {
            return m.Groups[1].Value;
          }
          return "-";
      }
      catch(Exception ex)
      {
         // If error occur in making the web request.
         this.Response.Write(API_URL +  "<br><br>");
         this.Response.Write(ex.Message);
         this.Response.End();
      }
      return null;
   }
 
   // Creates a signed URL which expires in 1 minute
   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;
   }
 
   // Display Cloud Front signed URL and image if user is not blocked and display country blocked message if user is blocked
   public string GetContent()
   {
      var country = GetCountryCodeFromIP();
      if (!BLOCKED_COUNTRIES.Contains(country))
      {
         // Signed URL with Cloud Front if country code is not blocked
         var url = GetSignedURL("CloudFront URL");
         var img = "<img src='{0}' />";
         return String.Format(img, url);
      }
      else
      {
         // Returns a string of message if country code is blocked
         return string.Format(BLOCKED_MSG, country);
      }
   }
</script>

Was this article helpful?

Related Articles