Dynamically controlling cross-domain permissions

What are crossdomain.xml files?

As developer who has ever dipped their toes into the murky pond that is cross-domain configuration with Flash will tell you, it is quite a confusing and somewhat aggravating task to accomplish. In this post, I’m going to demonstrate how you can control access to your APIs from Flash applications by dynamically generating crossdomain.xml files that work the same as static crossdomain.xml files.

But before we go any further, what the hell is a crossdomain.xml file?

The definition of a cross-domain configuration file is (taken from http://www.senocular.com/pub/adobe/crossdomain/policyfiles.html):

A cross-domain policy file is a XML document that grants a web client, such as Adobe Flash Player, permission to handle data across multiple domains. When a client hosts a content from a particular source domain and that content makes requests directed towards a domain other than its own, the remote domain would need to host a cross-domain policy file that would grant access to the source domain allowing the client to continue with the transaction. Policy files grant read access to data as well as permit a client to include custom headers in cross-domain requests.

Essentially what this means is that if you have a Flash application and you need to pull data (other than images or video) from a domain which is not the domain of your hosted application, you will need to place a crossdomain.xml file on the server you are requesting data from.

The configuration file needs to be placed in the webroot of the server; you can have a look at some of the more popular sites’ crossdomain.xml files:

This post is not a “how-to” on crossdomain.xml files unfortunately: for that, you can visit http://www.adobe.com/devnet/flashplayer/articles/cross_domain_policy.html – a great article by Lucas Adamski.

The Problem

You would like to control access to your application’s API based on a database table, for instance:

You have an application that serves up a list of products like Amazon.com to be made available via AMF requests (could be a REST-based architecture, SOAP, etc). You have a service offering whereby Flash/Flex application developers can register with your company to be allowed to access this wonderful API. You charge a set price per year for your service and you keep a database of authorized subscribers. At this stage, you can either allow any domain to access your API by using the following crossdomain.xml file:

1
2
3
4
5
6
<!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="*"/>
</cross-domain-policy>

The problem with this configuration is that any domain can send requests to your API from their Flash applications, and for obvious reasons this is not such a great idea.

The other (more secure) option would be to manually stick in each subscriber’s domain name into the crossdomain.xml file as follows:

1
2
3
4
5
6
7
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="example1.com"/>
   <allow-access-from domain="example2.com"/>
   <allow-access-from domain="example3.com"/>
</cross-domain-policy>

With the above configuration, you will start running into major headaches your subscribers either start cancelling their accounts or fail to pay in full. You will manually have to go and remove their domains from the configuration each time.

The Solution

When Flash applies a security policy like this, it automatically looks for a crossdomain.xml file on the requested server in the webroot. We can use a nifty combination of Apache rewriting and a PHP script to dynamically generate a list of authorized domains.

Apache Configuration

We want Apache to listen for an incoming request for our crossdomain.xml file, but instead of serving the XML file, we want to process a PHP script called generate-config.php to generate our configuration options. This example is quite simplistic, and I encourage you to take this further with whatever rules your application may require.

We are going to create a .htaccess file in the webroot of our server with the following contents:

RewriteEngine On
RewriteCond %{REQUEST_URI} crossdomain.xml
RewriteRule ^crossdomain\.xml$ generate-config.php [L]
RewriteEngine On
RewriteCond %{REQUEST_URI} crossdomain.xml
RewriteRule ^crossdomain\.xml$ generate-config.php [L]

This will present the output of our generate-config.php file as the contents of the crossdomain.xml file – essentially using another file’s content in place of another.

PHP & MySQL

In our generate-config.php file, we are going to:

  1. Connect to a database
  2. Run a SQL query that will return a list of subscribers
  3. Iterate through our list and add them to our XML output
  4. Echo the XML output back to Apache

First, create a database called crossdomain_test and then run the following SQL query to create our subscribers table:

CREATE TABLE IF NOT EXISTS `subscribers` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `domain` varchar(255) NOT NULL,
  `active` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Insert a couple of test rows:

INSERT INTO `subscribers` (`ID`, `name`, `domain`, `active`) VALUES
(1, 'YouTube', 'youtube.com', 1),
(2, 'Twitter', 'twitter.com', 1);

Now we’re going to create our generate-config.php file in the webroot:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
	// create our config skeleton according to the crossdomain.xml rules
	$xml = '<?xml version="1.0"?>
<!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"/>
</cross-domain-policy>';
 
	// create $config variable to hold our config data				
	$config = new SimpleXMLElement($xml);
 
	// connect to MySQL and select database
	$conn = mysql_connect("localhost", "username", "password");
	mysql_select_db("crossdomain_test", $conn);
 
	// loop through all rows, and create xml nodes
	$res = mysql_query("SELECT domain FROM subscribers WHERE active = 1");
	while($subscriber = mysql_fetch_object($res))
	{
		$child = $config->addChild("allow-access-from", null);
		$child->addAttribute("domain", $subscriber->domain);
	}
 
	// echo back to Apache
	echo $config->asXML();
?>

If we navigate to the crossdomain.xml file in the browser, we should see:

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!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="youtube.com"/>
	<allow-access-from domain="twitter.com"/>
</cross-domain-policy>

and if we delete one of the records out of the table (try deleting YouTube), and navigate to that page again, you’ll see:

1
2
3
4
5
6
<?xml version="1.0"?>
<!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="twitter.com"/>
</cross-domain-policy>

And that’s it! Not too difficult at all :)

