Sunday, April 03, 2011

ClickOnce Licensing HTTPHandler

Introduction
I've recently been working on a small application I intended to sell publicly and I was faced with the dilemma of how to deploy it for an individual user. My initial approach was with an MSI but this seemed a bit clumsy, especially around updating, and required me to learn quite a bit about installers that I didn't really care for. ClickOnce seemed like a much simpler alternative so I've recently re-released the application with a ClickOnce deployment. However, one downside to ClickOnce is that once you make it available on the Internet, it's available for anyone who can navigate to the address; there doesn't seem to be any concept of licensing. As I was selling the application, this seemed like a quite major shortcoming of ClickOnce, I wanted to make it at least a little bit challenging for someone to obtain my application without paying for it.

After quite a lot of research and a little bit of development, I've created this HTTP Handler that provides some level of licensing for ClickOnce applications and I thought I'd share it in the hope that it might save someone some time in deploying their application. I should point out that this code isn't intended to be compiled and deployed straight to your production environment as a solution to ClickOnce licensing. Security, particularly web based, is not my strong point and the code I provide is a base implementation only. I made some modifications for my own deployment of this HTTP Handler and you will probably need to as well. At the very least, you should review the code and understand its workings and limitations.

Background
I wanted to require a user to have a valid licence key to download the application and to perform updates, but I also wanted to allow a user to run the application even if they didn't have an Internet connection or the licensing server was down. Some research, particularly a helpful MSDN article on Administering ClickOnce Deployments, suggested the easiest way to do this was to provide a query string on the ClickOnce URL and a HTTP Handler to intercept the request and provide the validation.
The biggest issue with this is that a ClickOnce application has a pre signed manifest which details where the application is installed from and where updates can be retrieved from. The query string with the licence key will be different for every user but the manifest can't be easily updated because that would break the signing.

The 'solution', and I use that term in a loose sense as I'll soon explain, is to use the HTTP Handler to update and resign the manifest before returning it in the response.

Read more: Codeproject