Silverlight Hack

Silverlight & related .NET technologies

About Me

Welcome to Silverlighthack.com.  This is a site where you can find many articles on Silverlight, Windows Phone 7 and .NET related technologies.  

My name is Bart Czernicki.  I have been working with computers since 1988 and have over 12 professional years in the IT field focusing on architecture, technology strategy and product management.  I currently work as a Sr. Software Architect at a large software development company.

Below is the cover of my new book that shows how Silverlight's unique RIA features can be applied to create next-generation business intelligence (BI 2.0) applications.

Silverlight 4 Business Intelligence Soft 

Contact: bartczernicki@gmail.com

View Bart Czernickis profile on LinkedIn

NONE of the comments or opinions expressed here should be considered ofmy past or current employer(s).  The code provided is as-is without anyguarantees or warranties.

Silverlight clientaccesspolicy.xml files for the Enterprise (Part 1 of 2)

I decided to move this article up the chain in my backlog of articles as I have come across this scenario numerous times on the http://silverlight.net/ forums. This article will give some basic information that has been covered on numerous other sites and times and give some additional insight on how to handle cross-domain issues in enterprise Silverlight service deployments.

Note: This article is pretty long and doesn't really fit well into a blog format (which I find is very limited for effectivily presenting technical ideas on a larger scale).  I am going to start moving some of my bigger articles into possible whitepaper format as well.

Contents of this article (Part 1 of 2):

  • Background Information about cross-domain service access in Silverlight
  • Deploying cross-domain policy files on Enterprise Servers
    • Examples of Enterprise cross-domain configurations
    • Problems with maintaining the clientaccesspolicy.xml file manually
  • HttpHandler solution for dynamic clientaccesspolicy.xml files for the Enterprise
    • Walkthrough - Creating a basic HttpHandler for clientaccesspolicy.xml files
    • Basic Clientaccesspolicy Handler Part 1 - HttpHandler basics
    • Basic Clientaccesspolicy Handler Part 2 - Adding some code
  • Deploying managed HttpHandlers on IIS 7.0
    • Testing managed HttpHandlers (inside the browser)
    • TroubleShooting
  • Summary
  • Download link for HttpHandler source code

Background Information about cross-domain service access in Silverlight

Silverlight 2 uses services as its primary source of retrieving data across domain boundaries.  Once you enter the services and web application domain, you are exposing your content to malicious attacks.  One way Silverlight prevents its applications from launching malicious attacks on other sites is through opt-in cross-domain access.  This means the site has to say yes in order to receive and respond to requests from a particular domain.  This opt-in feature is controlled by a clientaccesspolicy.xml file.  If you have done any WCF programming with Silverlight, this should be familiar to you. If not, check the basic information on the MSDN site here.

Suppose that we have a Silverlight application hosted on  http://contoso.com/ (means the main/initial XAP file).  This application has a service backend that retrieves data from http://mycontososervice.com/.  These are obviously on two seperate domains and we have a cross-domain issue.  By default, this scenario will not work.  We need to create a clientaccesspolicy.xml file on the http://mycontososervice.com/ site that will allow calls from http://contoso.com/.  The location of the file must be located on the root of the site (http://mycontososervice.com/clientaccesspolicy.xml).

Here is a graphical representation of what is going on:

The clientaccesspolicy.xml file is located where the service is being hosted.  This is a very important point.  Most Silverlight developers that are starting out make a mistake in that they think the clientacesspolicy.xml is deployed onto the server where the Silverlight application is hosted.  This is not true and can cause many debugging headaches.  The clientacesspolicy.xml NEEDS to be deployed on the server hosting the WCF service so that Silverlight can properly consume it. 

Note: For simplicity reasons, I am not adding the crossdomain.xml file which is used by Flash.  Silverlight also uses this file in case the clientaccesspolicy.xml doesn't exist.  This is done for obvious reasons as Flash/Flex has a bigger install base and Silverlight is simply leveraging a possibly pre-existing cross-domain file.

 

Example of the format of the clientaccesspolicy.xml file that grants all domains access:

Example of the format of the clientaccesspolicy.xml file that grants access ONLY to contoso.com:

 Note: Notice how the only change was to add the <domain uri="http://contoso.com"/>.  This is more secure and other domains will be disallowed from making service calls.

