During my latest stint as the JIRA Developer on Support, I came across an issue where a customer reported that the Remember Me functionality of JIRA wasn’t working – but only for some users. In his instance, he had two users: wmlalai and lagonil – for now, let’s call them B1 and B2. For B1, the Remember Me functionality worked as expected; for B2, not so.
Curious to the cause of this problem, I loaded up the customer’s data in a local instance, and sure enough I was able to reproduce it. Monitoring the cookies within the browser to make sure they were being saved correctly, I noticed that upon the first login, the cookie was present in the browser for both users. When I closed the browser and restarted it, the cookie again was still there. But, when I navigated to JIRA, B2’s cookie was being deleted. This was accompanied by an exception in JIRA’s logs:
2008-03-07 15:46:32,470 http-8090-Processor2 DEBUG [atlassian.seraph.cookie.EncryptedCookieEncoder] Invalid password cookie submitted, trying insecure java.lang.RuntimeException: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher at com.atlassian.seraph.util.EncryptionUtils.decrypt(EncryptionUtils.java:77) at com.atlassian.seraph.cookie.EncryptedCookieEncoder.decodePasswordCookie(EncryptedCookieEncoder.java:43) at com.atlassian.seraph.auth.DefaultAuthenticator.decodeCookie(DefaultAuthenticator.java:393) at com.atlassian.seraph.auth.DefaultAuthenticator.getUserFromCookie(DefaultAuthenticator.java:245) at com.atlassian.seraph.auth.DefaultAuthenticator.getUser(DefaultAuthenticator.java:221)
Why would the cookie be the wrong length? I set a breakpoint in the DefaultAuthenticator.getUserFromCookie() method in Seraph, where the cookie is retrieved and decoded. When attempting to log in with B2, I observed the following value for the seraph.os.cookie:
as compared to the actual value stored in the cookie in the browser:
i.e., when retrieving the cookie value from the request, it was being truncated at the ‘>’ character.
Who stole (part of) the cookie from the cookie jar? I sniffed the network traffic to ensure the browser was sending the full value, and it was, so this led me to believe that the application server was the fiend. After a bit of searching, I found that others had been the victim of Tomcat’s cruel appetite. What confused me more was Apache’s response:
That is because those characters are illegal in version 0 cookies (as per the spec). You need to use version 1 cookies.
I had read the specs they were referring to: “Version 0” and “Version 1”, and neither made mention of illegal characters in cookie values other than semi-colon, comma and whitespace. Regardless, I tried their suggested solution of switching to “Version 1” cookies (by using the setVersion() method on the Cookie object when constructing it), and it did work. Note however that, when I tested the issue on Orion and Resin, they did not experience this problem, even though the cookies did have the “illegal” characters in them, AND the Cookie objects were “Version 0”. Go figure.
Why do we use these characters in our cookies anyway? Interestingly, this problem only appeared after the release of JIRA 3.12, when updates were made to Seraph code to increase the security of the seraph.os.cookie, by taking the hash of the username and password and encrypting it a little. And sometimes, this hash happens to contain those characters. What’s cool is that it seems to be reproducible, so if you fire up your own instance of JIRA running on Tomcat, and create a user named lagonil, you should get the same problem. We’re hoping to resolve this issue very soon; you can track it here.
So let that be a lesson to you, kids – if you’re ever going to use hash cookies, make sure you know what’s in them!