I spent about 2 days to find out why my code is not working and finally came to the conclusion it is jersey oauth1 client which does not fully support RSA-SHA1 signature method as I was able to get it working after some thorough investigation by ugly hacks involving reflection.
Of course it could also be that I used it wrongly, then please point out my error and make it easier usable and better documented.
What I'm trying to do:
I write a command-line tool that needs to query information from a JIRA 6 instance via its REST API. As our JIRA is completely closed, some sort of authentication is needed and JIRA suggests OAuth as the preferred method of authenticating.
What I did do:
I configured the Consumer in JIRA with the JIRA Application Links feature, for this I created a public / private key pair as JIRA only supports RSA-SHA1 as signature method and requires the public key.
(Commands to generate such a key pair would be handy in the Jersey documentation. The ones I used were:
- "openssl genrsa -out key.pem 2048" to create the private key
- "openssl pkcs8 -topk8 -in key.pem -nocrypt" to convert the private key into the format that is needed by jersey [needed me quite some time to find this out]
- "openssl rsa -in key.pem -pubout" to extract the public key from the private key
The output of the third command can be pasted into the service provider, the output of the second command can be used as consumerSecret directly)
I then googled a lot to find a good example or tutorial on how to get this going until I found your oauth-client-twitter which helped me a lot as it does most of what I needed, I just needed to adapt this a bit and change the signature method to "RSA-SHA1".
At least so I thought.
Basically I did something like
And thought this should work. Unfortunately I got only the message that there is a 400 error without any more information. No HTTP Headers, no body, nothing and I was not able to analyze it with WireShark as our JIRA only supports HTTPS.
After some digging and debugging I found out the problem is that the org.glassfish.jersey.client.oauth1.OAuth1AuthorizationFlowImpl.Builder#build call creates a new OAuth1AuthorizationFlowImpl instance which creates a new OAuth1Parameters instance that it uses and ignores completely the parameters set on the OAuth1BuilderImpl where the signatureMethod was set. I guess other settings like realm, timestamp, nonce and version are also ignored. And I found no legal method to get this signatureMethod set, so it uses the default HMAC-SHA1 which causes JIRA to give back error 400 (with additional information that HMAC is not supported but this was not retrievable anywhere).
So to work-around this, I added the following three hacky lines that set the signatureMethod on the field, retrieved via reflection.
So now at least the authorization flow was able to proceed. (Except that I don't get any verifier from JIRA but just have to continue with null as verifier after I allowed access in the browser, could be noted somewhere maybe that this is not necessarily required)
Then I wanted to do
which also failed with error 400.
I then changed this to do instead (first line changed)
which works and I needed anyway for if the access token comes from the stored properties file, but I first tried to do it like shown in the oauth-client-twitter example. Now I only decide on how to create the AccessToken and then always use that line and it works finally.