Clientaccesspolicy.xml file that only grants service access from contoso.com (other requests are not fulfilled):

Deploying cross-domain policy files on Enterprise Servers

One of the key aspects of a clientaccesspolicy.xml file is that it needs to be accessed on the root of the website.  In our example above, the request is http://mycontososervice.com/clientaccesspolicy.xml.  In order to achieve this on IIS, we would simply place the clientaccesspolicy.xml file on the root of our website (default IIS: c:\inetpub\wwwroot folder).  If you want to grant multiple domains access, an admin simply can modify the clientaccesspolicy.xml file.

As mentioned above, Flash has an equivalent cross-domain configuration file to Silverlight called the crossdomain.xml file.  This file has a different format; however, it serves the same purpose as the Silverlight clientaccesspolicy.xml file.  Let's take look at how some of the largest companies based on services use this file.  You can try this yourself by using any browser.

Examples of Enterprise cross-domain configurations:

Example of the Amazon crossdomain.xml file (http://www.amazon.com/crossdomain.xml) :

Example of the MySpace crossdomain.xml file (http://www.myspace.com/crossdomain.xml):

Some notes to take away from the two examples above:

  • Root domains are different and this obviously makes the domain calls cross-domain.  (i.e., amazon.com != amazon.fr).  You need to list all the different domains
  • Sub domains also define cross-domain calls (i.e., lads.myspace.com != myspace.com).  You need to list the different sub domains.
  • Secure and unsecure (http vs. https protocols) also make the calls cross-domain.

As you can see, maintaining these files can get quite complex very quickly in more advanced scenarios.  These files need to be accurate and improperly formatted xml config files can cause the validation of the configuration to be invalidated.

Problems with maintaining the clientaccesspolicy.xml file manually

Maintaing the clientaccesspolicy.xml file manually on a single or even a couple of servers is not a problem.  However, maintaining complex properly validated clientaccesspolicy.xml files on multiple servers or domains can be quite challenging.  One single fat finger and the file can invalidate all service calls.  Improperly adding or not removing a domain can cause a serious security violation.

Scenarios where manually maintaining the clientaccesspolicy.xml file manually can be an issue:

  • You are maintaining 2 different RIAs and want to keep both XML files in sync (I know Silverlight can use Flash's file, but we want to prepare for mass Silverlight deployments) 
  • The clientaccesspolicy.xml file is complex.  You have over 10-15 domains, subdomains and protocols that all have to work.
  • The clientaccesspolicy.xml is dynamic
    • The solution you offer allows clients to access the site through specialized domain (i.e., client.mydomain.com, client2.mydomain.com)
    • Architecture/hosting uses SaaS model (You host services others can consume)
    • Lots of changes occur to the file and you want to eliminate the "human factor".
  • The web service server is part of a web server farm or a cluster.  The files need to be in sync almost instantaneously.
  • Client anonymity is important (i.e., You don't want to expose who is consuming your services)

Obviously some of these challenges can be mitigated with other security measures and designs.  However, let's assume that in your scenario you have a properly working architecture/deployment and the clientaccesspolicy.xml file is becoming a maintenance nightmare.  What can you do?

HttpHandler solution for dynamic clientaccesspolicy.xml files for the Enterprise

To overcome complex cross-domain scenarios by using some of the more advanced features of ASP.NET, we can mitigate some of the manual work that comes with creating cross-domain policy files.  HttpHandlers are one way to solve some of the problems I listed above.

Httphandlers are a pretty powerful tool for ASP.NET applications that extend ISAPI extensions.  There are many uses for Httphandlers and one of them is to map certain web requests to specific handler functionality.  (I am not going to go over handlers in detail.  If you need more information, try this link: http://www.15seconds.com/issue/020417.htm).  We can create an HttpHandler that will see a request for a clientaccesspolicy.xml file.  Instead of manually copying the file off of the root server, we can generate the file dynamically.

Walkthrough - Creating a basic HttpHandler for clientaccesspolicy.xml files

We are going to create a few sample handlers and add functionality to each one.

Basic Clientaccesspolicy Handler  Part 1 - HttpHandler basics

  1. Open Visual Studio 2008 and create a new project.
  2. Select "Class Library" and let's call the project "SilverlightCrossDomainHandler" (Note: Do NOT create a Silverlight Class library.)
  3. Add a reference to the System.Web assembly. (We are going to be creating an ASP.NET HttpHandler which requires the IHttpHandler interface found in the System.Web assembly)
  4. Add a new class to the project and call it BasicClientaccesspolicyHandler.cs.
  5. Navigate to the class and change its access modifier to be public.
  6. Add a using statement "using System.Web;".  (This is needed as we will be implementing the IHttpHandler interface.)
  7. Implement the IHttpHandler interface by simply typing ": IHttpHandler" after the BasicClientaccesspolicyHandler class name.
  8. Right-click on the IHttpHandler name and select Implement Interface -> Implement Interface.  This will create the methods we need to implement for this handler to work.

You should have something like this now:  (If not, simply just copy and paste the code from below)

  using System;  using System.Collections.Generic;  using System.Linq;  using System.Text;  using System.Web;  namespace SilverlightCrossDomain  {  public class BasicClientaccesspolicyHandler : IHttpHandler   {  #region IHttpHandler Members  public bool IsReusable  {  get { throw new NotImplementedException(); }  }  public void ProcessRequest(HttpContext context)  {  throw new NotImplementedException();  }  #endregion  }  }  

Basic Clientaccesspolicy Handler Part 2 - HttpHandler adding some code

  1. Change the getter for the IsResusable property the exception to simply "return true;" (This allows the Handler to be pooled.)
  2. Delete the "throw new NotImplementedException();" inside the ProcessRequest method.  We are going to replace this with code.  We are going to use LINQ in order to build the clientaccesspolicy.xml file.  We can just as easily use StringBuilder, XmlDocuments or other forms.  (This is NOT meant for production.  This is just illustrating a concept.)
  3. Add a reference to the System.Core assembly. (This houses the LINQ methods.)
  4. Add the following using statement: "using System.Xml.Linq;" .
  5. Copy and paste the code below and insert it into the ProcessRequest method.  The code below uses the Parse method from the XDocument class to load a string and transform it into an XDocument object.

            XDocument clientaccessPolicyDoc = XDocument.Parse(
            @"<?xml version=""1.0"" encoding=""utf-8""?>
            <access-policy>
              <cross-domain-access>
                <policy>
                  <allow-from http-request-headers=""*"">
                    <domain uri=""*""/>
                  </allow-from>
                  <grant-to>
                    <resource path=""/"" include-subpaths=""true""/>
                  </grant-to>
                </policy>
              </cross-domain-access>
            </access-policy>");

            context.Response.Write(clientaccessPolicyDoc.ToString());

Your class file should now look like the following:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Xml.Linq;

namespace SilverlightCrossDomainHandler
{
    public class BasicClientaccesspolicyHandler : IHttpHandler
    {
        #region IHttpHandler Members

        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            XDocument clientaccessPolicyDoc = XDocument.Parse(
            @"<?xml version=""1.0"" encoding=""utf-8""?>
            <access-policy>
              <cross-domain-access>
                <policy>
                  <allow-from http-request-headers=""*"">
                    <domain uri=""*""/>
                  </allow-from>
                  <grant-to>
                    <resource path=""/"" include-subpaths=""true""/>
                  </grant-to>
                </policy>
              </cross-domain-access>
            </access-policy>");

            context.Response.Write(clientaccessPolicyDoc.ToString());
        }

        #endregion
    }
}

Deploying managed HttpHandlers on IIS 7.0

This will go over deploying the HttpHandler solution we created above into IIS 7.0.  I wanted to provide some basic instructions on deploying handlers as it can be tricky, making this article a complete resource.  However, this article is not about deployment so I will cover only IIS 7.0.  Why IIS 7.0 and not 6.0?  Simply because I think that most advanced developers should be taking advantage of IIS 7.0 features and some of the new WCF 4.0 bits will only work in IIS 7.0.  If you haven't converted to developing on either Vista or Windows 2008 now is a good time to do so.

This is one way we can deploy the HttpHandler on our server.  I like this solution as it is a global way to add the handlers to the entire web server and it is simpler to follow.  There are several different ways to do this.  Another good solution would be to deploy the handlers with a Silverlight web project.  This way the clientaccesspolicy.xml handler is only enabled when a Silverlight application is deployed.

  1. Build the SilverlightCrossDomainHandler solution in release mode
  2. Sign the assembly so that we can deploy it to the GAC
  3. Install the assembly into the GAC by copying the assembly to the c:\windows\assembly\ folder
  4. Edit the web server web.config and add our assembly type
    1. Navigate to the C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\ folder (v2 because that is the last version that has hooks into the core ASP.NET assemblies....NET 3.0 and 3.5 simply build on top of this)
    2. Open the web.config file with Visual Studio
    3. In the compliation element there is an assemblies element with several assemblies listed.  We will add our custom assembly here.
    4. Add this element: <add assembly="SilverlightCrossDomainHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4d1c49f632a38a3c"/>
      1. Note: The PublicKeyToken could be different if you are doing this project on your own.  Simply copy it and replace it with whatever your assembly has been signed with.  You can check what your public key token is by right-clicking the assembly once it is in the GAC
    5. Save the web.config file
  5. Add the HttpHandler to the global web server
    1. Open up IIS Manager
    2. Double click on "Handler Mappings"
    3. There will be several listed that are pre-installed when ASP.NET and IIS are set up by default.  In order to add your own right-click and select "Add Managed Handler..." (this can take a few seconds)
    4. A dialog box will appear
      1. In the Request Path enter: clientaccesspolicy.xml (this will mean that ANY request to the clientaccesspolicy.xml file will be handled by our handler we choose)
      2. Select the SilverlightCrossDomainHandler and whatever type you want (i.e. BasicClientaccesspolicyHandler) from the dropdown menu (if it is not located there, you probably messed up editing the web.config file)
      3. Name the handler what you like (i.e. Clientaccesspolicyhandler)
      4. Perform a restart on the web server or an iisreset or restart the application pool

 

Testing managed HttpHandlers (inside the browser)

To test our deployment simply point your browser to http://localhost/clientaccesspolicy.xml.  Of course, you want to make sure that you actually do not have a clientaccesspolicy.xml file on the root of IIS. If you put the URL into the browser and click OK, you will simply get a blank page (as this is not an HTML/ASPX/RSS etc request that has a visual reponse).  You can either use Fiddler or Web Development Helper.  To test using the Web Development Helper (for those that use Fiddler, you know how to do this already):

  1. Install the tool, if you haven't done so already.  The tool is an add-in for Internet Explorer after you install it you have to close all your IE sessions.
  2. Go to Tools -> Web Development Helper
  3. A window shoul appear on the bottom
  4. Check Enable Logging (this will let you monitor any requests made from the browser)
  5. Navigate to the page hosting your handler (i.e. http://localhost/clientaccesspolicy.xml)
  6. You will see a row entry for the response from the server
  7. Double-click on the row and a dialog pops up with detailed information about the request
  8. Click the Response Content Tab and notice that we have a well formed clientaccesspolicy.xml file

Note on the screen shot that Enable Logging is checked.  We received a response from the request and the Response Contect is well formed for the clientaccesspolicy.xml and it is ready to serve us:

The fun doesn't stop here :)  Since we deployed the handler to handle ANY request anywhere for clientaccesspolicy.xml (which you may or may not want to do).  All requests for subdomains work fine as well and are handled by the very same handler we installed.  In my test case I created a sub domain and profiled and it works fine:

TroubleShooting

If you do not have the proper IIS ASP.NET and Extensibility add-ons (ISAPI) turned on, you might receive this error: (Simply go back to Add/Remove programs and add the ASP.NET and Extensibility features for IIS).  Furthermore, ensure that ASP.NET is properly registered on your site.

 

Summary

This article introduced you to some of the basics in managing a clientaccesspolicy.xml file for the Enterprise.  We looked at other cross domain files how they are published in Enterprise scenarios and how some scenarios could warrant a more dyanmic configuration file.  One way to solve the complexity of dynamic cross-domain configurations is to use HttpHandlers to create the configuration for us.  In part 1 of the series we created a simple HttpHandler that returned a well formed file.  In part 2 of the series, we will create a dynamic clientacesspolicy.xml file from a database store that will properly create the file in a more complex scenario.

SilverlightCrossDomainHandler.zip (18.51 kb)

 

kick it on DotNetKicks.com
Posted: Nov 08 2008, 15:32 by Bart Czernicki | Comments (1) RSS comment feed |
  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Filed under: Enterprise | Silverlight | WCF
Tags:
Social Bookmarks: E-mail | Kick it! | DZone it! | del.icio.us
blog comments powered by Disqus