A Workaround for all frustrated developers consuming REST services

As a side-note, if you ever encounter a site that you need to pull data from and they do not have a crossdomain.xml file, all you have to do is write a simple “proxy” file with PHP (or whichever language you choose) that will accept one parameter (the URL to be called) and send the results back:

1
2
3
4
5
<?php
 
	$url = $_GET["url"];
	echo file_get_contents($url);
?>

Make sure that this proxy file is sitting in your domain though, or a domain with a crossdomain.xml file present.Vote in HexoSearch

Balsamiq Mockups – An essential tool for developers and designers

At the risk of sounding like a shameless peddler of commercial software, I would seriously recommend Balsamiq Mockups. Now, let my intentions be clear… I made an agreement with Valerie from Balsamiq that I would write a review of this software on my blog in exchange for a testing license. Look, what can I say… I was born Jewish.

Now, just because I received a free license to review the software it does not mean that will not point out the egregious problems that I find with the software, nor will I ramble on about how fantastic it is. All I will say is this: If you deal with clients often that have not got any creative done for a prospective project and are looking for Interface Design advice, this is the tool for you!

Onto the review…

Overview

Balsamiq Mockups is an AIR application built to help you mock up application interface designs in the timeframe of a (non-metric) “jiffy”. Since i’ve started using the application, i’ve put together numerous mockups for clients and always received good feedback. What Balsamiq lacks in extensibility it makes up for in sheer speed of use.
The application is well thought out and concise. No instruction manual or cerebral documentation necessary! As far as AIR applications go, this is one of the more advanced ones I’ve seen, and it certainly is a pleasure to work with. I wouldn’t go so far as to say it justifies a $79 price-tag, but it is well worth the loot.

Tooling and Extensibility

As far as tools go, the Balsamiq developers certainly went out of their way. Included in the application are over 75 user-interface components from Buttons to Charts to iPhones, as well as loads of icons that will provide the finishing touches on any rough cut. The components are all customizable, scalable and z-axis-orderable, and the keyboard shortcuts help you get the job done quite quickly once you’re comfortable with the application.

The application fails abysmally when it comes to extensibility; I would imagine that with an application like this, the developers should facilitate the downloading of custom component/icon packs, or even user-submitted ones. This could as quite an interesting angle to the application i feel. Another thing I wish it included was some sort of color palette to slightly adjust the components. I’m assuming that it wouldn’t be too much trouble to include a little color-transform slider to add a bit more dimension to the components for added visual cues.

