Using Amazon S3 with Adobe Flash and Microsoft Silverlight

Articles & Tutorials>Using Amazon S3 with Adobe Flash and Microsoft Silverlight
Want to host Flash or Silverlight content in Amazon S3? Martin Streicher shows how to configure an Adobe Flash or Microsoft Silverlight cross-domain policy file so you can take advantage of Amazon S3's scale.

Details

Submitted By: Craig@AWS
AWS Products Used: Amazon S3
Created On: January 19, 2009 7:04 PM GMT
Last Updated: February 5, 2009 5:02 PM GMT

By Martin Streicher

Amazon Simple Storage Service (Amazon S3) is expansive, capable, affordable, and simple to integrate into any application. Here, learn how Flash and Silverlight applications can connect to Amazon S3.

Use the Flash and Silverlight URL Policy File to Grant Access to Data Stored in Your Amazon S3 Bucket

To bolster availability, hasten transfer, and leverage an economy of scale, more and more web developers serve valuable application assets (images, movies, and web pages, among other forms of media and data) from Amazon S3. Amazon S3 provides (seemingly) limitless storage capacity and ample network presence and bandwidth to quickly deliver content to any computer on the globe. Amazon S3 is also very affordable. To paraphrase the Amazon S3 Design Requirements, Amazon S3 eliminates the hassle, cost, limitations, and risk of self-hosted storage.

Better yet, Amazon S3 is a snap to integrate. Each developer controls his or her own collection of files—or, in Amazon S3 parlance, his or her own bucket—and a set of associated, fine-grained access controls. The contents of a bucket can be accessed and modified programatically through a Simple Object Access Protocol (SOAP) or Representational State Transfer (REST) interface, and Hypertext Transfer Protocol (HTTP) is the default download protocol, providing each datum with a familiar URL. For example, a publicly available datum stored in Amazon S3 is referred to by a URL in the form http://pail.s3.amazonaws.com/filename, where pail is the unique name of the developer's bucket and filename is the datum.

In general, access to a bucket is sufficient for any server-based application (written in Perl, Python, Ruby, or Java, say) to store and retrieve any asset from Amazon S3:

  • Public access. To make an asset publicly available, upload it to a bucket, grant open access through the bucket's access control list (ACL), and reference its Amazon S3 URL.
  • Privileged access. To protect an asset, use an Amazon S3 ACL to limit entrée to a specific set of credentialed individuals and groups. Privileged access is typically realized programmatically.
  • Secure access. The Amazon S3 service is protected by a "wildcard" Secure Sockets Layer (SSL) certificate. Simply use HTTP over SSL (HTTPS) to secure each transmission.

Client applications—software that runs within the web browser, such as Flash and Silverlight—can also use Amazon S3, albeit with some additional configuration.

Thinking Outside the Sandbox

Code downloaded from the Internet may be faulty, capricious, or downright malicious. Thus, the browser and other client-side engines must be especially circumspect. To protect the user, a browser-based client application typically runs in a sandbox, or something of a virtual (and hopefully) impenetrable vault that separates client code from the underlying operating system, file system, network resources, and other sandboxes. That said, a client is not necessarily isolated; it can access resources using the sandbox as proxy, usually with strict rules. Thus, data the sandbox reads and potentially writes must be equally guarded.

For example, by default, a Flash application (or SWF file) may only read an asset served from the exact same host that serves the Flash application itself. According to this fiat, if the SWF file was downloaded from www.example.com, it can access other files on www.example.com but no files from www1.example.com or any other sub-domain in example.com.

However, because sharing files among many hosts in one domain and across domains is common, desirable, and practical on the modern Internet—the very essence of Amazon S3—an exception to the rule can be made if you so elect.

If you want to place your Flash application in your Amazon S3 bucket, you have two options:

  • Lump the SWF file and all its associated assets into the same bucket.
  • Use a URL policy file to grant inter-system and cross-domain access.

The former solution is terribly simple to realize: Deposit the application and all its assets in your Amazon S3 bucket. However, if you do not want to serve your application directly from your bucket, if you want to share your assets with other applications, or if you need to access data from another developer's bucket or server, you must grant or be granted express permission to access data from across disparate domains.

As a representative example, by default and convention, a Flash application served directly from the server www.example.com cannot access an Extensible Markup Language (XML) file from the site's Amazon S3 bucket. Further, an SWF file cannot modify the pixels of an image stored in a bucket unless given express entitlement, according to the Flash 9 documentation.

