"ClickOnce does not support ASP.NET forms-based authentication because it uses persistent cookies; these present a security risk because they reside in the Internet Explorer cache and can be hacked. Therefore, if you are deploying ClickOnce applications, any authentication scenario besides Windows authentication is unsupported."
- from Securing ClickOnce Applications by Microsoft
Even though Microsoft says that ClickOnce doesn't support ASP.NET Forms Authentication, there is a workaround.
Understanding How a ClickOnce Application is Downloaded
When access the ClickOnce deployment manifest (.application) file from IE, files are downloaded in following sequence:
- IE downloads the .application file.
- ClickOnce engine takes over the control and downloads the .application file again from the same URL.
- ClickOnce engine downloads the .application file from the update location (deploymentProvider codebase in the .application file).
- ClickOnce engine downloads the application manifest (.manifest) file specified in the .application file.
- ClickOnce engine downloads the files specified in the .manifest file using relative path based on the URL of the.manifest file.
As the ClickOnce engine doesn't support cookies, without a workaround step 2 will fail.
The Solution
You can find a workaround in this article: "Make ClickOnce Work With ASP.NET Forms Authentication". The trick is the Cookieless Forms Authentication introduced since ASP.NET 2.0. Please be aware that demo code from that article is for WPF Brower Application (.xbap), which don't have a "update location" in the .xbap file, therefore no step 3. For WinForm s/WPF applications, the workaround will fail in step 3 as IIS cannot find the Forms Authentication ticket from the URL. So in step 2, there is a need to embed the ticket into the deploymentProvider codebase, as same as the .manifest file URL, using the DeploymentUrl. As cookie is not supported, in step2, ticket(FormsIdentity) should be retrieved from context.User.Identity. Ticket can be embedded as either path or query string.
The configuration in the demo code is for IIS7.0 Classic mode as specified by the preCondition. For IIS7.0 Integrated mode, the configuration is:
<handlers> <add name="Clickonce manifest file" path="*.application" verb="*" type="ClickOnceHandler.ClickOnceApplicationHandler,ClickOnceHandler" resourceType="Unspecified" preCondition="" /> <add name="Clickonce files" path="*.deploy" verb="*" type="System.Web.StaticFileHandler" resourceType="Unspecified" preCondition="" /> </handlers>
Please see this article for more information about the configuration: ASP.NET Integration with IIS 7.
Upgrade Consideration
When a checks for update, the ClickOnce engine will access the .application file and the .manifest file.
If these files are protected, you will need to get a Forms Authentication ticket and embed it in the URL to access them, otherwise, you need to detect the update by your own code.
It should be acceptable to leave these two types of files unprotected (as configured above). Even though, you still need a ticket to upgrade the application.
The Pitfalls
While Forms Authentication ticket is encrypted then embedded into the URL, the length of the URL path is quite easy to exceed 260 characters. This may cause HTTP 400 Bad Request error.This could be the limitation of ASP.NET 2.0 and/or IIS. It recommends to upgrade to ASP.NET 4.0, and increase the UrlSegmentMaxLength registry value if there is a need - see more details: Http.sys registry settings for IIS.
The configuration in web.config must be consistent with the Application Pool setting (Integrated/Classic), otherwise the configuration will not take effects.