Good thing i downloaded the latest version (1.6.67 released on 24th Feb 2010) before i started ranting about the absence of the spacebar-invoked panning functionality… Good job guys! Works great :)

Search, Export and Memory Usage

The search functionality of Balsamiq is intuitive and responsive; scanning through different UI elements is a breeze and makes the whole experience that much more impressive. Balsamiq offers exporting your mockups to both PNG (why not JPG?) and PDF (go Thibault!) and it usually exports the mockups without problems. I’ve noticed that when my mockups become quite intense, the application does begin to lag a little though, but i’m confident that the developers are looking into that for future releases.

Conclusion

All in all, this is an indispensable tool for the discerning web developer & designer. If you need to give your clients an idea of what you’re going to produce and you have limited time, give this application a shot. Thanks to the Balsamiq team for the great addition to my development ammunition!Vote in HexoSearch

Accessing services-config.xml values from Flex at runtime

Recently I found this magic class in the Flex 3 SDK called ServerConfig. This class is great… What it allows you to do is access values that you defined in your services-config.xml file used to define the communication channels between Flex and your server.

Take the following services-config.xml file for example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
	<services>
		<service id="amfphp-flashremoting-service" class="flex.messaging.services.RemotingService"
				messageTypes="flex.messaging.messages.RemotingMessage">
			<destination id="amfphp">
				<channels>
					<channel ref="my-amfphp"/>
				</channels>
				<properties>
					<source>*</source>
				</properties>
			</destination>
		</service>
	</services>
	<channels>
		<channel-definition id="my-amfphp" class="mx.messaging.channels.AMFChannel">
			<endpoint uri="gateway.php" class="flex.messaging.endpoints.AMFEndpoint"/>
		</channel-definition>
	</channels>
</services-config>

As you can see, we’re setting the endpoint for our my-amfphp channel to gateway.php. What if you wanted to read that value into your Flex application? You could use the following code:

trace(ServerConfig.getChannel("my-amfphp").endpoint);

Check out the ServerConfig for more information!Vote in HexoSearch

AMFPHP is back!

Today is a wonderful day!

I have teamed up with Ariel Sommeria-klein to revive the legendary AMFPHP project that spawned a whole new dimension of Rich Internet Applications. Together we have brought AMFPHP 1.9 out of beta and made it compatible with PHP 5.3. We have also completely rewritten the AMFPHP service browser and we have several improvements planned for AMFPHP 2.0.

If you would like to help contribute to this great open-source application, please contact us.Vote in HexoSearch

Truly Cached Flex Modules

I was working on a project recently and I discovered (or possibly misunderstood – see disclaimer) that Flex does not cache modules correctly, or – at the very least – it does not do it effectively according to my tests.

My test was conducted using Flex SDK 3.4.0.9271, Firefox 3.5.7 and Flex Builder Professional 3.0.214193

According to this page (under the Preloading modules heading), Adobe asserts the following:

When a module is loaded by the Flex application for the first time, the module’s SWF file is transferred across the network and stored in the browser’s cache. If the Flex application unloads that module, but then later reloads it, there should be less wait time because Flash Player loads the module from the cache rather than across the network.

Module SWF files, like all SWF files, reside in the browser’s cache unless and until a user clears them. As a result, modules can be loaded by the main application across several sessions, reducing load time; but this depends on how frequently the browser’s cache is flushed.

I found the above claims to be demonstrably false, or at least just plain inefficient…

Let me qualify this:
According to my tests (conducted with my Firefox browser cache turned both on and off), i found that the application’s memory usage keeps growing exponentially when switching between two loaded modules. There was a variance (as you’d imagine) when the browser cache was left on but nonetheless, the memory usage keeps growing steadily.

