I maintain an ASP.NET MVC website that uses
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
to sign users in (they end up with a cookie named .ASPXAUTH
).
The client wants me to add an HTML to PDF feature, so I'm wrapping the wkhtmltopdf library and calling that. This ends up being a command that looks like this:
wkhtmltopdf http://example.com/Foo/Edit/42 Foo.pdf
However, that results in making a PDF of the login screen, as the wkhtmltopdf user agent is redirected since it doesn't have the correct cookie.
That's fine since, according to the wkhtmltopdf documentation, there's an argument like this:
--cookie <name> <value> Set an additional cookie (repeatable)
So I modify the command to be:
wkhtmltopdf --cookie .ASPXAUTH 91C0DE4C... http://example.com/Foo/Edit/42 Foo.pdf
Where the cookie value is retrieved using Request.Cookie[".ASPXAUTH"].Value
.
Unfortunately, this doesn't seem to work and I have no idea why. I know that ASP.NET is receiving the cookie because when I breakpoint the login page after the redirect, I can see that it's been set. So why does ASP.NET not accept my copied cookie?
Here's the contents of a request that ASP.NET allows (from Chrome):
GET http://localhost:50189/ReportingMonth/Edit/1193391 HTTP/1.1
Host: localhost:50189
Connection: keep-alive
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-CA,en;q=0.8,en-US;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: .ASPXAUTH=C8189041BF69FEF89A834B6F5035B786EC40145FFFBA3DBB6A04973BC58021C73D8D374E3577AA44BC26A784BC8A0C24831CF49FBD596BFFBA42C613E3C2C0C893D1587B7743D051643088BB8BAB667C047E0D1B84D7B76C4AADA7C62AB460D87C954BF9118BF5945E7D325D455CFD13A34C3DD5E597AFDF75D3C8EE76D8488B08ABBF6AE065B4C57CE47CB65AB17D65; language=en; ui-tabs-[object Object]=0
And here's one that it redirects to the login (from wkhtmltopdf):
GET http://localhost:50189/ReportingMonth/Edit/1193391 HTTP/1.1
Cookie: .ASPXAUTH=C8189041BF69FEF89A834B6F5035B786EC40145FFFBA3DBB6A04973BC58021C73D8D374E3577AA44BC26A784BC8A0C24831CF49FBD596BFFBA42C613E3C2C0C893D1587B7743D051643088BB8BAB667C047E0D1B84D7B76C4AADA7C62AB460D87C954BF9118BF5945E7D325D455CFD13A34C3DD5E597AFDF75D3C8EE76D8488B08ABBF6AE065B4C57CE47CB65AB17D65
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.3 (KHTML, like Gecko) Qt/4.7.1 Safari/533.3
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Connection: Keep-Alive
Accept-Encoding: gzip
Accept-Language: en-US,*
Host: localhost:50189
I found the problem. I noticed that once I changed the User-Agent
field (in Fiddler) to be the same as Chrome, it worked fine. So I did a little web sleuthing and discovered this bug on the wkhtmltopdf project page.
From the bug:
This is an issue under ASP .NET 4.0 as it seems that .NET interprets the User-Agent string "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-AU) AppleWebKit/532.4 (KHTML, like Gecko) Qt/4.6.1 Safari/532.4" as not supporting cookies which I think is preventing the --cookie option from working under ASP.
So it looks like the solution is either figuring out a way to make wkhtmltopdf change it's User-Agent
header (not looking promising) or figure out a way to tell ASP.NET that that user agent does support cookies.
Thanks for you help Darin Dimitrov.
Update
Ok, I figured out how to tell ASP.NET that the Qt web browser used by wkhtmltopdf supports cookies. You need to create a file called qt.browser
and save it in a directory callde App_Browsers
in the root of your ASP.NET project. Here's what you put in the qt.browser
file:
<browsers>
<!-- Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Qt/4.7.1 Safari/530.1 -->
<browser id="Qt" parentID="Safari">
<identification>
<userAgent match="Qt/(?'version'(?'major'\d+)(\.(?'minor'\d+)?)\w*)" />
</identification>
<capabilities>
<capability name="browser" value="Qt" />
<capability name="version" value="${version}" />
<capability name="majorversion" value="${major}" />
<capability name="minorversion" value="${minor}" />
<capability name="type" value="Qt${major}" />
<capability name="ecmascriptversion" value="3.0" />
<capability name="javascript" value="true" />
<capability name="javascriptversion" value="1.7" />
<capability name="w3cdomversion" value="1.0" />
<capability name="tagwriter" value="System.Web.UI.HtmlTextWriter" />
<capability name="cookies" value="true" />
<capability name="frames" value="true" />
<capability name="javaapplets" value="true" />
<capability name="supportsAccesskeyAttribute" value="true" />
<capability name="supportsCallback" value="true" />
<capability name="supportsDivNoWrap" value="false" />
<capability name="supportsFileUpload" value="true" />
<capability name="supportsMaintainScrollPositionOnPostback" value="true" />
<capability name="supportsMultilineTextBoxDisplay" value="true" />
<capability name="supportsXmlHttp" value="true" />
<capability name="tables" value="true" />
</capabilities>
</browser>
</browsers>
Then re-compile your project (and maybe restart your server if you can) and then presto, you can emulate the ASP.NET authentication cookie!
Looks like a bug and there seems to be a fix in the trunk.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With