Flash and Silverlight applications are given express permission with the URL policy file. Let's see how it works.

URL Policy Files

If you use Flash or Silverlight, the URL policy file (or cross-domain policy file when placed in an Amazon S3 bucket) grants license to read data from the bucket. Each entry in a cross-domain policy file specifies a set of one or more domains and the corresponding privileges for the set. You can place a cross-domain policy file at the root of your bucket and within each sub-folder to fine-tune access, unless the policy file at the root (the master policy file) forbids such configuration.

Here is a sample master policy file for use with Flash. The file must be named crossdomain.xml. (Silverlight has its own master policy file—clientaccesspolicy.xml—but also honors Flash's crossdomain.xml file if its own policy file is not provided.)

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE cross-domain-policy SYSTEM
  "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <site-control permitted-cross-domain-policies="master-only" />
  <allow-access-from domain="*.example.com" />
  <allow-http-request-headers-from domain="*.example.com" 
    headers="SOAPAction" />
</cross-domain-policy>

Briefly, this policy file dictates that non-master (non-root) policy files are disallowed (site-control permitted-cross-domain-policies="master-only") and strictly limits SOAP requests (allow-http-request-headers-from="SOAPAction,Content-Type") that originate from hosts in the domain example.com (domain="*.example.com"). In general, an SWF file cannot send a header to a remote host without such an explicit grant.

Let's create a small Flash application and a similar Silverlight application to demonstrate the use of a URL policy file. To follow the examples, you must have:

  • An Amazon S3 bucket. If you don't have an Amazon Web Services&0153; (AWS) account yet, sign-up is quick and easy.
  • Access to your web server. To deploy your Flash or Silverlight application, data, and one or more cross-domain policy files, you must have File Transfer Protocol (FTP), Secure FPT (SFTP), or Secure Shell (SSH) access to your web server.
  • A Flash and/or Silverlight software development kit (SDK). You can download Flash authoring software from the Adobe Flash Developer Center; Silverlight tools are available from the Silverlight home page. You must already have Microsoft Visual Studio 2008 with Service Pack 1 to install the Silverlight tools.
  • The Debug Flash Player. The Debug Flash Player logs each access of a URL policy file and helps debug implementations and rules. The Adobe Flash Builder integrated development environment (IDE) installs the Debug Flash Player, and other Flash software may install it, too. As an alternative, you can download the Debug Flash Player separately from the Flash Player Downloads page.

You may also find it helpful to have an HTTP protocol "sniffer," or monitor, such as the Mozilla Firefox plug-in Live HTTP Headers. An HTTP protocol sniffer can reveal headers and traffic and make it easier to debug requests.

Connect to Amazon S3 in a Flash

As mentioned earlier, an SWF file cannot read data from a "remote" host without explicit consent. (You can find the rationale for this mandate and a complete description of Flash security measures in the white paper, "Adobe Flash Player 9 Security.")

Let's create a simple Flash application to download and display portions of an inventory list. Use a URL policy file to grant cross-domain access:

  1. Ensure that the Debug Flash Player (the most recent version as of this writing is 9.0.124.0) is installed on your client machine and within the browser of your choice.
  2. Enable policy file logging:
    1. Go to your home directory and create the file mm.cfg with the following two lines:
      PolicyFileLog=1        # Enables policy file logging
      PolicyFileLogAppend=1  # Optional; do not clear log at startup
      

      (The exact location of your home directory depends on your platform. In Linux and Mac OS X, it's /home/name or /Users/name. In Windows Vista, it's C:\Users\name, and on older versions of Windows, it's C:\Documents and Settings\name. Your login name is name. Refer to the section, "Workflows," in "Policy file changes in Flash Player 9 and Flash Player 10" for all the details.)

    2. Create a directory to contain the log file. The directory's location and name again depend on your platform. Use this guide, and be mindful of the use of upper- and lowercase letters:
      • Windows: C:\Documents and Settings\username\Application Data\Macromedia\Flash Player\Logs
      • Windows Vista: C:\Users\username\AppData\Roaming\Macromedia\Flash Player\Logs
      • Macintosh: /Users/username/Library/Preferences/Macromedia/Flash Player/Logs
      • Linux: /home/username/.macromedia/Flash_Player/Logs

      In Linux, for instance, you would type:

      mkdir -p /home/username/.macromedia/Flash_Player/Logs
      
    3. Run any SWF in Debug Flash Player.

      Each time an SWF file runs, it should emit one or more messages to the file policyfiles.txt. At least one line should be written each time you open an SWF file. It should resemble this:

      OK: Root-level SWF loaded: 
        http://www.example.com/bin-release/Example.swf
      

      If you see such a line, logging is enabled and functioning properly. (You can find an index of possible messages in the section, "Log Message Reference," in "Policy file changes in Flash Player 9 and Flash Player 10.")

  3. Create the application.

    The following MXML code is minimal yet sufficient for the purposes of this demonstration. (This code is derived from an example found in Marco Casario's book, Flex Solutions: Essential Techniques for Flex 2 and 3 Developers, and is used with permission.)

    <?xml version="1.0"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" 
        creationComplete="start( event )">
      <mx:List id="list"/> 
      <mx:Button label="Lookup" click="loader.load( request );"/>
      <mx:Script> 
        <![CDATA[ 
          private var loader:URLLoader; 
          private var request:URLRequest =  
            new URLRequest( "http://example-media.s3.amazonaws.com/store.xml" ); 
    
          [Bindable] 
          private var result:XMLList; 
          private function start( event:Event ):void { 
            XML.ignoreWhitespace = true; 
            loader = new URLLoader( ); 
            loader.addEventListener( Event.COMPLETE, finish ); 
          } 
    
          private function finish( event:Event ):void {
            result = new XMLList( loader.data ); 
            list.dataProvider = result.item.name; 
          } 
        ]]> 
      </mx:Script> 
    </mx:Application>
    

    When you click Lookup, the code loads a small XML file from a server and displays the names of all items found. When you create the application, be sure to change the URL in the URLRequest() function to point to your Amazon S3 bucket.

  4. Create a data file named store.xml with the following data:
    <store> 
      <item> 
        <id>1</id> 
        <name>Hot Wheels</name> 
      </item> 
      <item> 
        <id>3</id> 
        <name>Mini-Mates</name> 
      </item> 
    </store>  
    
  5. Copy store.xml to the root of your Amazon bucket, then edit its ACL to allow global Read access.

    (If you use the Firefox browser, the Amazon S3 Firefox Organizer add-on is a convenient, helpful tool for managing the files in your bucket and your files' ACLs.)

  6. Compile your MXML application, export the release build, copy the release build to the root of your Amazon S3 bucket, then run the SWF from your bucket.

    (Be aware that the debug version of your code does not exercise the URL policy file: You must run the release SWF file.)

    Because the SWF and the data file are located concordantly, a policy file is superfluous. Glance at your policy file log: It should indicate only that the root-level (or primary) SWF file was loaded successfully.

  7. Delete the SWF from your bucket, and copy the original, released SWF file to your own server.
  8. Run the application from your server, and refer to the policy file log.

    It should contain something like this:

    OK: Root-level SWF loaded: file:///.../bin-release/Example.swf
    OK: Searching for <allow-access-from> in policy files to authorize data 
      loading from resource at http://example-media.s3.amazonaws.com/store.xml 
      by requestor from file:///.../bin-release/Example.swf
    Warning: Failed to load policy file from 
      http://example-media.s3.amazonaws.com/crossdomain.xml
    Error: Request for resource at http://example-media.s3.amazonaws.com/store.xml 
      by requestor from file:///.../bin-release/Example.swf is denied due to 
      lack of policy file permissions.  
    

    As expected, Flash prevents access to the data file, because there was no exact match between the hostname of the SWF file and the hostname of the data file. You can allay the error with a cross-domain policy file.

  9. Place the following code in the root directory of your Amazon S3 bucket, making sure to change the domain attribute of the allow-access-from element to refer to your domain or sub-domain.
    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE cross-domain-policy SYSTEM
      "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
    <cross-domain-policy>
      <site-control permitted-cross-domain-policies="master-only" />
      <allow-access-from domain="*.example.com" />
    </cross-domain-policy>
    
  10. Run your application anew from your own server.

    The application should work, as reflected by an entry in the policy file log similar to this:

    OK: Policy file accepted: 
      http://example-media.s3.amazonaws.com/crossdomain.xml
    OK: Request for resource at http://example-media.s3.amazonaws.com/store.xml 
      by requestor from http://www.example.com/example.swf is 
      permitted due to policy file at 
      http://example-media.s3.amazonaws.com/crossdomain.xml
    

    Success!

Typically, a Flash cross-domain policy file is placed in the root folder of your bucket. However, you can also place the policy file in any sub-folder within your bucket to limit access to a subset of resources. A non-master (non-root) policy file only grants access to data within its own directory and within its directory's subdirectories.

You can find a complete description of the Flash cross-domain policy file syntax online at the Adobe Developer Center.

Calling a Web Service from Silverlight

Like an SWF file, a Silverlight application can access resources across a domain boundary through a URL policy file. Silverlight's native cross-domain policy file is named clientaccesspolicy.xml. Silverlight also recognizes and honors Flash's crossdomain.xml file, with two caveats. If you use crossdomain.xml with Silverlight version 2, the file must be in the root directory of your site, and the policy file must be configured to allow access to the service from any domain or it is not recognized by Silverlight 2. This crossdomain.xml file works with Silverlight 2:

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
  "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-http-request-headers-from domain="*" />
</cross-domain-policy>

Scanning for policy files, Silverlight looks first for clientaccesspolicy.xml; if a file of that name does not exist, Silverlight then looks for the alternate crossdomain.xml. If both files are provided, the crossdomain.xml is ignored.

For example, to call a web service (written in Visual Basic, say) hosted on vbws.example.com from a Silverlight application hosted on www.example.com, you must grant access by placing an appropriately permissive clientaccesspolicy.xml file or an equivalent crossdomain.xml file in the root of the www.example.com Web site.

Silverlight is extremely cautious about cross-domain access. Even a difference in port numbers between a client and server (say, when both are running on your local machine during development as localhost:1111 and localhost:2222, respectively) requires a specific access policy.

Here is an example clientaccesspolicy.xml file identical in purpose to the sample Flash URL policy file shown earlier. This policy file allows any machine in the example.com domain to make a SOAP call to request an asset. (This example originally appeared in the blog of Silverlight developer Tim Heuer and is used with permission.)

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="http://*.example.com"/>
      </allow-from>
      <grant-to>
        <resource include-subpaths="false" path="/"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

You can find a complete description of Silverlight's URL policy file format on the Microsoft Developer Network (MSDN).

Building a complete web service for use with Silverlight is beyond the scope of this article. For detailed instructions on coding such a service, see "How to Access a Service from Silverlight using Visual Studio." However, there's no need to build a new web service for the purpose of this demonstration. Every Amazon S3 bucket provides a SOAP interface of its own! If your bucket is example-media.s3.amazonaws.com, your SOAP endpoint is http(s)://example-media.s3.amazonaws.com/soap. Visual Studio's tools can automatically generate the proxy code for a Microsoft .NET application to call Amazon's SOAP services. To permit the call, simply place a cross-domain policy file in the root of your bucket.

Of course, if you have a server with your own web services and you want to share those services with other sites' Silverlight applications, just create an appropriate clientaccesspolicy.xml file in the root of your web server.

Stay Vain with a CNAME

If you prefer, you can obscure the use of Amazon S3 from users with a simple CNAME record. Create a CNAME to serve your application and its assets from the same "virtual" host.

For instance, given the domain example.com, a bucket named example-media, and a datum called grammy.mp3, the addition of the CNAME record . . .

media  IN  CNAME  example-media.s3.amazonaws.com.

. . . allows the MPEG-3 file to be referred to as the more eponymous http://media.example.com/grammy.mp3.

You must have access to your domain name server to create a CNAME.

And although access through a bucket alias—such as example-media.s3.amazonaws.com—works with Amazon S3's SSL certificates, using a CNAME does not.

Weaving a Wider Web with Amazon S3

With the invention of Flash and Silverlight, a web application can now run on any platform yet be as rich and interactive as native, desktop analogs. Alas, a web application is only as reliable as its underlying infrastructure—server, network, bandwidth—and its security. Happily, with Amazon S3, you need not worry about uptime any longer. And with cross-domain policy files, you can combine your great application, leverage all those "9s" of up time, and keep your application and users safe.

Additional Resources

Amazon S3 product page

Other Amazon S3 articles and tutorials

About the Author

Martin Streicher is a freelance Ruby on Rails software developer, a widely published technology writer, and the former Editor-in-Chief of Linux Magazine. He collects art and toys and is an avid reader of the scientific works of Dr. Bunsen Honeydew. Martin has an advanced degree in Computer Science from Purdue University. He lives in Raleigh, NC.

©2014, Amazon Web Services, Inc. or its affiliates. All rights reserved.