In the code sample below, I have extended the functionality of the mx.modules.ModuleLoader class, and added a Dictionary (with a little logic) to manage the (ostensibly) effective caching of previously loaded modules. I have not tested this class extensively, but all the tests that I conducted seemed to produce a significant memory and speed improvement.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
 
	import mx.events.FlexEvent;
	import mx.events.ModuleEvent;
	import mx.modules.IModuleInfo;
	import mx.modules.ModuleLoader;
	import mx.modules.ModuleManager;
 
	/**
	 * This class manages the loading, unloading and caching of Flex Modules
	 * This is a modified version of the mx.modules.ModuleLoader class
	 *
	 * @author Danny Kopping - danny@ria-coder.com
	 */
	public class CachedModuleLoader extends ModuleLoader
	{
		private var map:Dictionary = new Dictionary();
 
		private var _url:String = null;
		private var module:IModuleInfo;
		private var loadRequested:Boolean = false;
 
		public function CachedModuleLoader()
		{
			super();
		}
 
		override public function set url(value:String):void
		{
			if (value == _url)
				return;
 
			if (module)
			{
				module.removeEventListener(ModuleEvent.PROGRESS, moduleProgressHandler);
				module.removeEventListener(ModuleEvent.SETUP, moduleSetupHandler);
				module.removeEventListener(ModuleEvent.READY, moduleReadyHandler);
				module.removeEventListener(ModuleEvent.ERROR, moduleErrorHandler);
				module.removeEventListener(ModuleEvent.UNLOAD, moduleUnloadHandler);
 
				//module.release();
				module = null;
 
				if (child)
				{
					removeChild(child);
					//child = null;
				}
			}
 
			_url = value;
 
			dispatchEvent(new FlexEvent(FlexEvent.URL_CHANGED));
			removeAllChildren();
 
			if (_url != null && loadRequested)
			{
				if(!map[_url])
					loadModule();
				else
				{
 
					child = map[_url];
					addChild(child);
				}
			}
		}
 
		override public function get url():String
		{
			return _url;
		}
 
		override public function createComponentsFromDescriptors(recurse:Boolean = true):void
		{
			super.createComponentsFromDescriptors(recurse);
 
			loadRequested = true;
			loadModule();
		}
 
		override public function loadModule(url:String = null, bytes:ByteArray = null):void
		{
			if (url != null)
				_url = url;
 
			if (_url == null)
			{
				//trace("loadModule() - null url");
				return;
			}
 
			if (map[_url])
			{
				//trace("loadModule() - already created the child");
				return;
			}
 
			if (module)
			{
				//trace("loadModule() - load already initiated");
				return;
			}
 
			dispatchEvent(new FlexEvent(FlexEvent.LOADING));
 
			module = ModuleManager.getModule(_url);
 
			module.addEventListener(ModuleEvent.PROGRESS, moduleProgressHandler);
			module.addEventListener(ModuleEvent.SETUP, moduleSetupHandler);
			module.addEventListener(ModuleEvent.READY, moduleReadyHandler);
			module.addEventListener(ModuleEvent.ERROR, moduleErrorHandler);
			module.addEventListener(ModuleEvent.UNLOAD, moduleUnloadHandler);
 
			module.load(applicationDomain, null, bytes);
		}
 
		override public function unloadModule():void
		{
			if (child && contains(child))
			{
				removeChild(child);
				child = null;
			}
 
			if (module)
			{
				module.removeEventListener(ModuleEvent.PROGRESS, moduleProgressHandler);
				module.removeEventListener(ModuleEvent.SETUP, moduleSetupHandler);
				module.removeEventListener(ModuleEvent.READY, moduleReadyHandler);
				module.removeEventListener(ModuleEvent.ERROR, moduleErrorHandler);
 
				module.unload();
				module.removeEventListener(ModuleEvent.UNLOAD, moduleUnloadHandler);
				module = null;
			}
 
			if(map[_url])
			{
				delete map[_url];
			}
		}
 
		private function moduleProgressHandler(event:ModuleEvent):void
		{
			dispatchEvent(event);
		}
 
		private function moduleSetupHandler(event:ModuleEvent):void
		{
			// Not ready for creation yet, but can call factory.info().
 
			dispatchEvent(event);
		}
 
		private function moduleReadyHandler(event:ModuleEvent):void
		{
			child = module.factory.create() as DisplayObject;
			dispatchEvent(event);
 
			if (child)
			{
				var p:DisplayObjectContainer = parent;
				// p.removeChild(this);
				addChild(child);
 
				map[url] = child;//ModuleManager.getModule(_url);
				//trace(map + ":" + url + ":" + map[url]);
			}
		}
 
		private function moduleErrorHandler(event:ModuleEvent):void
		{
			unloadModule();
			dispatchEvent(event);
		}
 
		private function moduleUnloadHandler(event:ModuleEvent):void
		{
			dispatchEvent(event);
		}
	}
}

The usage of this class is exactly the same as the regular mx.modules.ModuleLoader class. I hope this helps!

Download this file: Download

**DISCLAIMER**
I know a bit about Flex modules from hours of obsessing over them, but i do not know everything. From my tests of the efficacy of the above code & explanation, i found that it reduces memory usage and increases the general usability of my Flex project; i could be very wrong on this topic, and if i am – please tell me. Maybe i’m just an idiot, but it seems to work…
Vote in HexoSearch

VirtualBox Guest Additions woes

Sigh… I wish that computers would just work all the time!

Today i booted my machine, launched my snazzy Linux virtual machine, proceeded to start my XAMPP stack and mount my shared folder so that my Linux VM can communicate with my host OS (sigh) Windows… This works 99.9% of the time, but to my horror:

/sbin/mount.vboxsf: mounting failed with the error: No such device

FUCK! What now? So i google and google, but nothing works…

I’m now bashing my head in frustration against my desk, spilling my coffee and rubbing my blood-red forehead, but that didn’t help either… I try mount VBoxGuestAdditions via VirtualBox, nothing. Nothing, nothing, nothing! NOTHING!

By now i’m getting so irritated that i’m drinking coffee after coffee and smoking vociferously… and then…. -cue lightbulb- if you can’t take the horse to the water (mount VBoxGuestAdditions in Linux), pick the fucker up and dump him in there (download the fucking thing from Linux and run it from Linux). So, i dig around looking for the URL, eventually find it, mount the ISO file (help instructions on mounting an ISO file in Linux here), run the installation script, reboot and IT WORKS!! …and the children lived happily ever after.Vote in HexoSearch

Flash Runtime implemented in JavaScript

Now this completely threw me… I can’t believe how one guy can be so skilled!

Flash Runtime in JavaScript

This is completely ridiculous… Tobias Schneider has written a JavaScript-based Flash runtime! Well, this gives Internet Explorer another thing to completely fuck up! Very impressed indeed…Vote in HexoSearch

Using a Custom Cursor in Flex with CSS

If you want to use a custom busyCursor animation in your Flex applications, you don’t need to do anything fancy… All you have to do is define one, solitary property in your CSS file:

CursorManager
{
	/* You can use PNGs, SWFs or JPEGs */
	busyCursor: Embed(source="path/to/your/resource");
}

To invoke the busy cursor, use the following line:

CursorManager.setBusyCursor();

…or you could set the showBusyCursor to true in your HTTPService or RemoteObject instances.Vote in HexoSearch

Converting GIF to SWF using Flash CS4

A typical ballache… You want to use one of the cool loaders from http://ajaxload.info/ in your Flash/Flex apps, but it only generates a GIF file… So you’ll scour the net for a GIF2SWF application and you’ll undoubtedly come across a few, but you don’t have to look any further than Flash CS4 – surprisingly!

All you have to do is open a GIF file in Flash CS4 and it’ll automatically pull it apart and convert it to frames, which can then be converted to a SWF file :)

Hope it helps you at some point!Vote in HexoSearch

AMFPHP Genie v0.2

AMFPHP Genie (0.2) is a simple tool to help you get shit done using Flex and AMFPHP.

Check out http://dannykopping.co.za/amfphp-genie/ for more information!Vote in HexoSearch